diff --git a/rest/alien_controller.go b/rest/alien_controller.go index ad76124..9e3e565 100644 --- a/rest/alien_controller.go +++ b/rest/alien_controller.go @@ -279,7 +279,7 @@ func (this *AlienController) Upload(writer http.ResponseWriter, request *http.Re panic("文件大小不正确") } - dirMatter := this.matterDao.CheckDirByUuid(uploadToken.FolderUuid, user) + dirMatter := this.matterDao.CheckWithRootByUuid(uploadToken.FolderUuid, user) matter := this.matterService.Upload(file, user, dirMatter, uploadToken.Filename, uploadToken.Privacy) @@ -343,6 +343,12 @@ func (this *AlienController) CrawlDirect(writer http.ResponseWriter, request *ht //文件名。 filename := request.FormValue("filename") + //文件公有或私有 + privacyStr := request.FormValue("privacy") + //文件夹路径,以 / 开头。 + dir := request.FormValue("dir") + + if filename == "" { panic("文件名必填") } else if m, _ := regexp.MatchString(`[<>|*?/\\]`, filename); m { @@ -354,8 +360,6 @@ func (this *AlienController) CrawlDirect(writer http.ResponseWriter, request *ht panic("资源url必填,并且应该以http://或者https://开头") } - //文件公有或私有 - privacyStr := request.FormValue("privacy") var privacy bool if privacyStr == "" { panic(`文件公有性必填`) @@ -369,8 +373,6 @@ func (this *AlienController) CrawlDirect(writer http.ResponseWriter, request *ht } } - //文件夹路径,以 / 开头。 - dir := request.FormValue("dir") user := this.CheckRequestUser(writer, request) dirUuid, dirRelativePath := this.matterService.GetDirUuid(user, dir) diff --git a/rest/dav_service.go b/rest/dav_service.go index b6aec2f..0b49fc1 100644 --- a/rest/dav_service.go +++ b/rest/dav_service.go @@ -161,13 +161,8 @@ func (this *DavService) HandlePropfind(writer http.ResponseWriter, request *http this.PanicError(err) //寻找符合条件的matter. - var matter *Matter //如果是空或者/就是请求根目录 - if subPath == "" || subPath == "/" { - matter = NewRootMatter(user) - } else { - matter = this.matterDao.checkByUserUuidAndPath(user.Uuid, subPath) - } + matter := this.matterDao.CheckWithRootByPath(subPath, user) var matters []*Matter if depth == 0 { @@ -208,14 +203,7 @@ func (this *DavService) HandleGetHeadPost(writer http.ResponseWriter, request *h fmt.Printf("GET %s\n", subPath) - //寻找符合条件的matter. - var matter *Matter - //如果是空或者/就是请求根目录 - if subPath == "" || subPath == "/" { - matter = NewRootMatter(user) - } else { - matter = this.matterDao.checkByUserUuidAndPath(user.Uuid, subPath) - } + matter := this.matterDao.CheckWithRootByPath(subPath, user) //如果是文件夹,相当于是 Propfind if matter.Dir { @@ -237,14 +225,7 @@ func (this *DavService) HandlePut(writer http.ResponseWriter, request *http.Requ dirPath := GetDirOfPath(subPath) //寻找符合条件的matter. - var matter *Matter - //如果是空或者/就是请求根目录 - if dirPath == "" || dirPath == "/" { - matter = NewRootMatter(user) - } else { - matter = this.matterDao.checkByUserUuidAndPath(user.Uuid, dirPath) - } - + dirMatter := this.matterDao.CheckWithRootByPath(dirPath, user) //如果存在,那么先删除再说。 srcMatter := this.matterDao.findByUserUuidAndPath(user.Uuid, subPath) @@ -252,8 +233,7 @@ func (this *DavService) HandlePut(writer http.ResponseWriter, request *http.Requ this.matterService.Delete(srcMatter) } - - this.matterService.Upload(request.Body, user, matter, filename, true) + this.matterService.Upload(request.Body, user, dirMatter, filename, true) } @@ -263,13 +243,7 @@ func (this *DavService) HandleDelete(writer http.ResponseWriter, request *http.R fmt.Printf("DELETE %s\n", subPath) //寻找符合条件的matter. - var matter *Matter - //如果是空或者/就是请求根目录 - if subPath == "" || subPath == "/" { - matter = NewRootMatter(user) - } else { - matter = this.matterDao.checkByUserUuidAndPath(user.Uuid, subPath) - } + matter := this.matterDao.CheckWithRootByPath(subPath, user) this.matterService.Delete(matter) } @@ -283,13 +257,7 @@ func (this *DavService) HandleMkcol(writer http.ResponseWriter, request *http.Re dirPath := GetDirOfPath(subPath) //寻找符合条件的matter. - var dirMatter *Matter - //如果是空或者/就是请求根目录 - if dirPath == "" || dirPath == "/" { - dirMatter = NewRootMatter(user) - } else { - dirMatter = this.matterDao.checkByUserUuidAndPath(user.Uuid, dirPath) - } + dirMatter := this.matterDao.CheckWithRootByPath(dirPath, user) this.matterService.CreateDirectory(dirMatter, thisDirName, user) @@ -301,13 +269,7 @@ func (this *DavService) HandleOptions(w http.ResponseWriter, r *http.Request, us fmt.Printf("OPTIONS %s\n", subPath) //寻找符合条件的matter. - var matter *Matter - //如果是空或者/就是请求根目录 - if subPath == "" || subPath == "/" { - matter = NewRootMatter(user) - } else { - matter = this.matterDao.checkByUserUuidAndPath(user.Uuid, subPath) - } + matter := this.matterDao.CheckWithRootByPath(subPath, user) allow := "OPTIONS, LOCK, PUT, MKCOL" if matter.Dir { @@ -333,7 +295,8 @@ func (this *DavService) prepareMoveCopy( destDirMatter *Matter, srcDirPath string, destinationDirPath string, - destinationName string) { + destinationName string, + overwrite bool) { //解析出目标路径。 destinationStr := request.Header.Get("Destination") @@ -376,7 +339,7 @@ func (this *DavService) prepareMoveCopy( destinationDirPath = GetDirOfPath(destinationPath) srcDirPath = GetDirOfPath(subPath) - overwrite := false + overwrite = false if overwriteStr == "T" { overwrite = true } @@ -387,36 +350,15 @@ func (this *DavService) prepareMoveCopy( } //源matter. + //寻找符合条件的matter. + srcMatter = this.matterDao.CheckWithRootByPath(subPath, user) + //如果是空或者/就是请求根目录 - if subPath == "" || subPath == "/" { + if srcMatter.Uuid == MATTER_ROOT { this.PanicBadRequest("你不能移动根目录!") - } else { - srcMatter = this.matterDao.checkByUserUuidAndPath(user.Uuid, subPath) } - //目标matter - destMatter := this.matterDao.findByUserUuidAndPath(user.Uuid, destinationPath) - - //目标文件夹matter - if destinationDirPath == "" || destinationDirPath == "/" { - destDirMatter = NewRootMatter(user) - } else { - destDirMatter = this.matterDao.checkByUserUuidAndPath(user.Uuid, destinationDirPath) - } - - //如果目标matter存在了。 - if destMatter != nil { - - //如果目标matter还存在了。 - if overwrite { - //要求覆盖。那么删除。 - this.matterService.Delete(destMatter) - } else { - this.PanicBadRequest("%s已经存在,操作失败!", destinationName) - } - } - - return srcMatter, destDirMatter, srcDirPath, destinationDirPath, destinationName + return srcMatter, destDirMatter, srcDirPath, destinationDirPath, destinationName, overwrite } @@ -425,16 +367,16 @@ func (this *DavService) HandleMove(writer http.ResponseWriter, request *http.Req fmt.Printf("MOVE %s\n", subPath) - srcMatter, destDirMatter, srcDirPath, destinationDirPath, destinationName := this.prepareMoveCopy(writer, request, user, subPath) + srcMatter, destDirMatter, srcDirPath, destinationDirPath, destinationName, overwrite := this.prepareMoveCopy(writer, request, user, subPath) //移动到新目录中去。 if destinationDirPath == srcDirPath { //文件夹没变化,相当于重命名。 this.matterService.Rename(srcMatter, destinationName, user) } else { - this.matterService.Move(srcMatter, destDirMatter) + this.matterService.Move(srcMatter, destDirMatter, overwrite) } - this.logger.Info("完成移动 %s => %s", subPath, destinationDirPath) + this.logger.Info("完成移动 %s => %s", subPath, destDirMatter.Path) } //复制文件/文件夹 @@ -442,12 +384,12 @@ func (this *DavService) HandleCopy(writer http.ResponseWriter, request *http.Req fmt.Printf("COPY %s\n", subPath) - srcMatter, destDirMatter, _, destinationDirPath, destinationName := this.prepareMoveCopy(writer, request, user, subPath) + srcMatter, destDirMatter, _, _, destinationName, overwrite := this.prepareMoveCopy(writer, request, user, subPath) //复制到新目录中去。 - this.matterService.Copy(srcMatter, destDirMatter, destinationName) + this.matterService.Copy(srcMatter, destDirMatter, destinationName,overwrite) - this.logger.Info("完成复制 %s => %s", subPath, destinationDirPath) + this.logger.Info("完成复制 %s => %s", subPath, destDirMatter.Path) } diff --git a/rest/download/download.go b/rest/download/download.go index 3ac46aa..1feab50 100644 --- a/rest/download/download.go +++ b/rest/download/download.go @@ -362,3 +362,37 @@ func DownloadFile( } } + + + +// 从指定的url下载一个文件。参考:https://golangcode.com/download-a-file-from-a-url/ +func HttpDownloadFile(filepath string, url string) (int64, error) { + + // Create the file + out, err := os.Create(filepath) + if err != nil { + return 0, err + } + defer func() { + e := out.Close() + PanicError(e) + }() + + // Get the data + resp, err := http.Get(url) + if err != nil { + return 0, err + } + defer func() { + e := resp.Body.Close() + PanicError(e) + }() + + // Write the body to file + size, err := io.Copy(out, resp.Body) + if err != nil { + return 0, err + } + + return size, nil +} diff --git a/rest/matter_controller.go b/rest/matter_controller.go index 261cece..26f2751 100644 --- a/rest/matter_controller.go +++ b/rest/matter_controller.go @@ -232,7 +232,7 @@ func (this *MatterController) Upload(writer http.ResponseWriter, request *http.R fileName = fileName[pos+1:] } - dirMatter := this.matterDao.CheckDirByUuid(puuid, user) + dirMatter := this.matterDao.CheckWithRootByUuid(puuid, user) matter := this.matterService.Upload(file, user, dirMatter, fileName, privacy) @@ -406,31 +406,20 @@ func (this *MatterController) Move(writer http.ResponseWriter, request *http.Req } user := this.checkUser(writer, request) - if user.Role != USER_ROLE_ADMINISTRATOR { - userUuid = user.Uuid - } - if userUuid == "" { + if user.Role != USER_ROLE_ADMINISTRATOR || userUuid == "" { userUuid = user.Uuid } user = this.userDao.CheckByUuid(userUuid) //验证dest是否有问题 - var destMatter *Matter - if destUuid == "" { - this.PanicBadRequest("destUuid参数必填") - } else { - if destUuid == MATTER_ROOT { - destMatter = NewRootMatter(user) - } else { - destMatter = this.matterService.Detail(destUuid) - if !destMatter.Dir { - this.PanicBadRequest("目标不是文件夹") - } - if user.Role != USER_ROLE_ADMINISTRATOR && destMatter.UserUuid != user.Uuid { - this.PanicUnauthorized("没有权限") - } - } + var destMatter = this.matterDao.CheckWithRootByUuid(destUuid, user) + if !destMatter.Dir { + this.PanicBadRequest("目标不是文件夹") + } + + if user.Role != USER_ROLE_ADMINISTRATOR && destMatter.UserUuid != user.Uuid { + this.PanicUnauthorized("没有权限") } var srcMatters []*Matter @@ -439,10 +428,6 @@ func (this *MatterController) Move(writer http.ResponseWriter, request *http.Req //找出该文件或者文件夹 srcMatter := this.matterDao.CheckByUuid(uuid) - if user.Role != USER_ROLE_ADMINISTRATOR && srcMatter.UserUuid != user.Uuid { - this.PanicUnauthorized("没有权限") - } - if srcMatter.Puuid == destMatter.Uuid { this.PanicBadRequest("没有进行移动,操作无效!") } @@ -459,24 +444,10 @@ func (this *MatterController) Move(writer http.ResponseWriter, request *http.Req panic("文件和目标文件夹的拥有者不是同一人") } - //文件夹不能把自己移入到自己中,也不可以移入到自己的子文件夹下。 - tmpMatter := destMatter - for tmpMatter != nil { - if uuid == tmpMatter.Uuid { - panic("文件夹不能把自己移入到自己中,也不可以移入到自己的子文件夹下。") - } - tmpMatter = tmpMatter.Parent - } - srcMatters = append(srcMatters, srcMatter) } - for _, srcMatter := range srcMatters { - - //TODO:移动物理目录并且加锁。 - this.matterService.Move(srcMatter, destMatter) - - } + this.matterService.MoveBatch(srcMatters, destMatter) return this.Success(nil) } diff --git a/rest/matter_dao.go b/rest/matter_dao.go index b46fba7..23d89c7 100644 --- a/rest/matter_dao.go +++ b/rest/matter_dao.go @@ -49,9 +49,12 @@ func (this *MatterDao) CheckByUuid(uuid string) *Matter { return matter } - //按照uuid查找一个文件夹,可能返回root对应的matter. -func (this *MatterDao) CheckDirByUuid(uuid string, user *User) *Matter { +func (this *MatterDao) CheckWithRootByUuid(uuid string, user *User) *Matter { + + if uuid == "" { + this.PanicBadRequest("uuid cannot be nil.") + } var matter *Matter if uuid == MATTER_ROOT { @@ -66,6 +69,25 @@ func (this *MatterDao) CheckDirByUuid(uuid string, user *User) *Matter { return matter } +//按照path查找一个matter,可能返回root对应的matter. +func (this *MatterDao) CheckWithRootByPath(path string, user *User) *Matter { + + var matter *Matter + + if user == nil { + this.PanicBadRequest("user cannot be nil.") + } + + //目标文件夹matter + if path == "" || path == "/" { + matter = NewRootMatter(user) + } else { + matter = this.checkByUserUuidAndPath(user.Uuid, path) + } + + return matter +} + //按照名字查询文件夹 func (this *MatterDao) FindByUserUuidAndPuuidAndNameAndDirTrue(userUuid string, puuid string, name string) *Matter { diff --git a/rest/matter_service.go b/rest/matter_service.go index 83035a8..ce49bfa 100644 --- a/rest/matter_service.go +++ b/rest/matter_service.go @@ -90,7 +90,6 @@ func (this *MatterService) Upload(file io.Reader, user *User, dirMatter *Matter, this.userService.MatterLock(user.Uuid) defer this.userService.MatterUnlock(user.Uuid) - //验证dirMatter if dirMatter == nil { panic(result.BadRequest("dirMatter cannot be nil.")) @@ -245,14 +244,153 @@ func (this *MatterService) CreateDirectory(dirMatter *Matter, name string, user return matter } +//处理 移动和复制时可能存在的覆盖问题。 +func (this *MatterService) handleOverwrite(userUuid string, destinationPath string, overwrite bool) { -//将一个srcMatter复制到另一个destMatter(必须为文件夹)下,名字叫做name -func (this *MatterService) Copy(srcMatter *Matter, destDirMatter *Matter, name string) { + //目标matter。因为有可能已经存在了 + destMatter := this.matterDao.findByUserUuidAndPath(userUuid, destinationPath) + //如果目标matter存在了。 + if destMatter != nil { + //如果目标matter还存在了。 + if overwrite { + //要求覆盖。那么删除。 + this.matterDao.Delete(destMatter) + } else { + this.PanicBadRequest("%s已经存在,操作失败!", destMatter.Path) + } + } + +} + +//将一个srcMatter放置到另一个destMatter(必须为文件夹)下 不关注 overwrite 和 lock. +func (this *MatterService) innerMove(srcMatter *Matter, destDirMatter *Matter) { + + if srcMatter == nil { + panic(result.BadRequest("srcMatter cannot be nil.")) + } if !destDirMatter.Dir { this.PanicBadRequest("目标必须为文件夹") } + if srcMatter.Dir { + //如果源是文件夹 + destAbsolutePath := destDirMatter.AbsolutePath() + "/" + srcMatter.Name + srcAbsolutePath := srcMatter.AbsolutePath() + + //物理文件一口气移动 + err := os.Rename(srcAbsolutePath, destAbsolutePath) + this.PanicError(err) + + //修改数据库中信息 + srcMatter.Puuid = destDirMatter.Uuid + srcMatter.Path = destDirMatter.Path + "/" + srcMatter.Name + srcMatter = this.matterDao.Save(srcMatter) + + //调整该文件夹下文件的Path. + matters := this.matterDao.List(srcMatter.Uuid, srcMatter.UserUuid, nil) + for _, m := range matters { + this.adjustPath(m, srcMatter) + } + + } else { + //如果源是普通文件 + + destAbsolutePath := destDirMatter.AbsolutePath() + "/" + srcMatter.Name + srcAbsolutePath := srcMatter.AbsolutePath() + + //物理文件进行移动 + err := os.Rename(srcAbsolutePath, destAbsolutePath) + this.PanicError(err) + + //删除对应的缓存。 + this.imageCacheDao.DeleteByMatterUuid(srcMatter.Uuid) + + //修改数据库中信息 + srcMatter.Puuid = destDirMatter.Uuid + srcMatter.Path = destDirMatter.Path + "/" + srcMatter.Name + srcMatter = this.matterDao.Save(srcMatter) + + } + + return +} + +//将一个srcMatter放置到另一个destMatter(必须为文件夹)下 +func (this *MatterService) Move(srcMatter *Matter, destDirMatter *Matter, overwrite bool) { + + if srcMatter == nil { + panic(result.BadRequest("srcMatter cannot be nil.")) + } + + //操作锁 + this.userService.MatterLock(srcMatter.UserUuid) + defer this.userService.MatterUnlock(srcMatter.UserUuid) + + if !destDirMatter.Dir { + this.PanicBadRequest("目标必须为文件夹") + } + + + //文件夹不能把自己移入到自己中,也不可以移入到自己的子文件夹下。 + destDirMatter = this.WrapDetail(destDirMatter) + tmpMatter := destDirMatter + for tmpMatter != nil { + if srcMatter.Uuid == tmpMatter.Uuid { + panic("文件夹不能把自己移入到自己中,也不可以移入到自己的子文件夹下。") + } + tmpMatter = tmpMatter.Parent + } + + //处理覆盖的问题 + destinationPath := destDirMatter.Path + "/" + srcMatter.Name + this.handleOverwrite(srcMatter.UserUuid, destinationPath, overwrite) + + //做move操作。 + this.innerMove(srcMatter, destDirMatter) +} + +//将一个srcMatter放置到另一个destMatter(必须为文件夹)下 +func (this *MatterService) MoveBatch(srcMatters []*Matter, destDirMatter *Matter) { + + if destDirMatter == nil { + panic(result.BadRequest("destDirMatter cannot be nil.")) + } + + //操作锁 + this.userService.MatterLock(destDirMatter.UserUuid) + defer this.userService.MatterUnlock(destDirMatter.UserUuid) + + if srcMatters == nil { + panic(result.BadRequest("srcMatters cannot be nil.")) + } + + if !destDirMatter.Dir { + this.PanicBadRequest("目标必须为文件夹") + } + + //文件夹不能把自己移入到自己中,也不可以移入到自己的子文件夹下。 + destDirMatter = this.WrapDetail(destDirMatter) + for _, srcMatter := range srcMatters { + + tmpMatter := destDirMatter + for tmpMatter != nil { + if srcMatter.Uuid == tmpMatter.Uuid { + panic("文件夹不能把自己移入到自己中,也不可以移入到自己的子文件夹下。") + } + tmpMatter = tmpMatter.Parent + } + } + + for _, srcMatter := range srcMatters { + this.innerMove(srcMatter, destDirMatter) + } + +} + +//内部移动一个文件(提供给Copy调用),无需关心overwrite问题。 +func (this *MatterService) innerCopy(srcMatter *Matter, destDirMatter *Matter, name string) { + if srcMatter.Dir { //如果源是文件夹 @@ -275,10 +413,11 @@ func (this *MatterService) Copy(srcMatter *Matter, destDirMatter *Matter, name s //复制子文件或文件夹 matters := this.matterDao.List(srcMatter.Uuid, srcMatter.UserUuid, nil) for _, m := range matters { - this.Copy(m, newMatter, m.Name) + this.innerCopy(m, newMatter, m.Name) } } else { + //如果源是普通文件 destAbsolutePath := destDirMatter.AbsolutePath() + "/" + name srcAbsolutePath := srcMatter.AbsolutePath() @@ -298,258 +437,43 @@ func (this *MatterService) Copy(srcMatter *Matter, destDirMatter *Matter, name s Privacy: srcMatter.Privacy, Path: destDirMatter.Path + "/" + name, } - newMatter = this.matterDao.Create(newMatter) } - } +//将一个srcMatter复制到另一个destMatter(必须为文件夹)下,名字叫做name +func (this *MatterService) Copy(srcMatter *Matter, destDirMatter *Matter, name string, overwrite bool) { -//根据一个文件夹路径,找到最后一个文件夹的uuid,如果中途出错,返回err. -func (this *MatterService) GetDirUuid(user *User, dir string) (puuid string, dirRelativePath string) { - - if dir == "" { - panic(`文件夹不能为空`) - } else if dir[0:1] != "/" { - panic(`文件夹必须以/开头`) - } else if strings.Index(dir, "//") != -1 { - panic(`文件夹不能出现连续的//`) - } else if m, _ := regexp.MatchString(`[<>|*?\\]`, dir); m { - panic(`文件夹中不能包含以下特殊符号:< > | * ? \`) + if srcMatter == nil { + panic(result.BadRequest("srcMatter cannot be nil.")) } - if dir == "/" { - return MATTER_ROOT, "" - } + //操作锁 + this.userService.MatterLock(srcMatter.UserUuid) + defer this.userService.MatterUnlock(srcMatter.UserUuid) - if dir[len(dir)-1] == '/' { - dir = dir[:len(dir)-1] - } - - //递归找寻文件的上级目录uuid. - folders := strings.Split(dir, "/") - - if len(folders) > 32 { - panic("文件夹最多32层。") - } - - puuid = MATTER_ROOT - parentRelativePath := "/" - for k, name := range folders { - - if len(name) > 200 { - panic("每级文件夹的最大长度为200") - } - - if k == 0 { - continue - } - - matter := this.matterDao.FindByUserUuidAndPuuidAndNameAndDirTrue(user.Uuid, puuid, name) - if matter == nil { - //创建一个文件夹。这里一般都是通过alien接口来创建的文件夹。 - matter = &Matter{ - Puuid: puuid, - UserUuid: user.Uuid, - Username: user.Username, - Dir: true, - Name: name, - Path: parentRelativePath + "/" + name, - } - matter = this.matterDao.Create(matter) - } - - puuid = matter.Uuid - parentRelativePath = matter.Path - } - - return puuid, parentRelativePath -} - - -//获取某个文件的详情,会把父级依次倒着装进去。如果中途出错,直接抛出异常。 -func (this *MatterService) Detail(uuid string) *Matter { - - matter := this.matterDao.CheckByUuid(uuid) - - //组装file的内容,展示其父组件。 - puuid := matter.Puuid - tmpMatter := matter - for puuid != MATTER_ROOT { - pFile := this.matterDao.CheckByUuid(puuid) - tmpMatter.Parent = pFile - tmpMatter = pFile - puuid = pFile.Puuid - } - - return matter -} - -// 从指定的url下载一个文件。参考:https://golangcode.com/download-a-file-from-a-url/ -func (this *MatterService) httpDownloadFile(filepath string, url string) (int64, error) { - - // Create the file - out, err := os.Create(filepath) - if err != nil { - return 0, err - } - defer func() { - e := out.Close() - this.PanicError(e) - }() - - // Get the data - resp, err := http.Get(url) - if err != nil { - return 0, err - } - defer func() { - e := resp.Body.Close() - this.PanicError(e) - }() - - // Write the body to file - size, err := io.Copy(out, resp.Body) - if err != nil { - return 0, err - } - - return size, nil -} - -//去指定的url中爬文件 -func (this *MatterService) Crawl(url string, filename string, user *User, puuid string, dirRelativePath string, privacy bool) *Matter { - - //文件名不能太长。 - if len(filename) > 200 { - panic("文件名不能超过200") - } - - //获取文件应该存放在的物理路径的绝对路径和相对路径。 - absolutePath := GetUserFileRootDir(user.Username) + dirRelativePath + "/" + filename - relativePath := dirRelativePath + "/" + filename - - //使用临时文件存放 - fmt.Printf("存放于%s", absolutePath) - size, err := this.httpDownloadFile(absolutePath, url) - this.PanicError(err) - - //判断用户自身上传大小的限制。 - if user.SizeLimit >= 0 { - if size > user.SizeLimit { - panic("您最大只能上传" + HumanFileSize(user.SizeLimit) + "的文件") - } - } - - //查找文件夹下面是否有同名文件。 - matters := this.matterDao.ListByUserUuidAndPuuidAndDirAndName(user.Uuid, puuid, false, filename) - //如果有同名的文件,那么我们直接覆盖同名文件。 - for _, dbFile := range matters { - this.Delete(dbFile) - } - - //将文件信息存入数据库中。 - matter := &Matter{ - Puuid: puuid, - UserUuid: user.Uuid, - Username: user.Username, - Dir: false, - Name: filename, - Md5: "", - Size: size, - Privacy: privacy, - Path: relativePath, - } - - matter = this.matterDao.Create(matter) - - return matter -} - -//调整一个Matter的path值 -func (this *MatterService) adjustPath(matter *Matter, parentMatter *Matter) { - - if matter.Dir { - //如果源是文件夹 - - //首先调整好自己 - matter.Path = parentMatter.Path + "/" + matter.Name - matter = this.matterDao.Save(matter) - - //调整该文件夹下文件的Path. - matters := this.matterDao.List(matter.Uuid, matter.UserUuid, nil) - for _, m := range matters { - this.adjustPath(m, matter) - } - - } else { - //如果源是普通文件 - - //删除该文件的所有缓存 - this.imageCacheDao.DeleteByMatterUuid(matter.Uuid) - - //调整path - matter.Path = parentMatter.Path + "/" + matter.Name - matter = this.matterDao.Save(matter) - } - -} - -//将一个srcMatter放置到另一个destMatter(必须为文件夹)下 -func (this *MatterService) Move(srcMatter *Matter, destMatter *Matter) { - - if !destMatter.Dir { + if !destDirMatter.Dir { this.PanicBadRequest("目标必须为文件夹") } - if srcMatter.Dir { - //如果源是文件夹 - destAbsolutePath := destMatter.AbsolutePath() + "/" + srcMatter.Name - srcAbsolutePath := srcMatter.AbsolutePath() + destinationPath := destDirMatter.Path + "/" + name + this.handleOverwrite(srcMatter.UserUuid, destinationPath, overwrite) - //物理文件一口气移动 - err := os.Rename(srcAbsolutePath, destAbsolutePath) - this.PanicError(err) - - //修改数据库中信息 - srcMatter.Puuid = destMatter.Uuid - srcMatter.Path = destMatter.Path + "/" + srcMatter.Name - srcMatter = this.matterDao.Save(srcMatter) - - //调整该文件夹下文件的Path. - matters := this.matterDao.List(srcMatter.Uuid, srcMatter.UserUuid, nil) - for _, m := range matters { - this.adjustPath(m, srcMatter) - } - - } else { - //如果源是普通文件 - - destAbsolutePath := destMatter.AbsolutePath() + "/" + srcMatter.Name - srcAbsolutePath := srcMatter.AbsolutePath() - - //物理文件进行移动 - err := os.Rename(srcAbsolutePath, destAbsolutePath) - this.PanicError(err) - - //删除对应的缓存。 - this.imageCacheDao.DeleteByMatterUuid(srcMatter.Uuid) - - //修改数据库中信息 - srcMatter.Puuid = destMatter.Uuid - srcMatter.Path = destMatter.Path + "/" + srcMatter.Name - srcMatter = this.matterDao.Save(srcMatter) - - } - - return + this.innerCopy(srcMatter, destDirMatter, name) } - //将一个matter 重命名为 name func (this *MatterService) Rename(matter *Matter, name string, user *User) { + if user == nil { + this.PanicBadRequest("user cannot be nil") + } + + //操作锁 + this.userService.MatterLock(user.Uuid) + defer this.userService.MatterUnlock(user.Uuid) + //验证参数。 if name == "" { this.PanicBadRequest("name参数必填") @@ -620,3 +544,168 @@ func (this *MatterService) Rename(matter *Matter, name string, user *User) { return } + +//根据一个文件夹路径,找到最后一个文件夹的uuid,如果中途出错,返回err. +func (this *MatterService) GetDirUuid(user *User, dir string) (puuid string, dirRelativePath string) { + + if dir == "" { + panic(`文件夹不能为空`) + } else if dir[0:1] != "/" { + panic(`文件夹必须以/开头`) + } else if strings.Index(dir, "//") != -1 { + panic(`文件夹不能出现连续的//`) + } else if m, _ := regexp.MatchString(`[<>|*?\\]`, dir); m { + panic(`文件夹中不能包含以下特殊符号:< > | * ? \`) + } + + if dir == "/" { + return MATTER_ROOT, "" + } + + if dir[len(dir)-1] == '/' { + dir = dir[:len(dir)-1] + } + + //递归找寻文件的上级目录uuid. + folders := strings.Split(dir, "/") + + if len(folders) > 32 { + panic("文件夹最多32层。") + } + + puuid = MATTER_ROOT + parentRelativePath := "/" + for k, name := range folders { + + if len(name) > 200 { + panic("每级文件夹的最大长度为200") + } + + if k == 0 { + continue + } + + matter := this.matterDao.FindByUserUuidAndPuuidAndNameAndDirTrue(user.Uuid, puuid, name) + if matter == nil { + //创建一个文件夹。这里一般都是通过alien接口来创建的文件夹。 + matter = &Matter{ + Puuid: puuid, + UserUuid: user.Uuid, + Username: user.Username, + Dir: true, + Name: name, + Path: parentRelativePath + "/" + name, + } + matter = this.matterDao.Create(matter) + } + + puuid = matter.Uuid + parentRelativePath = matter.Path + } + + return puuid, parentRelativePath +} + +//包装某个matter的详情。会把父级依次倒着装进去。如果中途出错,直接抛出异常。 +func (this *MatterService) WrapDetail(matter *Matter) *Matter { + + if matter == nil { + this.PanicBadRequest("matter cannot be nil.") + } + + //组装file的内容,展示其父组件。 + puuid := matter.Puuid + tmpMatter := matter + for puuid != MATTER_ROOT { + pFile := this.matterDao.CheckByUuid(puuid) + tmpMatter.Parent = pFile + tmpMatter = pFile + puuid = pFile.Puuid + } + + return matter +} + +//获取某个文件的详情,会把父级依次倒着装进去。如果中途出错,直接抛出异常。 +func (this *MatterService) Detail(uuid string) *Matter { + matter := this.matterDao.CheckByUuid(uuid) + return this.WrapDetail(matter) +} + +//去指定的url中爬文件 +func (this *MatterService) Crawl(url string, filename string, user *User, puuid string, dirRelativePath string, privacy bool) *Matter { + + //文件名不能太长。 + if len(filename) > 200 { + panic("文件名不能超过200") + } + + //获取文件应该存放在的物理路径的绝对路径和相对路径。 + absolutePath := GetUserFileRootDir(user.Username) + dirRelativePath + "/" + filename + relativePath := dirRelativePath + "/" + filename + + //使用临时文件存放 + fmt.Printf("存放于%s", absolutePath) + size, err := download.HttpDownloadFile(absolutePath, url) + this.PanicError(err) + + //判断用户自身上传大小的限制。 + if user.SizeLimit >= 0 { + if size > user.SizeLimit { + panic("您最大只能上传" + HumanFileSize(user.SizeLimit) + "的文件") + } + } + + //查找文件夹下面是否有同名文件。 + matters := this.matterDao.ListByUserUuidAndPuuidAndDirAndName(user.Uuid, puuid, false, filename) + //如果有同名的文件,那么我们直接覆盖同名文件。 + for _, dbFile := range matters { + this.Delete(dbFile) + } + + //将文件信息存入数据库中。 + matter := &Matter{ + Puuid: puuid, + UserUuid: user.Uuid, + Username: user.Username, + Dir: false, + Name: filename, + Md5: "", + Size: size, + Privacy: privacy, + Path: relativePath, + } + + matter = this.matterDao.Create(matter) + + return matter +} + +//调整一个Matter的path值 +func (this *MatterService) adjustPath(matter *Matter, parentMatter *Matter) { + + if matter.Dir { + //如果源是文件夹 + + //首先调整好自己 + matter.Path = parentMatter.Path + "/" + matter.Name + matter = this.matterDao.Save(matter) + + //调整该文件夹下文件的Path. + matters := this.matterDao.List(matter.Uuid, matter.UserUuid, nil) + for _, m := range matters { + this.adjustPath(m, matter) + } + + } else { + //如果源是普通文件 + + //删除该文件的所有缓存 + this.imageCacheDao.DeleteByMatterUuid(matter.Uuid) + + //调整path + matter.Path = parentMatter.Path + "/" + matter.Name + matter = this.matterDao.Save(matter) + } + +}