From 82047f4504687081609e346efe653aa7ae5fd2d6 Mon Sep 17 00:00:00 2001 From: lishuang Date: Sun, 12 Jul 2020 17:26:15 +0800 Subject: [PATCH] Add the deleted feature. --- code/rest/matter_controller.go | 75 +++++++++++++++++++++++++++++++++- code/rest/matter_dao.go | 49 +++++++++++++++++++--- code/rest/matter_model.go | 1 + code/rest/matter_service.go | 59 +++++++++++++++++++++++++- 4 files changed, 176 insertions(+), 8 deletions(-) diff --git a/code/rest/matter_controller.go b/code/rest/matter_controller.go index 7e4c6be..0737973 100644 --- a/code/rest/matter_controller.go +++ b/code/rest/matter_controller.go @@ -73,6 +73,8 @@ func (this *MatterController) RegisterRoutes() map[string]func(writer http.Respo routeMap["/api/matter/create/directory"] = this.Wrap(this.CreateDirectory, USER_ROLE_USER) routeMap["/api/matter/upload"] = this.Wrap(this.Upload, USER_ROLE_USER) routeMap["/api/matter/crawl"] = this.Wrap(this.Crawl, USER_ROLE_USER) + routeMap["/api/matter/soft/delete"] = this.Wrap(this.SoftDelete, USER_ROLE_USER) + routeMap["/api/matter/soft/delete/batch"] = this.Wrap(this.SoftDeleteBatch, USER_ROLE_USER) routeMap["/api/matter/delete"] = this.Wrap(this.Delete, USER_ROLE_USER) routeMap["/api/matter/delete/batch"] = this.Wrap(this.DeleteBatch, USER_ROLE_USER) routeMap["/api/matter/rename"] = this.Wrap(this.Rename, USER_ROLE_USER) @@ -118,6 +120,7 @@ func (this *MatterController) Page(writer http.ResponseWriter, request *http.Req puuid := request.FormValue("puuid") name := request.FormValue("name") dir := request.FormValue("dir") + deleted := request.FormValue("deleted") orderDir := request.FormValue("orderDir") orderSize := request.FormValue("orderSize") orderName := request.FormValue("orderName") @@ -201,7 +204,7 @@ func (this *MatterController) Page(writer http.ResponseWriter, request *http.Req }, } - pager := this.matterDao.Page(page, pageSize, puuid, userUuid, name, dir, extensions, sortArray) + pager := this.matterDao.Page(page, pageSize, puuid, userUuid, name, dir, deleted, extensions, sortArray) return this.Success(pager) } @@ -280,6 +283,57 @@ func (this *MatterController) Crawl(writer http.ResponseWriter, request *http.Re return this.Success(matter) } +//soft delete. +func (this *MatterController) SoftDelete(writer http.ResponseWriter, request *http.Request) *result.WebResult { + + uuid := request.FormValue("uuid") + if uuid == "" { + panic(result.BadRequest("uuid cannot be null")) + } + + matter := this.matterDao.CheckByUuid(uuid) + + user := this.checkUser(request) + if matter.UserUuid != user.Uuid { + panic(result.UNAUTHORIZED) + } + + this.matterService.AtomicSoftDelete(request, matter, user) + + return this.Success("OK") +} + +func (this *MatterController) SoftDeleteBatch(writer http.ResponseWriter, request *http.Request) *result.WebResult { + + uuids := request.FormValue("uuids") + if uuids == "" { + panic(result.BadRequest("uuids cannot be null")) + } + + uuidArray := strings.Split(uuids, ",") + + for _, uuid := range uuidArray { + + matter := this.matterDao.FindByUuid(uuid) + + if matter == nil { + this.logger.Warn("%s not exist anymore", uuid) + continue + } + + user := this.checkUser(request) + if matter.UserUuid != user.Uuid { + panic(result.UNAUTHORIZED) + } + + this.matterService.AtomicSoftDelete(request, matter, user) + + } + + return this.Success("OK") +} + +//complete delete. func (this *MatterController) Delete(writer http.ResponseWriter, request *http.Request) *result.WebResult { uuid := request.FormValue("uuid") @@ -357,6 +411,10 @@ func (this *MatterController) ChangePrivacy(writer http.ResponseWriter, request matter := this.matterDao.CheckByUuid(uuid) + if matter.Deleted { + panic(result.BadRequest("matter has been deleted. Cannot change privacy.")) + } + if matter.Privacy == privacy { panic(result.BadRequest("not changed. Invalid operation.")) } @@ -395,6 +453,10 @@ func (this *MatterController) Move(writer http.ResponseWriter, request *http.Req panic(result.UNAUTHORIZED) } + if destMatter.Deleted { + panic(result.BadRequest("dest matter has been deleted. Cannot move.")) + } + var srcMatters []*Matter for _, uuid := range srcUuids { srcMatter := this.matterDao.CheckByUuid(uuid) @@ -403,6 +465,10 @@ func (this *MatterController) Move(writer http.ResponseWriter, request *http.Req panic(result.BadRequest("no move, invalid operation")) } + if srcMatter.Deleted { + panic(result.BadRequest("src matter has been deleted. Cannot move.")) + } + //check whether there are files with the same name. count := this.matterDao.CountByUserUuidAndPuuidAndDirAndName(user.Uuid, destMatter.Uuid, srcMatter.Dir, srcMatter.Name) @@ -461,6 +527,13 @@ func (this *MatterController) Zip(writer http.ResponseWriter, request *http.Requ if matters == nil || len(matters) == 0 { panic(result.BadRequest("matters cannot be nil.")) } + + for _, matter := range matters { + if matter.Deleted { + panic(result.BadRequest("matter has been deleted. Cannot download batch.")) + } + } + user := this.checkUser(request) puuid := matters[0].Puuid diff --git a/code/rest/matter_dao.go b/code/rest/matter_dao.go index a694d65..161433f 100644 --- a/code/rest/matter_dao.go +++ b/code/rest/matter_dao.go @@ -246,7 +246,7 @@ func (this *MatterDao) FindByUuids(uuids []string, sortArray []builder.OrderPair return matters } -func (this *MatterDao) PlainPage(page int, pageSize int, puuid string, userUuid string, name string, dir string, extensions []string, sortArray []builder.OrderPair) (int, []*Matter) { +func (this *MatterDao) PlainPage(page int, pageSize int, puuid string, userUuid string, name string, dir string, deleted string, extensions []string, sortArray []builder.OrderPair) (int, []*Matter) { var wp = &builder.WherePair{} @@ -268,6 +268,12 @@ func (this *MatterDao) PlainPage(page int, pageSize int, puuid string, userUuid wp = wp.And(&builder.WherePair{Query: "dir = ?", Args: []interface{}{0}}) } + if deleted == TRUE { + wp = wp.And(&builder.WherePair{Query: "deleted = ?", Args: []interface{}{1}}) + } else if deleted == FALSE { + wp = wp.And(&builder.WherePair{Query: "deleted = ?", Args: []interface{}{0}}) + } + var conditionDB *gorm.DB if extensions != nil && len(extensions) > 0 { var orWp = &builder.WherePair{} @@ -291,16 +297,16 @@ func (this *MatterDao) PlainPage(page int, pageSize int, puuid string, userUuid return count, matters } -func (this *MatterDao) Page(page int, pageSize int, puuid string, userUuid string, name string, dir string, extensions []string, sortArray []builder.OrderPair) *Pager { +func (this *MatterDao) Page(page int, pageSize int, puuid string, userUuid string, name string, dir string, deleted string, extensions []string, sortArray []builder.OrderPair) *Pager { - count, matters := this.PlainPage(page, pageSize, puuid, userUuid, name, dir, extensions, sortArray) + count, matters := this.PlainPage(page, pageSize, puuid, userUuid, name, dir, deleted, extensions, sortArray) pager := NewPager(page, pageSize, count, matters) return pager } //handle matter page by page. -func (this *MatterDao) PageHandle(puuid string, userUuid string, name string, dir string, fun func(matter *Matter)) { +func (this *MatterDao) PageHandle(puuid string, userUuid string, name string, dir string, deleted string, fun func(matter *Matter)) { //delete share and bridges. pageSize := 1000 @@ -310,13 +316,13 @@ func (this *MatterDao) PageHandle(puuid string, userUuid string, name string, di Value: DIRECTION_ASC, }, } - count, _ := this.PlainPage(0, pageSize, puuid, userUuid, name, dir, nil, sortArray) + count, _ := this.PlainPage(0, pageSize, puuid, userUuid, name, dir, deleted, nil, sortArray) if count > 0 { var totalPages = int(math.Ceil(float64(count) / float64(pageSize))) var page int for page = 0; page < totalPages; page++ { - _, matters := this.PlainPage(0, pageSize, puuid, userUuid, name, dir, nil, sortArray) + _, matters := this.PlainPage(0, pageSize, puuid, userUuid, name, dir, deleted, nil, sortArray) for _, matter := range matters { fun(matter) } @@ -411,6 +417,37 @@ func (this *MatterDao) Delete(matter *Matter) { } } +//soft delete a file from db and disk. +func (this *MatterDao) SoftDelete(matter *Matter) { + + // recursive if dir + if matter.Dir { + matters := this.FindByPuuidAndUserUuid(matter.Uuid, matter.UserUuid, nil) + + for _, f := range matters { + this.SoftDelete(f) + } + + //soft delete from db. + db := core.CONTEXT.GetDB().Model(&Matter{}).Where("uuid = ?", matter.Uuid).Update(map[string]interface{}{"deleted": 1}) + this.PanicError(db.Error) + + } else { + + //soft delete from db. + db := core.CONTEXT.GetDB().Model(&Matter{}).Where("uuid = ?", matter.Uuid).Update(map[string]interface{}{"deleted": 1}) + this.PanicError(db.Error) + + //no need to delete its image cache. + + //delete all the share. + this.bridgeDao.DeleteByMatterUuid(matter.Uuid) + + //no need to delete from disk. + + } +} + func (this *MatterDao) DeleteByUserUuid(userUuid string) { db := core.CONTEXT.GetDB().Where("user_uuid = ?", userUuid).Delete(Matter{}) diff --git a/code/rest/matter_model.go b/code/rest/matter_model.go index 4f1bd3b..da52442 100644 --- a/code/rest/matter_model.go +++ b/code/rest/matter_model.go @@ -45,6 +45,7 @@ type Matter struct { Children []*Matter `json:"-" gorm:"-"` Prop string `json:"prop" gorm:"type:varchar(1024) not null;default:'{}'"` VisitTime time.Time `json:"visitTime" gorm:"type:timestamp not null;default:'2018-01-01 00:00:00'"` + Deleted bool `json:"deleted" gorm:"type:tinyint(1) not null;default:0"` } // set File's table name to be `profiles` diff --git a/code/rest/matter_service.go b/code/rest/matter_service.go index dd1b729..0358110 100644 --- a/code/rest/matter_service.go +++ b/code/rest/matter_service.go @@ -255,6 +255,21 @@ func (this *MatterService) Delete(request *http.Request, matter *Matter, user *U this.ComputeRouteSize(matter.Puuid, user) } +//soft delete files. +func (this *MatterService) SoftDelete(request *http.Request, matter *Matter, user *User) { + + if matter == nil { + panic(result.BadRequest("matter cannot be nil")) + } + + if matter.Deleted { + panic(result.BadRequest("matter has been deleted")) + } + + this.matterDao.SoftDelete(matter) + //no need to recompute size. +} + //atomic delete files func (this *MatterService) AtomicDelete(request *http.Request, matter *Matter, user *User) { @@ -269,6 +284,24 @@ func (this *MatterService) AtomicDelete(request *http.Request, matter *Matter, u this.Delete(request, matter, user) } +//atomic soft delete files +func (this *MatterService) AtomicSoftDelete(request *http.Request, matter *Matter, user *User) { + + if matter == nil { + panic(result.BadRequest("matter cannot be nil")) + } + + if matter.Deleted { + panic(result.BadRequest("matter has been deleted")) + } + + //lock + this.userService.MatterLock(matter.UserUuid) + defer this.userService.MatterUnlock(matter.UserUuid) + + this.SoftDelete(request, matter, user) +} + //upload files. func (this *MatterService) Upload(request *http.Request, file io.Reader, user *User, dirMatter *Matter, filename string, privacy bool) *Matter { @@ -280,6 +313,10 @@ func (this *MatterService) Upload(request *http.Request, file io.Reader, user *U panic(result.BadRequest("dirMatter cannot be nil.")) } + if dirMatter.Deleted { + panic(result.BadRequest("Dir has been deleted. Cannot upload under it.")) + } + if len(filename) > MATTER_NAME_MAX_LENGTH { panic(result.BadRequestI18n(request, i18n.MatterNameLengthExceedLimit, len(filename), MATTER_NAME_MAX_LENGTH)) } @@ -479,6 +516,10 @@ func (this *MatterService) createDirectory(request *http.Request, dirMatter *Mat panic(result.BadRequest("dirMatter must be directory")) } + if dirMatter.Deleted { + panic(result.BadRequest("Dir has been deleted. Cannot create dir under it.")) + } + if dirMatter.UserUuid != user.Uuid { panic(result.BadRequest("file's user not the same")) @@ -537,6 +578,10 @@ func (this *MatterService) createDirectory(request *http.Request, dirMatter *Mat func (this *MatterService) AtomicCreateDirectory(request *http.Request, dirMatter *Matter, name string, user *User) *Matter { + if dirMatter.Deleted { + panic(result.BadRequest("Dir has been deleted. Cannot create sub dir under it.")) + } + this.userService.MatterLock(user.Uuid) defer this.userService.MatterUnlock(user.Uuid) @@ -782,6 +827,10 @@ func (this *MatterService) AtomicRename(request *http.Request, matter *Matter, n panic(result.BadRequest("user cannot be nil")) } + if matter.Deleted { + panic(result.BadRequest("matter has been deleted. Cannot rename.")) + } + this.userService.MatterLock(user.Uuid) defer this.userService.MatterUnlock(user.Uuid) @@ -869,6 +918,10 @@ func (this *MatterService) AtomicMirror(request *http.Request, srcPath string, d destDirMatter := this.CreateDirectories(request, user, destPath) + if destDirMatter.Deleted { + panic(result.BadRequest("dest matter has been deleted. Cannot mirror.")) + } + this.mirror(request, srcPath, destDirMatter, overwrite, user) } @@ -1036,6 +1089,10 @@ func (this *MatterService) AtomicCrawl(request *http.Request, url string, filena panic(result.BadRequest("user cannot be nil.")) } + if dirMatter.Deleted { + panic(result.BadRequest("Dir has been deleted. Cannot crawl under it.")) + } + this.userService.MatterLock(user.Uuid) defer this.userService.MatterUnlock(user.Uuid) @@ -1138,7 +1195,7 @@ func (this *MatterService) scanPhysicsFolder(request *http.Request, dirInfo os.F } //fetch all matters under this folder. - _, matters := this.matterDao.PlainPage(0, 1000, dirMatter.Uuid, user.Uuid, "", "", nil, nil) + _, matters := this.matterDao.PlainPage(0, 1000, dirMatter.Uuid, user.Uuid, "", "", "", nil, nil) nameMatterMap := make(map[string]*Matter) for _, m := range matters { nameMatterMap[m.Name] = m