From 5dd0fec9539a113bd19360d27127c9a811ac808b Mon Sep 17 00:00:00 2001 From: zicla Date: Wed, 1 May 2019 19:53:20 +0800 Subject: [PATCH] Finish the download archive feature. --- .../util_framework.go => core/handler.go} | 5 +- code/rest/alien_controller.go | 6 + code/rest/alien_service.go | 12 +- code/rest/base_bean.go | 2 +- code/rest/dashboard_service.go | 4 +- code/rest/dav_service.go | 4 +- code/rest/footprint_controller.go | 91 ------- code/rest/footprint_service.go | 4 +- code/rest/image_cache_controller.go | 14 +- code/rest/matter_controller.go | 98 ++++---- code/rest/matter_dao.go | 94 +++++++- code/rest/matter_model.go | 23 +- code/rest/matter_service.go | 226 ++++++++++++++++-- code/rest/preference_controller.go | 14 +- code/rest/preference_model.go | 1 + code/rest/share_controller.go | 54 ++++- code/rest/share_service.go | 8 +- code/rest/user_dao.go | 6 + code/rest/user_model.go | 28 ++- code/support/tank_application.go | 4 +- code/support/tank_config.go | 9 +- code/support/tank_logger.go | 3 +- code/support/tank_router.go | 6 +- code/test/main_test.go | 2 +- code/tool/util/util_file.go | 9 +- code/tool/util/util_zip.go | 20 +- 26 files changed, 492 insertions(+), 255 deletions(-) rename code/{tool/util/util_framework.go => core/handler.go} (75%) diff --git a/code/tool/util/util_framework.go b/code/core/handler.go similarity index 75% rename from code/tool/util/util_framework.go rename to code/core/handler.go index 4040a0f..70f50bf 100644 --- a/code/tool/util/util_framework.go +++ b/code/core/handler.go @@ -1,11 +1,10 @@ -package util +package core //带有panic恢复的方法 func RunWithRecovery(f func()) { defer func() { if err := recover(); err != nil { - //TODO 全局日志记录 - //LOGGER.Error("异步任务错误: %v", err) + LOGGER.Error("异步任务错误: %v", err) } }() diff --git a/code/rest/alien_controller.go b/code/rest/alien_controller.go index b499c40..1c97dbb 100644 --- a/code/rest/alien_controller.go +++ b/code/rest/alien_controller.go @@ -20,6 +20,7 @@ type AlienController struct { imageCacheDao *ImageCacheDao imageCacheService *ImageCacheService alienService *AlienService + shareService *ShareService } //初始化方法 @@ -61,6 +62,11 @@ func (this *AlienController) Init() { if c, ok := b.(*AlienService); ok { this.alienService = c } + + b = core.CONTEXT.GetBean(this.shareService) + if c, ok := b.(*ShareService); ok { + this.shareService = c + } } //注册自己的路由。 diff --git a/code/rest/alien_service.go b/code/rest/alien_service.go index 784ae15..8742c9c 100644 --- a/code/rest/alien_service.go +++ b/code/rest/alien_service.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/eyebluecn/tank/code/core" "github.com/eyebluecn/tank/code/tool/result" - "github.com/eyebluecn/tank/code/tool/util" "net/http" "time" ) @@ -116,11 +115,8 @@ func (this *AlienService) PreviewOrDownload( shareUuid := request.FormValue("shareUuid") shareCode := request.FormValue("shareCode") shareRootUuid := request.FormValue("shareRootUuid") - if shareUuid == "" || shareCode == "" || shareRootUuid == "" { - panic(result.UNAUTHORIZED) - } else { - this.shareService.ValidateMatter(shareUuid, shareCode, operator, shareRootUuid, matter) - } + + this.shareService.ValidateMatter(shareUuid, shareCode, operator, shareRootUuid, matter) } } @@ -131,7 +127,7 @@ func (this *AlienService) PreviewOrDownload( this.logger.Info("准备下载文件夹 %s", matter.Name) //目标地点 - this.matterService.DownloadDirectory(writer, request, matter) + this.matterService.DownloadZip(writer, request, []*Matter{matter}) } else { @@ -155,7 +151,7 @@ func (this *AlienService) PreviewOrDownload( } //文件下载次数加一,为了加快访问速度,异步进行 - go util.RunWithRecovery(func() { + go core.RunWithRecovery(func() { this.matterDao.TimesIncrement(uuid) }) diff --git a/code/rest/base_bean.go b/code/rest/base_bean.go index 0a410ca..a86f14b 100644 --- a/code/rest/base_bean.go +++ b/code/rest/base_bean.go @@ -26,7 +26,7 @@ func (this *BaseBean) Cleanup() { //处理错误的统一方法 可以省去if err!=nil 这段代码 func (this *BaseBean) PanicError(err error) { - util.PanicError(err) + core.PanicError(err) } //能找到一个user就找到一个 diff --git a/code/rest/dashboard_service.go b/code/rest/dashboard_service.go index 406e6b2..8044cda 100644 --- a/code/rest/dashboard_service.go +++ b/code/rest/dashboard_service.go @@ -56,12 +56,12 @@ func (this *DashboardService) Bootstrap() { expression := "0 5 0 * * ?" cronJob := cron.New() err := cronJob.AddFunc(expression, this.etl) - util.PanicError(err) + core.PanicError(err) cronJob.Start() this.logger.Info("[cron job] 每日00:05清洗离线数据") //立即执行一次数据清洗任务 - go util.RunWithRecovery(this.etl) + go core.RunWithRecovery(this.etl) } diff --git a/code/rest/dav_service.go b/code/rest/dav_service.go index 37c1066..8601c26 100644 --- a/code/rest/dav_service.go +++ b/code/rest/dav_service.go @@ -173,7 +173,7 @@ func (this *DavService) HandlePropfind(writer http.ResponseWriter, request *http matters = []*Matter{matter} } else { // len(matters) == 0 表示该文件夹下面是空文件夹 - matters = this.matterDao.List(matter.Uuid, user.Uuid, nil) + matters = this.matterDao.ListByPuuidAndUserUuid(matter.Uuid, user.Uuid, nil) //将当前的matter添加到头部 matters = append([]*Matter{matter}, matters...) @@ -237,7 +237,7 @@ func (this *DavService) HandlePut(writer http.ResponseWriter, request *http.Requ this.matterService.AtomicDelete(srcMatter) } - this.matterService.AtomicUpload(request.Body, user, dirMatter, filename, true) + this.matterService.Upload(request.Body, user, dirMatter, filename, true) } diff --git a/code/rest/footprint_controller.go b/code/rest/footprint_controller.go index 9e7e0d5..54d5644 100644 --- a/code/rest/footprint_controller.go +++ b/code/rest/footprint_controller.go @@ -2,10 +2,7 @@ package rest import ( "github.com/eyebluecn/tank/code/core" - "github.com/eyebluecn/tank/code/tool/builder" - "github.com/eyebluecn/tank/code/tool/result" "net/http" - "strconv" ) type FootprintController struct { @@ -36,93 +33,5 @@ func (this *FootprintController) RegisterRoutes() map[string]func(writer http.Re routeMap := make(map[string]func(writer http.ResponseWriter, request *http.Request)) - //每个Controller需要主动注册自己的路由。 - routeMap["/api/footprint/delete"] = this.Wrap(this.Delete, USER_ROLE_USER) - routeMap["/api/footprint/detail"] = this.Wrap(this.Detail, USER_ROLE_USER) - routeMap["/api/footprint/page"] = this.Wrap(this.Page, USER_ROLE_USER) - return routeMap } - -//查看详情。 -func (this *FootprintController) Detail(writer http.ResponseWriter, request *http.Request) *result.WebResult { - - uuid := request.FormValue("uuid") - if uuid == "" { - panic(result.BadRequest("图片缓存的uuid必填")) - } - - footprint := this.footprintService.Detail(uuid) - - //验证当前之人是否有权限查看这么详细。 - user := this.checkUser(writer, request) - if user.Role != USER_ROLE_ADMINISTRATOR { - if footprint.UserUuid != user.Uuid { - panic("没有权限查看该图片缓存") - } - } - - return this.Success(footprint) - -} - -//按照分页的方式查询 -func (this *FootprintController) Page(writer http.ResponseWriter, request *http.Request) *result.WebResult { - - //如果是根目录,那么就传入root. - pageStr := request.FormValue("page") - pageSizeStr := request.FormValue("pageSize") - userUuid := request.FormValue("userUuid") - orderCreateTime := request.FormValue("orderCreateTime") - orderSize := request.FormValue("orderSize") - - user := this.checkUser(writer, request) - if user.Role != USER_ROLE_ADMINISTRATOR { - userUuid = user.Uuid - } - - var page int - if pageStr != "" { - page, _ = strconv.Atoi(pageStr) - } - - pageSize := 200 - if pageSizeStr != "" { - tmp, err := strconv.Atoi(pageSizeStr) - if err == nil { - pageSize = tmp - } - } - - sortArray := []builder.OrderPair{ - { - Key: "create_time", - Value: orderCreateTime, - }, - { - Key: "size", - Value: orderSize, - }, - } - - pager := this.footprintDao.Page(page, pageSize, userUuid, sortArray) - - return this.Success(pager) -} - -//删除一条记录 -func (this *FootprintController) Delete(writer http.ResponseWriter, request *http.Request) *result.WebResult { - - uuid := request.FormValue("uuid") - if uuid == "" { - panic(result.BadRequest("uuid必填")) - } - - footprint := this.footprintDao.FindByUuid(uuid) - - if footprint != nil { - this.footprintDao.Delete(footprint) - } - - return this.Success("删除成功!") -} diff --git a/code/rest/footprint_service.go b/code/rest/footprint_service.go index 4d8271c..e53a539 100644 --- a/code/rest/footprint_service.go +++ b/code/rest/footprint_service.go @@ -98,12 +98,12 @@ func (this *FootprintService) Bootstrap() { expression := "0 10 0 * * ?" cronJob := cron.New() err := cronJob.AddFunc(expression, this.cleanOldData) - util.PanicError(err) + core.PanicError(err) cronJob.Start() this.logger.Info("[cron job] 每日00:10 删除8日之前的访问数据") //立即执行一次数据清洗任务 - go util.RunWithRecovery(this.cleanOldData) + go core.RunWithRecovery(this.cleanOldData) } diff --git a/code/rest/image_cache_controller.go b/code/rest/image_cache_controller.go index f650525..adbfec4 100644 --- a/code/rest/image_cache_controller.go +++ b/code/rest/image_cache_controller.go @@ -58,10 +58,8 @@ func (this *ImageCacheController) Detail(writer http.ResponseWriter, request *ht //验证当前之人是否有权限查看这么详细。 user := this.checkUser(writer, request) - if user.Role != USER_ROLE_ADMINISTRATOR { - if imageCache.UserUuid != user.Uuid { - panic("没有权限查看该图片缓存") - } + if imageCache.UserUuid != user.Uuid { + panic(result.UNAUTHORIZED) } return this.Success(imageCache) @@ -82,9 +80,7 @@ func (this *ImageCacheController) Page(writer http.ResponseWriter, request *http orderSize := request.FormValue("orderSize") user := this.checkUser(writer, request) - if user.Role != USER_ROLE_ADMINISTRATOR { - userUuid = user.Uuid - } + userUuid = user.Uuid var page int if pageStr != "" { @@ -136,7 +132,7 @@ func (this *ImageCacheController) Delete(writer http.ResponseWriter, request *ht //判断图片缓存的所属人是否正确 user := this.checkUser(writer, request) - if user.Role != USER_ROLE_ADMINISTRATOR && imageCache.UserUuid != user.Uuid { + if imageCache.UserUuid != user.Uuid { panic(result.Unauthorized("没有权限")) } @@ -162,7 +158,7 @@ func (this *ImageCacheController) DeleteBatch(writer http.ResponseWriter, reques //判断图片缓存的所属人是否正确 user := this.checkUser(writer, request) - if user.Role != USER_ROLE_ADMINISTRATOR && imageCache.UserUuid != user.Uuid { + if imageCache.UserUuid != user.Uuid { panic(result.Unauthorized("没有权限")) } diff --git a/code/rest/matter_controller.go b/code/rest/matter_controller.go index c6f408c..e8022b8 100644 --- a/code/rest/matter_controller.go +++ b/code/rest/matter_controller.go @@ -65,7 +65,6 @@ func (this *MatterController) Init() { if b, ok := b.(*ImageCacheService); ok { this.imageCacheService = b } - } //注册自己的路由。 @@ -87,6 +86,7 @@ func (this *MatterController) RegisterRoutes() map[string]func(writer http.Respo //本地文件映射 routeMap["/api/matter/mirror"] = this.Wrap(this.Mirror, USER_ROLE_USER) + routeMap["/api/matter/zip"] = this.Wrap(this.Zip, USER_ROLE_USER) return routeMap } @@ -103,10 +103,8 @@ func (this *MatterController) Detail(writer http.ResponseWriter, request *http.R //验证当前之人是否有权限查看这么详细。 user := this.checkUser(writer, request) - if user.Role != USER_ROLE_ADMINISTRATOR { - if matter.UserUuid != user.Uuid { - panic("没有权限查看该文件") - } + if matter.UserUuid != user.Uuid { + panic(result.UNAUTHORIZED) } return this.Success(matter) @@ -125,7 +123,6 @@ func (this *MatterController) Page(writer http.ResponseWriter, request *http.Req orderTimes := request.FormValue("orderTimes") puuid := request.FormValue("puuid") - userUuid := request.FormValue("userUuid") name := request.FormValue("name") dir := request.FormValue("dir") orderDir := request.FormValue("orderDir") @@ -133,6 +130,8 @@ func (this *MatterController) Page(writer http.ResponseWriter, request *http.Req orderName := request.FormValue("orderName") extensionsStr := request.FormValue("extensions") + var userUuid string + //使用分享提取码的形式授权。 shareUuid := request.FormValue("shareUuid") shareCode := request.FormValue("shareCode") @@ -151,13 +150,13 @@ func (this *MatterController) Page(writer http.ResponseWriter, request *http.Req user := this.findUser(writer, request) //根据某个shareUuid和code,某个用户是否有权限获取 shareRootUuid 下面的 matterUuid this.shareService.ValidateMatter(shareUuid, shareCode, user, shareRootUuid, dirMatter) + userUuid = dirMatter.Uuid } else { //非分享模式要求必须登录 user := this.checkUser(writer, request) - if user.Role != USER_ROLE_ADMINISTRATOR { - userUuid = user.Uuid - } + userUuid = user.Uuid + } var page int @@ -220,14 +219,9 @@ func (this *MatterController) CreateDirectory(writer http.ResponseWriter, reques puuid := request.FormValue("puuid") name := request.FormValue("name") - userUuid := request.FormValue("userUuid") //管理员可以指定给某个用户创建文件夹。 user := this.checkUser(writer, request) - if user.Role != USER_ROLE_ADMINISTRATOR { - userUuid = user.Uuid - } - user = this.userDao.CheckByUuid(userUuid) //找到父级matter var dirMatter *Matter @@ -244,7 +238,6 @@ func (this *MatterController) CreateDirectory(writer http.ResponseWriter, reques //上传文件 func (this *MatterController) Upload(writer http.ResponseWriter, request *http.Request) *result.WebResult { - userUuid := request.FormValue("userUuid") puuid := request.FormValue("puuid") privacyStr := request.FormValue("privacy") file, handler, err := request.FormFile("file") @@ -255,11 +248,6 @@ func (this *MatterController) Upload(writer http.ResponseWriter, request *http.R }() user := this.checkUser(writer, request) - //管理员可以传到指定用户的目录下。 - if user.Role != USER_ROLE_ADMINISTRATOR { - userUuid = user.Uuid - } - user = this.userDao.CheckByUuid(userUuid) privacy := privacyStr == TRUE @@ -279,7 +267,8 @@ func (this *MatterController) Upload(writer http.ResponseWriter, request *http.R dirMatter := this.matterDao.CheckWithRootByUuid(puuid, user) - matter := this.matterService.AtomicUpload(file, user, dirMatter, fileName, privacy) + //为了支持多文件同时上传 + matter := this.matterService.Upload(file, user, dirMatter, fileName, privacy) return this.Success(matter) } @@ -289,19 +278,9 @@ func (this *MatterController) Crawl(writer http.ResponseWriter, request *http.Re url := request.FormValue("url") destPath := request.FormValue("destPath") - userUuid := request.FormValue("userUuid") filename := request.FormValue("filename") user := this.checkUser(writer, request) - if user.Role != USER_ROLE_ADMINISTRATOR { - userUuid = user.Uuid - } else { - if userUuid == "" { - userUuid = user.Uuid - } - } - - user = this.userDao.CheckByUuid(userUuid) dirMatter := this.matterService.CreateDirectories(user, destPath) @@ -330,8 +309,8 @@ func (this *MatterController) Delete(writer http.ResponseWriter, request *http.R //判断文件的所属人是否正确 user := this.checkUser(writer, request) - if user.Role != USER_ROLE_ADMINISTRATOR && matter.UserUuid != user.Uuid { - panic(result.Unauthorized("没有权限")) + if matter.UserUuid != user.Uuid { + panic(result.UNAUTHORIZED) } this.matterService.AtomicDelete(matter) @@ -361,8 +340,8 @@ func (this *MatterController) DeleteBatch(writer http.ResponseWriter, request *h //判断文件的所属人是否正确 user := this.checkUser(writer, request) - if user.Role != USER_ROLE_ADMINISTRATOR && matter.UserUuid != user.Uuid { - panic(result.Unauthorized("没有权限")) + if matter.UserUuid != user.Uuid { + panic(result.UNAUTHORIZED) } this.matterService.AtomicDelete(matter) @@ -383,8 +362,8 @@ func (this *MatterController) Rename(writer http.ResponseWriter, request *http.R //找出该文件或者文件夹 matter := this.matterDao.CheckByUuid(uuid) - if user.Role != USER_ROLE_ADMINISTRATOR && matter.UserUuid != user.Uuid { - panic(result.Unauthorized("没有权限")) + if matter.UserUuid != user.Uuid { + panic(result.UNAUTHORIZED) } this.matterService.AtomicRename(matter, name, user) @@ -409,8 +388,8 @@ func (this *MatterController) ChangePrivacy(writer http.ResponseWriter, request //权限验证 user := this.checkUser(writer, request) - if user.Role != USER_ROLE_ADMINISTRATOR && matter.UserUuid != user.Uuid { - panic(result.Unauthorized("没有权限")) + if matter.UserUuid != user.Uuid { + panic(result.UNAUTHORIZED) } matter.Privacy = privacy @@ -424,7 +403,6 @@ func (this *MatterController) Move(writer http.ResponseWriter, request *http.Req srcUuidsStr := request.FormValue("srcUuids") destUuid := request.FormValue("destUuid") - userUuid := request.FormValue("userUuid") var srcUuids []string //验证参数。 @@ -435,11 +413,6 @@ func (this *MatterController) Move(writer http.ResponseWriter, request *http.Req } user := this.checkUser(writer, request) - if user.Role != USER_ROLE_ADMINISTRATOR || userUuid == "" { - userUuid = user.Uuid - } - - user = this.userDao.CheckByUuid(userUuid) //验证dest是否有问题 var destMatter = this.matterDao.CheckWithRootByUuid(destUuid, user) @@ -447,8 +420,8 @@ func (this *MatterController) Move(writer http.ResponseWriter, request *http.Req panic(result.BadRequest("目标不是文件夹")) } - if user.Role != USER_ROLE_ADMINISTRATOR && destMatter.UserUuid != user.Uuid { - panic(result.Unauthorized("没有权限")) + if destMatter.UserUuid != user.Uuid { + panic(result.UNAUTHORIZED) } var srcMatters []*Matter @@ -504,3 +477,34 @@ func (this *MatterController) Mirror(writer http.ResponseWriter, request *http.R return this.Success(nil) } + +//下载压缩包 +func (this *MatterController) Zip(writer http.ResponseWriter, request *http.Request) *result.WebResult { + + uuids := request.FormValue("uuids") + if uuids == "" { + panic(result.BadRequest("文件的uuids必填")) + } + + uuidArray := strings.Split(uuids, ",") + + matters := this.matterDao.ListByUuids(uuidArray, nil) + + if matters == nil || len(matters) == 0 { + panic(result.BadRequest("matters cannot be nil.")) + } + user := this.checkUser(writer, request) + puuid := matters[0].Puuid + + for _, m := range matters { + if m.UserUuid != user.Uuid { + panic(result.UNAUTHORIZED) + } else if m.Puuid != puuid { + panic(result.BadRequest("puuid not same")) + } + } + + this.matterService.DownloadZip(writer, request, matters) + + return nil +} diff --git a/code/rest/matter_dao.go b/code/rest/matter_dao.go index d265e41..6d0bea7 100644 --- a/code/rest/matter_dao.go +++ b/code/rest/matter_dao.go @@ -218,9 +218,24 @@ func (this *MatterDao) ListByUserUuidAndPuuidAndDirAndName(userUuid string, puui } //获取某个文件夹下所有的文件和子文件 -func (this *MatterDao) List(puuid string, userUuid string, sortArray []builder.OrderPair) []*Matter { +func (this *MatterDao) ListByPuuidAndUserUuid(puuid string, userUuid string, sortArray []builder.OrderPair) []*Matter { var matters []*Matter + if sortArray == nil { + + //顺序按照文件夹,创建时间 + sortArray = []builder.OrderPair{ + { + Key: "dir", + Value: DIRECTION_DESC, + }, + { + Key: "create_time", + Value: DIRECTION_DESC, + }, + } + } + db := core.CONTEXT.GetDB().Where(Matter{UserUuid: userUuid, Puuid: puuid}).Order(this.GetSortString(sortArray)).Find(&matters) this.PanicError(db.Error) @@ -228,10 +243,10 @@ func (this *MatterDao) List(puuid string, userUuid string, sortArray []builder.O } //根据uuid查找对应的Matters -func (this *MatterDao) ListByUuids(puuids []string, sortArray []builder.OrderPair) []*Matter { +func (this *MatterDao) ListByUuids(uuids []string, sortArray []builder.OrderPair) []*Matter { var matters []*Matter - db := core.CONTEXT.GetDB().Where(puuids).Order(this.GetSortString(sortArray)).Find(&matters) + db := core.CONTEXT.GetDB().Where(uuids).Order(this.GetSortString(sortArray)).Find(&matters) this.PanicError(db.Error) return matters @@ -315,12 +330,68 @@ func (this *MatterDao) TimesIncrement(matterUuid string) { this.PanicError(db.Error) } +//获取一个文件夹中直系文件/文件夹的总大小 puuid可以传root +func (this *MatterDao) SizeByPuuidAndUserUuid(matterUuid string, userUuid string) int64 { + + var wp = &builder.WherePair{Query: "puuid = ? AND user_uuid = ?", Args: []interface{}{matterUuid, userUuid}} + + var count int64 + db := core.CONTEXT.GetDB().Model(&Matter{}).Where(wp.Query, wp.Args...).Count(&count) + if count == 0 { + return 0 + } + + var sumSize int64 + db = core.CONTEXT.GetDB().Model(&Matter{}).Where(wp.Query, wp.Args...).Select("SUM(size)") + this.PanicError(db.Error) + row := db.Row() + err := row.Scan(&sumSize) + core.PanicError(err) + + return sumSize +} + +//统计某个文件/文件夹的大小(会自动往上统计,直到根目录) +func (this *MatterDao) ComputeRouteSize(matterUuid string, userUuid string) { + + //如果更新到了根目录,那么更新到用户身上。 + if matterUuid == MATTER_ROOT { + + size := this.SizeByPuuidAndUserUuid(MATTER_ROOT, userUuid) + + //更新用户文件的总大小。 + db := core.CONTEXT.GetDB().Model(&User{}).Where("uuid = ?", userUuid).Update("total_size", size) + this.PanicError(db.Error) + + return + } + + matter := this.CheckByUuid(matterUuid) + + //只有文件夹才去统计 + if matter.Dir { + //计算该目录下的直系文件/文件夹总大小 + size := this.SizeByPuuidAndUserUuid(matterUuid, userUuid) + + //大小有变化才更新 + if matter.Size != size { + //更新大小。 + db := core.CONTEXT.GetDB().Model(&Matter{}).Where("uuid = ?", matterUuid).Update("size", size) + this.PanicError(db.Error) + } + + } + + //更新自己的上一级目录。 + this.ComputeRouteSize(matter.Puuid, userUuid) +} + //删除一个文件,数据库中删除,物理磁盘上删除。 func (this *MatterDao) Delete(matter *Matter) { //目录的话递归删除。 if matter.Dir { - matters := this.List(matter.Uuid, matter.UserUuid, nil) + matters := this.ListByPuuidAndUserUuid(matter.Uuid, matter.UserUuid, nil) for _, f := range matters { this.Delete(f) @@ -426,12 +497,25 @@ func (this *MatterDao) SumSizeByUserUuidAndPath(userUuid string, path string) in this.PanicError(db.Error) row := db.Row() err := row.Scan(&sumSize) - util.PanicError(err) + core.PanicError(err) return sumSize } +//一个文件夹中的数量 +func (this *MatterDao) CountByUserUuidAndPath(userUuid string, path string) int64 { + + var wp = &builder.WherePair{Query: "user_uuid = ? AND path like ?", Args: []interface{}{userUuid, path + "%"}} + + var count int64 + db := core.CONTEXT.GetDB().Model(&Matter{}).Where(wp.Query, wp.Args...).Count(&count) + core.PanicError(db.Error) + + return count + +} + //执行清理操作 func (this *MatterDao) Cleanup() { this.logger.Info("[MatterDao]执行清理:清除数据库中所有Matter记录。删除磁盘中所有Matter文件。") diff --git a/code/rest/matter_model.go b/code/rest/matter_model.go index 58bba23..7296627 100644 --- a/code/rest/matter_model.go +++ b/code/rest/matter_model.go @@ -24,17 +24,18 @@ const ( */ type Matter struct { Base - Puuid string `json:"puuid" gorm:"type:char(36);index:idx_puuid"` - UserUuid string `json:"userUuid" gorm:"type:char(36);index:idx_uu"` - Username string `json:"username" gorm:"type:varchar(45) not null"` - Dir bool `json:"dir" gorm:"type:tinyint(1) not null;default:0"` - Name string `json:"name" gorm:"type:varchar(255) not null"` - Md5 string `json:"md5" gorm:"type:varchar(45)"` - Size int64 `json:"size" gorm:"type:bigint(20) not null;default:0"` - Privacy bool `json:"privacy" gorm:"type:tinyint(1) not null;default:0"` - Path string `json:"path" gorm:"type:varchar(1024)"` - Times int64 `json:"times" gorm:"type:bigint(20) not null;default:0"` - Parent *Matter `json:"parent" gorm:"-"` + Puuid string `json:"puuid" gorm:"type:char(36);index:idx_puuid"` + UserUuid string `json:"userUuid" gorm:"type:char(36);index:idx_uu"` + Username string `json:"username" gorm:"type:varchar(45) not null"` + Dir bool `json:"dir" gorm:"type:tinyint(1) not null;default:0"` + Name string `json:"name" gorm:"type:varchar(255) not null"` + Md5 string `json:"md5" gorm:"type:varchar(45)"` + Size int64 `json:"size" gorm:"type:bigint(20) not null;default:0"` + Privacy bool `json:"privacy" gorm:"type:tinyint(1) not null;default:0"` + Path string `json:"path" gorm:"type:varchar(1024)"` + Times int64 `json:"times" gorm:"type:bigint(20) not null;default:0"` + Parent *Matter `json:"parent" gorm:"-"` + Children []*Matter `json:"-" gorm:"-"` } // set File's table name to be `profiles` diff --git a/code/rest/matter_service.go b/code/rest/matter_service.go index c1aa3ef..adf3256 100644 --- a/code/rest/matter_service.go +++ b/code/rest/matter_service.go @@ -1,6 +1,7 @@ package rest import ( + "archive/zip" "fmt" "github.com/eyebluecn/tank/code/core" "github.com/eyebluecn/tank/code/tool/download" @@ -78,26 +79,54 @@ func (this *MatterService) DownloadFile( download.DownloadFile(writer, request, filePath, filename, withContentDisposition) } -//下载文件夹 -func (this *MatterService) DownloadDirectory( +//下载文件 要求必须是同一个父matter下的。 +func (this *MatterService) DownloadZip( writer http.ResponseWriter, request *http.Request, - matter *Matter) { + matters []*Matter) { - if matter == nil { - panic(result.BadRequest("matter不能为nil")) + if matters == nil || len(matters) == 0 { + panic(result.BadRequest("matters cannot be nil.")) + } + userUuid := matters[0].UserUuid + puuid := matters[0].Puuid + + for _, m := range matters { + if m.UserUuid != userUuid { + panic(result.BadRequest("userUuid not same")) + } else if m.Puuid != puuid { + panic(result.BadRequest("puuid not same")) + } } - if !matter.Dir { - panic(result.BadRequest("matter 只能是文件夹")) + preference := this.preferenceService.Fetch() + + var count int64 = 0 + for _, matter := range matters { + //验证文件夹中文件数量 + count = count + this.matterDao.CountByUserUuidAndPath(matter.UserUuid, matter.Path) + } + + this.logger.Info("此次下载包含文件数量 %s", count) + + //文件数量判断。 + if preference.DownloadDirMaxNum >= 0 { + if count > preference.DownloadDirMaxNum { + panic(result.BadRequest("下载包中文件数量 %d 超出限制了 %d ", count, preference.DownloadDirMaxNum)) + } + } + + var sumSize int64 = 0 + for _, matter := range matters { + //验证文件夹中文件数量 + sumSize = sumSize + this.matterDao.SumSizeByUserUuidAndPath(matter.UserUuid, matter.Path) } //验证文件夹中文件总大小。 - sumSize := this.matterDao.SumSizeByUserUuidAndPath(matter.UserUuid, matter.Path) - this.logger.Info("文件夹 %s 大小为 %s", matter.Name, util.HumanFileSize(sumSize)) + this.logger.Info("此次下载大小为 %s", util.HumanFileSize(sumSize)) //判断用户自身上传大小的限制 - preference := this.preferenceService.Fetch() + //大小判断 if preference.DownloadDirMaxSize >= 0 { if sumSize > preference.DownloadDirMaxSize { panic(result.BadRequest("文件夹大小%s超出下载限制%s ", util.HumanFileSize(sumSize), util.HumanFileSize(preference.DownloadDirMaxSize))) @@ -105,14 +134,18 @@ func (this *MatterService) DownloadDirectory( } //准备zip放置的目录。 - destZipDirPath := fmt.Sprintf("%s/%d", GetUserZipRootDir(matter.Username), time.Now().UnixNano()/1e6) + destZipDirPath := fmt.Sprintf("%s/%d", GetUserZipRootDir(matters[0].Username), time.Now().UnixNano()/1e6) util.MakeDirAll(destZipDirPath) - destZipName := fmt.Sprintf("%s.zip", matter.Name) + destZipName := fmt.Sprintf("%s.zip", matters[0].Name) + if len(matters) > 1 || !matters[0].Dir { + destZipName = "archive.zip" + } destZipPath := fmt.Sprintf("%s/%s", destZipDirPath, destZipName) - util.Zip(matter.AbsolutePath(), destZipPath) + //_ = util.Zip(matter.AbsolutePath(), destZipPath) + this.zipMatters(matters, destZipPath) //下载 download.DownloadFile(writer, request, destZipPath, destZipName, true) @@ -126,6 +159,118 @@ func (this *MatterService) DownloadDirectory( } +//打包一系列的matter +func (this *MatterService) zipMatters(matters []*Matter, destPath string) { + + if util.PathExists(destPath) { + panic(result.BadRequest("%s 已经存在了", destPath)) + } + + //要求必须是同一个父matter下的。 + if matters == nil || len(matters) == 0 { + panic(result.BadRequest("matters cannot be nil.")) + } + userUuid := matters[0].UserUuid + puuid := matters[0].Puuid + baseDirPath := util.GetDirOfPath(matters[0].AbsolutePath()) + + for _, m := range matters { + if m.UserUuid != userUuid { + panic(result.BadRequest("userUuid not same")) + } else if m.Puuid != puuid { + panic(result.BadRequest("puuid not same")) + } + } + + //将每个matter的children装填好 + for _, m := range matters { + this.WrapChildrenDetail(m) + } + + // 创建准备写入的文件 + fileWriter, err := os.Create(destPath) + this.PanicError(err) + + defer func() { + err := fileWriter.Close() + this.PanicError(err) + }() + + // 通过 fileWriter 来创建 zip.Write + zipWriter := zip.NewWriter(fileWriter) + defer func() { + // 检测一下是否成功关闭 + err := zipWriter.Close() + this.PanicError(err) + }() + + //采用深度优先搜索算法。 + var walkFunc func(matter *Matter) + walkFunc = func(matter *Matter) { + + path := matter.AbsolutePath() + + fileInfo, err := os.Stat(path) + this.PanicError(err) + + // 通过文件信息,创建 zip 的文件信息 + fileHeader, err := zip.FileInfoHeader(fileInfo) + this.PanicError(err) + + // 替换文件信息中的文件名 + fileHeader.Name = strings.TrimPrefix(path, baseDirPath) + + // 目录前要加上/ + if matter.Dir { + fileHeader.Name += "/" + } + + // 写入文件信息,并返回一个 Write 结构 + writer, err := zipWriter.CreateHeader(fileHeader) + this.PanicError(err) + + // 检测,如果不是标准文件就只写入头信息,不写入文件数据到 writer + // 如目录,也没有数据需要写 + if fileHeader.Mode().IsRegular() { + + // 打开要压缩的文件 + fileToBeZip, err := os.Open(path) + defer func() { + err = fileToBeZip.Close() + this.PanicError(err) + }() + this.PanicError(err) + + // 将打开的文件 Copy 到 writer + _, err = io.Copy(writer, fileToBeZip) + this.PanicError(err) + + } + + //如果有子文件,继续往下钻 + for _, m := range matter.Children { + walkFunc(m) + } + } + + for _, m := range matters { + walkFunc(m) + } +} + +//删除文件 +func (this *MatterService) Delete(matter *Matter) { + + if matter == nil { + panic(result.BadRequest("matter不能为nil")) + } + + this.matterDao.Delete(matter) + + //重新计算文件大小 + this.matterDao.ComputeRouteSize(matter.Puuid, matter.UserUuid) +} + //删除文件 func (this *MatterService) AtomicDelete(matter *Matter) { @@ -137,7 +282,7 @@ func (this *MatterService) AtomicDelete(matter *Matter) { this.userService.MatterLock(matter.UserUuid) defer this.userService.MatterUnlock(matter.UserUuid) - this.matterDao.Delete(matter) + this.Delete(matter) } //上传文件 @@ -219,6 +364,11 @@ func (this *MatterService) Upload(file io.Reader, user *User, dirMatter *Matter, } matter = this.matterDao.Create(matter) + //统计文件夹的大小。 + go core.RunWithRecovery(func() { + this.matterDao.ComputeRouteSize(dirMatter.Uuid, user.Uuid) + }) + return matter } @@ -330,7 +480,7 @@ func (this *MatterService) handleOverwrite(userUuid string, destinationPath stri //如果目标matter还存在了。 if overwrite { //要求覆盖。那么删除。 - this.matterDao.Delete(destMatter) + this.Delete(destMatter) } else { panic(result.BadRequest("%s已经存在,操作失败!", destMatter.Path)) } @@ -349,6 +499,10 @@ func (this *MatterService) move(srcMatter *Matter, destDirMatter *Matter) { panic(result.BadRequest("目标必须为文件夹")) } + userUuid := srcMatter.UserUuid + srcPuuid := srcMatter.Puuid + destDirUuid := destDirMatter.Uuid + if srcMatter.Dir { //如果源是文件夹 destAbsolutePath := destDirMatter.AbsolutePath() + "/" + srcMatter.Name @@ -364,7 +518,7 @@ func (this *MatterService) move(srcMatter *Matter, destDirMatter *Matter) { srcMatter = this.matterDao.Save(srcMatter) //调整该文件夹下文件的Path. - matters := this.matterDao.List(srcMatter.Uuid, srcMatter.UserUuid, nil) + matters := this.matterDao.ListByPuuidAndUserUuid(srcMatter.Uuid, srcMatter.UserUuid, nil) for _, m := range matters { this.adjustPath(m, srcMatter) } @@ -389,7 +543,10 @@ func (this *MatterService) move(srcMatter *Matter, destDirMatter *Matter) { } - return + //调整两个文件夹的大小 + this.matterDao.ComputeRouteSize(srcPuuid, userUuid) + this.matterDao.ComputeRouteSize(destDirUuid, userUuid) + } //将一个srcMatter放置到另一个destMatter(必须为文件夹)下 @@ -411,7 +568,7 @@ func (this *MatterService) AtomicMove(srcMatter *Matter, destDirMatter *Matter, } //文件夹不能把自己移入到自己中,也不可以移入到自己的子文件夹下。 - destDirMatter = this.WrapDetail(destDirMatter) + destDirMatter = this.WrapParentDetail(destDirMatter) tmpMatter := destDirMatter for tmpMatter != nil { if srcMatter.Uuid == tmpMatter.Uuid { @@ -448,7 +605,7 @@ func (this *MatterService) AtomicMoveBatch(srcMatters []*Matter, destDirMatter * } //文件夹不能把自己移入到自己中,也不可以移入到自己的子文件夹下。 - destDirMatter = this.WrapDetail(destDirMatter) + destDirMatter = this.WrapParentDetail(destDirMatter) for _, srcMatter := range srcMatters { tmpMatter := destDirMatter @@ -489,7 +646,7 @@ func (this *MatterService) copy(srcMatter *Matter, destDirMatter *Matter, name s newMatter = this.matterDao.Create(newMatter) //复制子文件或文件夹 - matters := this.matterDao.List(srcMatter.Uuid, srcMatter.UserUuid, nil) + matters := this.matterDao.ListByPuuidAndUserUuid(srcMatter.Uuid, srcMatter.UserUuid, nil) for _, m := range matters { this.copy(m, newMatter, m.Name) } @@ -593,7 +750,7 @@ func (this *MatterService) AtomicRename(matter *Matter, name string, user *User) matter = this.matterDao.Save(matter) //调整该文件夹下文件的Path. - matters := this.matterDao.List(matter.Uuid, matter.UserUuid, nil) + matters := this.matterDao.ListByPuuidAndUserUuid(matter.Uuid, matter.UserUuid, nil) for _, m := range matters { this.adjustPath(m, matter) } @@ -691,7 +848,7 @@ func (this *MatterService) mirror(srcPath string, destDirMatter *Matter, overwri if matter != nil { //如果是覆盖,那么删除之前的文件 if overwrite { - this.matterDao.Delete(matter) + this.Delete(matter) } else { //直接完成。 return @@ -757,7 +914,7 @@ func (this *MatterService) CreateDirectories(user *User, dirPath string) *Matter } //包装某个matter的详情。会把父级依次倒着装进去。如果中途出错,直接抛出异常。 -func (this *MatterService) WrapDetail(matter *Matter) *Matter { +func (this *MatterService) WrapParentDetail(matter *Matter) *Matter { if matter == nil { panic(result.BadRequest("matter cannot be nil.")) @@ -776,10 +933,29 @@ func (this *MatterService) WrapDetail(matter *Matter) *Matter { return matter } +//包装某个matter的详情。会把子级依次装进去。如果中途出错,直接抛出异常。 +func (this *MatterService) WrapChildrenDetail(matter *Matter) { + + if matter == nil { + panic(result.BadRequest("matter cannot be nil.")) + } + + if matter.Dir { + + children := this.matterDao.ListByPuuidAndUserUuid(matter.Uuid, matter.UserUuid, nil) + matter.Children = children + + for _, child := range matter.Children { + this.WrapChildrenDetail(child) + } + } + +} + //获取某个文件的详情,会把父级依次倒着装进去。如果中途出错,直接抛出异常。 func (this *MatterService) Detail(uuid string) *Matter { matter := this.matterDao.CheckByUuid(uuid) - return this.WrapDetail(matter) + return this.WrapParentDetail(matter) } //去指定的url中爬文件 @@ -819,7 +995,7 @@ func (this *MatterService) adjustPath(matter *Matter, parentMatter *Matter) { matter = this.matterDao.Save(matter) //调整该文件夹下文件的Path. - matters := this.matterDao.List(matter.Uuid, matter.UserUuid, nil) + matters := this.matterDao.ListByPuuidAndUserUuid(matter.Uuid, matter.UserUuid, nil) for _, m := range matters { this.adjustPath(m, matter) } diff --git a/code/rest/preference_controller.go b/code/rest/preference_controller.go index d25431e..d028176 100644 --- a/code/rest/preference_controller.go +++ b/code/rest/preference_controller.go @@ -74,17 +74,26 @@ func (this *PreferenceController) Edit(writer http.ResponseWriter, request *http copyright := request.FormValue("copyright") record := request.FormValue("record") downloadDirMaxSizeStr := request.FormValue("downloadDirMaxSize") + downloadDirMaxNumStr := request.FormValue("downloadDirMaxNum") var downloadDirMaxSize int64 = 0 if downloadDirMaxSizeStr == "" { - panic("文件下载最大限制必填!") + panic("文件下载大小限制必填!") } else { intDownloadDirMaxSize, err := strconv.Atoi(downloadDirMaxSizeStr) this.PanicError(err) - downloadDirMaxSize = int64(intDownloadDirMaxSize) } + var downloadDirMaxNum int64 = 0 + if downloadDirMaxNumStr == "" { + panic("文件下载数量限制必填!") + } else { + intDownloadDirMaxNum, err := strconv.Atoi(downloadDirMaxNumStr) + this.PanicError(err) + downloadDirMaxNum = int64(intDownloadDirMaxNum) + } + preference := this.preferenceDao.Fetch() preference.Name = name preference.LogoUrl = logoUrl @@ -92,6 +101,7 @@ func (this *PreferenceController) Edit(writer http.ResponseWriter, request *http preference.Copyright = copyright preference.Record = record preference.DownloadDirMaxSize = downloadDirMaxSize + preference.DownloadDirMaxNum = downloadDirMaxNum preference = this.preferenceDao.Save(preference) diff --git a/code/rest/preference_model.go b/code/rest/preference_model.go index 2645c62..85f5b56 100644 --- a/code/rest/preference_model.go +++ b/code/rest/preference_model.go @@ -10,6 +10,7 @@ type Preference struct { Copyright string `json:"copyright" gorm:"type:varchar(1024)"` Record string `json:"record" gorm:"type:varchar(1024)"` DownloadDirMaxSize int64 `json:"downloadDirMaxSize" gorm:"type:bigint(20) not null;default:-1"` + DownloadDirMaxNum int64 `json:"downloadDirMaxNum" gorm:"type:bigint(20) not null;default:-1"` } // set File's table name to be `profiles` diff --git a/code/rest/share_controller.go b/code/rest/share_controller.go index 204de3c..0d07c63 100644 --- a/code/rest/share_controller.go +++ b/code/rest/share_controller.go @@ -64,6 +64,7 @@ func (this *ShareController) RegisterRoutes() map[string]func(writer http.Respon routeMap["/api/share/detail"] = this.Wrap(this.Detail, USER_ROLE_USER) routeMap["/api/share/page"] = this.Wrap(this.Page, USER_ROLE_USER) routeMap["/api/share/browse"] = this.Wrap(this.Browse, USER_ROLE_GUEST) + routeMap["/api/share/zip"] = this.Wrap(this.Zip, USER_ROLE_GUEST) return routeMap } @@ -205,8 +206,8 @@ func (this *ShareController) DeleteBatch(writer http.ResponseWriter, request *ht //判断图片缓存的所属人是否正确 user := this.checkUser(writer, request) - if user.Role != USER_ROLE_ADMINISTRATOR && imageCache.UserUuid != user.Uuid { - panic(result.Unauthorized("没有权限")) + if imageCache.UserUuid != user.Uuid { + panic(result.UNAUTHORIZED) } this.shareDao.Delete(imageCache) @@ -227,10 +228,9 @@ func (this *ShareController) Detail(writer http.ResponseWriter, request *http.Re //验证当前之人是否有权限查看这么详细。 user := this.checkUser(writer, request) - if user.Role != USER_ROLE_ADMINISTRATOR { - if share.UserUuid != user.Uuid { - panic(result.Unauthorized("没有权限")) - } + + if share.UserUuid != user.Uuid { + panic(result.UNAUTHORIZED) } return this.Success(share) @@ -243,13 +243,9 @@ func (this *ShareController) Page(writer http.ResponseWriter, request *http.Requ //如果是根目录,那么就传入root. pageStr := request.FormValue("page") pageSizeStr := request.FormValue("pageSize") - userUuid := request.FormValue("userUuid") orderCreateTime := request.FormValue("orderCreateTime") user := this.checkUser(writer, request) - if user.Role != USER_ROLE_ADMINISTRATOR { - userUuid = user.Uuid - } var page int if pageStr != "" { @@ -271,7 +267,7 @@ func (this *ShareController) Page(writer http.ResponseWriter, request *http.Requ }, } - pager := this.shareDao.Page(page, pageSize, userUuid, sortArray) + pager := this.shareDao.Page(page, pageSize, user.Uuid, sortArray) return this.Success(pager) } @@ -364,3 +360,39 @@ func (this *ShareController) Browse(writer http.ResponseWriter, request *http.Re return this.Success(share) } + +//下载压缩包 +func (this *ShareController) Zip(writer http.ResponseWriter, request *http.Request) *result.WebResult { + + //如果是根目录,那么就传入root. + shareUuid := request.FormValue("shareUuid") + code := request.FormValue("code") + + //当前查看的puuid。 puuid=root表示查看分享的根目录,其余表示查看某个文件夹下的文件。 + puuid := request.FormValue("puuid") + rootUuid := request.FormValue("rootUuid") + + user := this.findUser(writer, request) + + if puuid == MATTER_ROOT { + + //下载分享全部内容。 + share := this.shareService.CheckShare(shareUuid, code, user) + bridges := this.bridgeDao.ListByShareUuid(share.Uuid) + var matterUuids []string + for _, bridge := range bridges { + matterUuids = append(matterUuids, bridge.MatterUuid) + } + matters := this.matterDao.ListByUuids(matterUuids, nil) + this.matterService.DownloadZip(writer, request, matters) + + } else { + + //下载某个目录。 + matter := this.matterDao.CheckByUuid(puuid) + this.shareService.ValidateMatter(shareUuid, code, user, rootUuid, matter) + this.matterService.DownloadZip(writer, request, []*Matter{matter}) + } + + return nil +} diff --git a/code/rest/share_service.go b/code/rest/share_service.go index 1c8637a..4c98bb0 100644 --- a/code/rest/share_service.go +++ b/code/rest/share_service.go @@ -79,7 +79,7 @@ func (this *ShareService) CheckShare(shareUuid string, code string, user *User) func (this *ShareService) ValidateMatter(shareUuid string, code string, user *User, shareRootUuid string, matter *Matter) { if matter == nil { - panic(result.BadRequest("matter cannot be nil")) + panic(result.Unauthorized("matter cannot be nil")) } //如果文件是自己的,那么放行 @@ -87,8 +87,8 @@ func (this *ShareService) ValidateMatter(shareUuid string, code string, user *Us return } - if shareRootUuid == "" { - panic(result.BadRequest("matterUuid cannot be null")) + if shareUuid == "" || code == "" || shareRootUuid == "" { + panic(result.Unauthorized("shareUuid,code,shareRootUuid cannot be null")) } share := this.CheckShare(shareUuid, code, user) @@ -106,7 +106,7 @@ func (this *ShareService) ValidateMatter(shareUuid string, code string, user *Us //保证 puuid对应的matter是shareRootMatter的子文件夹。 child := strings.HasPrefix(matter.Path, shareRootMatter.Path) if !child { - panic(result.BadRequest("%s 不是 %s 的子文件夹!", matter.Uuid, shareRootUuid)) + panic(result.Unauthorized("%s 不是 %s 的子文件夹!", matter.Uuid, shareRootUuid)) } } diff --git a/code/rest/user_dao.go b/code/rest/user_dao.go index 48326a4..3f9ad88 100644 --- a/code/rest/user_dao.go +++ b/code/rest/user_dao.go @@ -11,6 +11,12 @@ type UserDao struct { BaseDao } +//初始化方法 +func (this *UserDao) Init() { + this.BaseDao.Init() + +} + //创建用户 func (this *UserDao) Create(user *User) *User { diff --git a/code/rest/user_model.go b/code/rest/user_model.go index e0b14d6..64d5a52 100644 --- a/code/rest/user_model.go +++ b/code/rest/user_model.go @@ -29,18 +29,20 @@ const ( type User struct { Base - Role string `json:"role" gorm:"type:varchar(45)"` - Username string `json:"username" gorm:"type:varchar(45) not null;unique"` - Password string `json:"-" gorm:"type:varchar(255)"` - Email string `json:"email" gorm:"type:varchar(45) not null;unique"` - Phone string `json:"phone" gorm:"type:varchar(45)"` - Gender string `json:"gender" gorm:"type:varchar(45)"` - City string `json:"city" gorm:"type:varchar(45)"` - AvatarUrl string `json:"avatarUrl" gorm:"type:varchar(255)"` - LastIp string `json:"lastIp" gorm:"type:varchar(128)"` - LastTime time.Time `json:"lastTime" gorm:"type:timestamp not null;default:'2018-01-01 00:00:00'"` - SizeLimit int64 `json:"sizeLimit" gorm:"type:bigint(20) not null;default:-1"` - Status string `json:"status" gorm:"type:varchar(45)"` + Role string `json:"role" gorm:"type:varchar(45)"` + Username string `json:"username" gorm:"type:varchar(45) not null;unique"` + Password string `json:"-" gorm:"type:varchar(255)"` + Email string `json:"email" gorm:"type:varchar(45) not null;unique"` + Phone string `json:"phone" gorm:"type:varchar(45)"` + Gender string `json:"gender" gorm:"type:varchar(45)"` + City string `json:"city" gorm:"type:varchar(45)"` + AvatarUrl string `json:"avatarUrl" gorm:"type:varchar(255)"` + LastIp string `json:"lastIp" gorm:"type:varchar(128)"` + LastTime time.Time `json:"lastTime" gorm:"type:timestamp not null;default:'2018-01-01 00:00:00'"` + SizeLimit int64 `json:"sizeLimit" gorm:"type:bigint(20) not null;default:-1"` + TotalSizeLimit int64 `json:"totalSizeLimit" gorm:"type:bigint(20) not null;default:-1"` + TotalSize int64 `json:"totalSize" gorm:"type:bigint(20) not null;default:0"` + Status string `json:"status" gorm:"type:varchar(45)"` } // set User's table name to be `profiles` @@ -59,7 +61,7 @@ func GetGender(genderString string) string { //通过一个字符串获取角色 func GetRole(roleString string) string { - if roleString == USER_ROLE_USER || roleString == USER_ROLE_ADMINISTRATOR { + if roleString == USER_ROLE_GUEST || roleString == USER_ROLE_USER || roleString == USER_ROLE_ADMINISTRATOR { return roleString } else { return USER_ROLE_USER diff --git a/code/support/tank_application.go b/code/support/tank_application.go index 520dedb..841cbb3 100644 --- a/code/support/tank_application.go +++ b/code/support/tank_application.go @@ -188,7 +188,7 @@ func (this *TankApplication) HandleMirror() { } response, err := http.PostForm(urlString, params) - util.PanicError(err) + core.PanicError(err) bodyBytes, err := ioutil.ReadAll(response.Body) @@ -235,7 +235,7 @@ func (this *TankApplication) HandleCrawl() { } response, err := http.PostForm(urlString, params) - util.PanicError(err) + core.PanicError(err) bodyBytes, err := ioutil.ReadAll(response.Body) diff --git a/code/support/tank_config.go b/code/support/tank_config.go index 7128b6e..32f6779 100644 --- a/code/support/tank_config.go +++ b/code/support/tank_config.go @@ -145,7 +145,7 @@ func (this *TankConfig) ReadFromConfigFile() { if this.item.MatterPath == "" { this.matterPath = util.GetHomePath() + "/matter" } else { - this.matterPath = this.item.MatterPath + this.matterPath = util.UniformPath(this.item.MatterPath) } util.MakeDirAll(this.matterPath) @@ -179,6 +179,7 @@ func (this *TankConfig) MysqlUrl() string { //文件存放路径 func (this *TankConfig) MatterPath() string { + return this.matterPath } @@ -209,11 +210,11 @@ func (this *TankConfig) FinishInstall(mysqlPort int, mysqlHost string, mysqlSche //写入到配置文件中(不能使用os.O_APPEND 否则会追加) filePath := util.GetConfPath() + "/tank.json" f, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE, 0777) - util.PanicError(err) + core.PanicError(err) _, err = f.Write(jsonStr) - util.PanicError(err) + core.PanicError(err) err = f.Close() - util.PanicError(err) + core.PanicError(err) this.ReadFromConfigFile() diff --git a/code/support/tank_logger.go b/code/support/tank_logger.go index 48e74d6..2d1213f 100644 --- a/code/support/tank_logger.go +++ b/code/support/tank_logger.go @@ -2,6 +2,7 @@ package support import ( "fmt" + "github.com/eyebluecn/tank/code/core" "github.com/eyebluecn/tank/code/tool/util" "github.com/robfig/cron" "log" @@ -30,7 +31,7 @@ func (this *TankLogger) Init() { expression := "0 0 0 * * ?" cronJob := cron.New() err := cronJob.AddFunc(expression, this.maintain) - util.PanicError(err) + core.PanicError(err) cronJob.Start() this.Info("[cron job] 每日00:00维护日志") diff --git a/code/support/tank_router.go b/code/support/tank_router.go index 69be22f..d03bcfb 100644 --- a/code/support/tank_router.go +++ b/code/support/tank_router.go @@ -89,7 +89,7 @@ func (this *TankRouter) GlobalPanicHandler(writer http.ResponseWriter, request * } } //全局方便的异常拦截 - if strings.HasSuffix(file, "util/util_framework.go") { + if strings.HasSuffix(file, "core/handler.go") { _, file, line, ok = runtime.Caller(4) if !ok { file = "???" @@ -133,7 +133,7 @@ func (this *TankRouter) GlobalPanicHandler(writer http.ResponseWriter, request * } //错误情况记录。 - go util.RunWithRecovery(func() { + go core.RunWithRecovery(func() { this.footprintService.Trace(writer, request, time.Now().Sub(startTime), false) }) } @@ -181,7 +181,7 @@ func (this *TankRouter) ServeHTTP(writer http.ResponseWriter, request *http.Requ } //正常的访问记录会落到这里。 - go util.RunWithRecovery(func() { + go core.RunWithRecovery(func() { this.footprintService.Trace(writer, request, time.Now().Sub(startTime), true) }) diff --git a/code/test/main_test.go b/code/test/main_test.go index b0bdc36..d282381 100644 --- a/code/test/main_test.go +++ b/code/test/main_test.go @@ -30,7 +30,7 @@ func TestCron(t *testing.T) { panic("intent to panic.") } }) - util.PanicError(err) + core.PanicError(err) c.Start() diff --git a/code/tool/util/util_file.go b/code/tool/util/util_file.go index 10a48eb..78bb57c 100644 --- a/code/tool/util/util_file.go +++ b/code/tool/util/util_file.go @@ -67,7 +67,7 @@ func GetHomePath() string { exPath = GetDevHomePath() + "/tmp" } - return exPath + return UniformPath(exPath) } //获取前端静态资源的位置。如果你在开发模式下,可以将这里直接返回tank/build下面的html路径。 @@ -254,3 +254,10 @@ func CopyFile(srcPath string, destPath string) (nBytes int64) { nBytes, err = io.Copy(destFile, srcFile) return nBytes } + +//路径归一化处理,把\\替换成/ +func UniformPath(path string) string { + + return strings.Replace(path, "\\", "/", -1) + +} diff --git a/code/tool/util/util_zip.go b/code/tool/util/util_zip.go index fc3bc8c..2877462 100644 --- a/code/tool/util/util_zip.go +++ b/code/tool/util/util_zip.go @@ -11,10 +11,10 @@ import ( ) //将srcPath压缩到destPath。 -func Zip(srcPath string, destPath string) { +func Zip(srcPath string, destPath string) error { //统一处理\\成/ - srcPath = strings.Replace(srcPath, "\\", "/", -1) + srcPath = UniformPath(srcPath) if PathExists(destPath) { panic(result.BadRequest("%s 已经存在了", destPath)) @@ -22,10 +22,14 @@ func Zip(srcPath string, destPath string) { // 创建准备写入的文件 fileWriter, err := os.Create(destPath) - PanicError(err) + if err != nil { + return err + } defer func() { err := fileWriter.Close() - PanicError(err) + if err != nil { + panic(err) + } }() // 通过 fileWriter 来创建 zip.Write @@ -46,7 +50,7 @@ func Zip(srcPath string, destPath string) { } //统一处理\\成/ - path = strings.Replace(path, "\\", "/", -1) + path = UniformPath(path) // 通过文件信息,创建 zip 的文件信息 fileHeader, err := zip.FileInfoHeader(fileInfo) @@ -78,7 +82,9 @@ func Zip(srcPath string, destPath string) { fileToBeZip, err := os.Open(path) defer func() { err = fileToBeZip.Close() - PanicError(err) + if err != nil { + panic(err) + } }() if err != nil { return @@ -92,5 +98,5 @@ func Zip(srcPath string, destPath string) { return nil }) - PanicError(err) + return err }