From 5625149766769554f3172f50ba6da1fd083c5d15 Mon Sep 17 00:00:00 2001 From: zicla Date: Sat, 4 May 2019 23:36:05 +0800 Subject: [PATCH] Finish half translation work. --- code/core/application.go | 5 +- code/core/bean.go | 10 +- code/core/config.go | 16 +- code/core/context.go | 11 +- code/core/controller.go | 4 +- code/core/global.go | 11 +- code/core/handler.go | 8 +- code/core/logger.go | 4 +- code/rest/alien_controller.go | 220 +++++++++++----------------- code/rest/alien_service.go | 35 ++--- code/rest/base_bean.go | 18 +-- code/rest/base_controller.go | 39 ++--- code/rest/base_dao.go | 8 +- code/rest/base_model.go | 23 +-- code/rest/bridge_dao.go | 61 ++++---- code/rest/bridge_model.go | 3 +- code/rest/bridge_service.go | 3 - code/rest/dashboard_controller.go | 15 +- code/rest/dashboard_dao.go | 19 +-- code/rest/dashboard_model.go | 24 +-- code/rest/dashboard_service.go | 53 ++----- code/rest/dav_controller.go | 41 +++--- code/rest/dav_model.go | 10 +- code/rest/dav_service.go | 128 +++++++--------- code/rest/download_token_dao.go | 36 +++-- code/rest/footprint_controller.go | 3 - code/rest/footprint_dao.go | 71 +++++---- code/rest/footprint_model.go | 2 +- code/rest/footprint_service.go | 22 +-- code/rest/image_cache_controller.go | 22 +-- code/rest/image_cache_dao.go | 74 +++++----- code/rest/image_cache_model.go | 4 +- code/rest/image_cache_service.go | 82 ++++------- code/rest/install_controller.go | 79 +++------- code/rest/install_model.go | 2 +- code/rest/matter_controller.go | 69 +++------ code/rest/matter_dao.go | 98 +++++-------- code/rest/matter_model.go | 4 +- code/rest/matter_service.go | 16 -- code/rest/preference_controller.go | 4 - code/rest/preference_dao.go | 6 +- code/rest/preference_service.go | 6 +- code/rest/session_dao.go | 34 +++-- code/rest/session_service.go | 6 +- code/rest/share_controller.go | 9 +- code/rest/share_dao.go | 37 +++-- code/rest/share_service.go | 2 - code/rest/upload_token_dao.go | 26 +++- code/rest/user_controller.go | 3 - code/rest/user_dao.go | 36 ++--- code/rest/user_service.go | 2 - code/tool/result/web_result.go | 39 ++--- 52 files changed, 613 insertions(+), 950 deletions(-) diff --git a/code/core/application.go b/code/core/application.go index 56899fa..767588c 100644 --- a/code/core/application.go +++ b/code/core/application.go @@ -1,9 +1,6 @@ package core -/** - * 从命令行输入的相关信息 - */ type Application interface { - //启动整个应用 + //start the application Start() } diff --git a/code/core/bean.go b/code/core/bean.go index a34301d..576b24e 100644 --- a/code/core/bean.go +++ b/code/core/bean.go @@ -1,15 +1,15 @@ package core /** - * 系统中的Bean接口,即系统中单例模式 + * bean interface means singleton in application */ type Bean interface { - //初始化方法 + //init the bean when constructing Init() - //系统清理方法 + //cleanup the bean when system's cleanup Cleanup() - //所有配置都加载完成后调用的方法,包括数据库加载完毕 + //when everything(including db's connection) loaded, this method will be invoked. Bootstrap() - //快速的Panic方法 + //shortcut for panic check. PanicError(err error) } diff --git a/code/core/config.go b/code/core/config.go index f25d397..7c30225 100644 --- a/code/core/config.go +++ b/code/core/config.go @@ -1,33 +1,27 @@ package core const ( - //用户身份的cookie字段名 + //authentication key of cookie COOKIE_AUTH_KEY = "_ak" - //使用用户名密码给接口授权key USERNAME_KEY = "_username" PASSWORD_KEY = "_password" - //默认端口号 DEFAULT_SERVER_PORT = 6010 - //数据库表前缀 tank30_表示当前应用版本是tank:3.0.x版,数据库结构发生变化必然是中型升级 + //db table's prefix. tank30_ means current version is tank:3.0.x TABLE_PREFIX = "tank30_" - //当前版本 VERSION = "3.0.0.beta1" ) type Config interface { - //是否已经安装 Installed() bool - //启动端口 ServerPort() int - //获取mysql链接 + //get the mysql url. eg. tank:tank123@tcp(127.0.0.1:3306)/tank?charset=utf8&parseTime=True&loc=Local MysqlUrl() string - - //文件存放路径 + //files storage location. MatterPath() string - //完成安装过程,主要是要将配置写入到文件中 + //when installed by user. Write configs to tank.json FinishInstall(mysqlPort int, mysqlHost string, mysqlSchema string, mysqlUsername string, mysqlPassword string) } diff --git a/code/core/context.go b/code/core/context.go index 19721ff..9a7a2c8 100644 --- a/code/core/context.go +++ b/code/core/context.go @@ -7,24 +7,21 @@ import ( ) type Context interface { - //具备响应http请求的能力 http.Handler - //获取数据库链接 + //get the gorm.DB. all the db connection will use this GetDB() *gorm.DB - //获取一个Bean GetBean(bean Bean) Bean - //获取全局的Session缓存 + //get the global session cache GetSessionCache() *cache.Table - //获取全局的ControllerMap GetControllerMap() map[string]Controller - //系统安装成功 + //when application installed. this method will invoke every bean's Bootstrap method InstallOk() - //清空系统 + //this method will invoke every bean's Cleanup method Cleanup() } diff --git a/code/core/controller.go b/code/core/controller.go index 6cb875b..bf683e7 100644 --- a/code/core/controller.go +++ b/code/core/controller.go @@ -4,8 +4,8 @@ import "net/http" type Controller interface { Bean - //注册自己固定的路由。 + //register self's fixed routes RegisterRoutes() map[string]func(writer http.ResponseWriter, request *http.Request) - //处理一些特殊的路由。 + //handle some special routes, eg. params in the url. HandleRoutes(writer http.ResponseWriter, request *http.Request) (func(writer http.ResponseWriter, request *http.Request), bool) } diff --git a/code/core/global.go b/code/core/global.go index 51649a9..ddbbab1 100644 --- a/code/core/global.go +++ b/code/core/global.go @@ -1,16 +1,15 @@ package core -//该文件中记录的是应用系统中全局变量。主要有日志LOGGER和上下文CONTEXT +//the global variables in the application. -//命令行输入等相关信息 +//application var APPLICATION Application -//日志系统必须高保 -//全局唯一的日志对象(在main函数中初始化) +//logger var LOGGER Logger -//全局唯一配置 +//config var CONFIG Config -//全局唯一的上下文(在main函数中初始化) +//context var CONTEXT Context diff --git a/code/core/handler.go b/code/core/handler.go index 70f50bf..3dc2127 100644 --- a/code/core/handler.go +++ b/code/core/handler.go @@ -1,18 +1,18 @@ package core -//带有panic恢复的方法 +//run a method with panic recovery. func RunWithRecovery(f func()) { defer func() { if err := recover(); err != nil { - LOGGER.Error("异步任务错误: %v", err) + LOGGER.Error("error in async method: %v", err) } }() - //执行函数 + //execute the method f() } -//处理错误的统一方法 可以省去if err!=nil 这段代码 +//shortcut for panic check func PanicError(err error) { if err != nil { panic(err) diff --git a/code/core/logger.go b/code/core/logger.go index d59b516..972f66a 100644 --- a/code/core/logger.go +++ b/code/core/logger.go @@ -2,10 +2,10 @@ package core type Logger interface { - //处理日志的统一方法。 + //basic log method Log(prefix string, format string, v ...interface{}) - //不同级别的日志处理 + //log with different level. Debug(format string, v ...interface{}) Info(format string, v ...interface{}) Warn(format string, v ...interface{}) diff --git a/code/rest/alien_controller.go b/code/rest/alien_controller.go index d1c1c2a..8b4e310 100644 --- a/code/rest/alien_controller.go +++ b/code/rest/alien_controller.go @@ -1,7 +1,6 @@ package rest import ( - "fmt" "github.com/eyebluecn/tank/code/core" "github.com/eyebluecn/tank/code/tool/i18n" "github.com/eyebluecn/tank/code/tool/result" @@ -24,11 +23,9 @@ type AlienController struct { shareService *ShareService } -//初始化方法 func (this *AlienController) Init() { this.BaseController.Init() - //手动装填本实例的Bean. b := core.CONTEXT.GetBean(this.uploadTokenDao) if c, ok := b.(*UploadTokenDao); ok { this.uploadTokenDao = c @@ -70,28 +67,26 @@ func (this *AlienController) Init() { } } -//注册自己的路由。 func (this *AlienController) RegisterRoutes() map[string]func(writer http.ResponseWriter, request *http.Request) { routeMap := make(map[string]func(writer http.ResponseWriter, request *http.Request)) - //每个Controller需要主动注册自己的路由。 - routeMap["/api/alien/fetch/upload/token"] = this.Wrap(this.FetchUploadToken, USER_ROLE_GUEST) - routeMap["/api/alien/fetch/download/token"] = this.Wrap(this.FetchDownloadToken, USER_ROLE_GUEST) - routeMap["/api/alien/confirm"] = this.Wrap(this.Confirm, USER_ROLE_GUEST) + routeMap["/api/alien/fetch/upload/token"] = this.Wrap(this.FetchUploadToken, USER_ROLE_USER) + routeMap["/api/alien/fetch/download/token"] = this.Wrap(this.FetchDownloadToken, USER_ROLE_USER) + routeMap["/api/alien/confirm"] = this.Wrap(this.Confirm, USER_ROLE_USER) routeMap["/api/alien/upload"] = this.Wrap(this.Upload, USER_ROLE_GUEST) routeMap["/api/alien/crawl/token"] = this.Wrap(this.CrawlToken, USER_ROLE_GUEST) - routeMap["/api/alien/crawl/direct"] = this.Wrap(this.CrawlDirect, USER_ROLE_GUEST) + routeMap["/api/alien/crawl/direct"] = this.Wrap(this.CrawlDirect, USER_ROLE_USER) return routeMap } -//处理一些特殊的接口,比如参数包含在路径中,一般情况下,controller不将参数放在url路径中 +//handle some special routes, eg. params in the url. func (this *AlienController) HandleRoutes(writer http.ResponseWriter, request *http.Request) (func(writer http.ResponseWriter, request *http.Request), bool) { path := request.URL.Path - //匹配 /api/alien/preview/{uuid}/{filename} (响应头不包含 content-disposition) + //match /api/alien/preview/{uuid}/{filename} (response header not contain content-disposition) reg := regexp.MustCompile(`^/api/alien/preview/([^/]+)/([^/]+)$`) strs := reg.FindStringSubmatch(path) if len(strs) == 3 { @@ -101,7 +96,7 @@ func (this *AlienController) HandleRoutes(writer http.ResponseWriter, request *h return f, true } - //匹配 /api/alien/download/{uuid}/{filename} (响应头包含 content-disposition) + //match /api/alien/download/{uuid}/{filename} (response header contain content-disposition) reg = regexp.MustCompile(`^/api/alien/download/([^/]+)/([^/]+)$`) strs = reg.FindStringSubmatch(path) if len(strs) == 3 { @@ -114,76 +109,60 @@ func (this *AlienController) HandleRoutes(writer http.ResponseWriter, request *h return nil, false } -//系统中的用户x要获取一个UploadToken,用于提供给x信任的用户上传文件。 +//fetch a upload token for guest. Guest can upload file with this token. func (this *AlienController) FetchUploadToken(writer http.ResponseWriter, request *http.Request) *result.WebResult { - //文件名。 filename := request.FormValue("filename") + expireTimeStr := request.FormValue("expireTime") + privacyStr := request.FormValue("privacy") + sizeStr := request.FormValue("size") + //store dir path + dirPath := request.FormValue("dirPath") + if filename == "" { - panic("文件名必填") + panic(result.BadRequest("filename cannot be null")) } else if m, _ := regexp.MatchString(MATTER_NAME_PATTERN, filename); m { panic(result.BadRequestI18n(request, i18n.MatterNameContainSpecialChars)) } - //什么时间后过期,默认24h - expireStr := request.FormValue("expire") - expire := 24 * 60 * 60 - if expireStr != "" { - var err error - expire, err = strconv.Atoi(expireStr) - if err != nil { - panic(`过期时间不符合规范`) - } - if expire < 1 { - panic(`过期时间不符合规范`) - } - - } - - //文件公有或私有 - privacyStr := request.FormValue("privacy") - var privacy bool - if privacyStr == "" { - panic(`文件公有性必填`) + var expireTime time.Time + if expireTimeStr == "" { + panic(result.BadRequest("time format error")) } else { - if privacyStr == TRUE { - privacy = true - } else if privacyStr == "false" { - privacy = false - } else { - panic(`文件公有性不符合规范`) - } + expireTime = util.ConvertDateTimeStringToTime(expireTimeStr) + } + if expireTime.Before(time.Now()) { + panic(result.BadRequest("expire time cannot before now")) + } + + var privacy = false + if privacyStr == TRUE { + privacy = true } - //文件大小 - sizeStr := request.FormValue("size") var size int64 if sizeStr == "" { - panic(`文件大小必填`) + panic(result.BadRequest("file size cannot be null")) } else { var err error size, err = strconv.ParseInt(sizeStr, 10, 64) if err != nil { - panic(`文件大小不符合规范`) + panic(result.BadRequest("file size error")) } if size < 1 { - panic(`文件大小不符合规范`) + panic(result.BadRequest("file size error")) } } - //文件夹路径,以 / 开头。 - dir := request.FormValue("dir") - user := this.checkUser(request) - dirMatter := this.matterService.CreateDirectories(request, user, dir) + dirMatter := this.matterService.CreateDirectories(request, user, dirPath) - mm, _ := time.ParseDuration(fmt.Sprintf("%ds", expire)) uploadToken := &UploadToken{ UserUuid: user.Uuid, FolderUuid: dirMatter.Uuid, MatterUuid: "", - ExpireTime: time.Now().Add(mm), + ExpireTime: expireTime, Filename: filename, Privacy: privacy, Size: size, @@ -196,51 +175,34 @@ func (this *AlienController) FetchUploadToken(writer http.ResponseWriter, reques } -//系统中的用户x 拿着某个文件的uuid来确认是否其信任的用户已经上传好了。 +//user confirm a file whether uploaded successfully. func (this *AlienController) Confirm(writer http.ResponseWriter, request *http.Request) *result.WebResult { matterUuid := request.FormValue("matterUuid") if matterUuid == "" { - panic("matterUuid必填") + panic(result.BadRequest("matterUuid cannot be null")) } user := this.checkUser(request) matter := this.matterDao.CheckByUuid(matterUuid) if matter.UserUuid != user.Uuid { - panic("文件不属于你") + panic(result.BadRequest("matter not belong to you")) } return this.Success(matter) } -//系统中的用户x 信任的用户上传文件。这个接口需要支持跨域。 +//a guest upload a file with a upload token. func (this *AlienController) Upload(writer http.ResponseWriter, request *http.Request) *result.WebResult { - //允许跨域请求。 + //allow cors. this.allowCORS(writer) if request.Method == "OPTIONS" { - return this.Success("OK") + //nil means empty response body. + return nil } uploadTokenUuid := request.FormValue("uploadTokenUuid") - if uploadTokenUuid == "" { - panic("uploadTokenUuid必填") - } - - uploadToken := this.uploadTokenDao.FindByUuid(uploadTokenUuid) - if uploadToken == nil { - panic("uploadTokenUuid无效") - } - - if uploadToken.ExpireTime.Before(time.Now()) { - panic("uploadToken已失效") - } - - user := this.userDao.CheckByUuid(uploadToken.UserUuid) - - err := request.ParseMultipartForm(32 << 20) - this.PanicError(err) - file, handler, err := request.FormFile("file") this.PanicError(err) defer func() { @@ -248,47 +210,61 @@ func (this *AlienController) Upload(writer http.ResponseWriter, request *http.Re this.PanicError(e) }() + if uploadTokenUuid == "" { + panic(result.BadRequest("uploadTokenUuid cannot be null")) + } + + uploadToken := this.uploadTokenDao.CheckByUuid(uploadTokenUuid) + + if uploadToken.ExpireTime.Before(time.Now()) { + panic(result.BadRequest("uploadToken has expired")) + } + + user := this.userDao.CheckByUuid(uploadToken.UserUuid) + + err = request.ParseMultipartForm(32 << 20) + this.PanicError(err) + if handler.Filename != uploadToken.Filename { - panic("文件名称不正确") + panic(result.BadRequest("filename doesn't the one in uploadToken")) } if handler.Size != uploadToken.Size { - panic("文件大小不正确") + panic(result.BadRequest("file size doesn't the one in uploadToken")) } dirMatter := this.matterDao.CheckWithRootByUuid(uploadToken.FolderUuid, user) - matter := this.matterService.AtomicUpload(request, file, user, dirMatter, uploadToken.Filename, uploadToken.Privacy) + matter := this.matterService.Upload(request, file, user, dirMatter, uploadToken.Filename, uploadToken.Privacy) - //更新这个uploadToken的信息. + //expire the upload token. uploadToken.ExpireTime = time.Now() this.uploadTokenDao.Save(uploadToken) return this.Success(matter) } -//给一个指定的url,从该url中去拉取文件回来。此处采用uploadToken的模式。 +//crawl a url with uploadToken. guest can visit this method. func (this *AlienController) CrawlToken(writer http.ResponseWriter, request *http.Request) *result.WebResult { - //允许跨域请求。 + + //allow cors. this.allowCORS(writer) if request.Method == "OPTIONS" { - return this.Success("OK") + //nil means empty response body. + return nil } uploadTokenUuid := request.FormValue("uploadTokenUuid") url := request.FormValue("url") if uploadTokenUuid == "" { - panic("uploadTokenUuid必填") + panic(result.BadRequest("uploadTokenUuid cannot be null")) } - uploadToken := this.uploadTokenDao.FindByUuid(uploadTokenUuid) - if uploadToken == nil { - panic("uploadTokenUuid无效") - } + uploadToken := this.uploadTokenDao.CheckByUuid(uploadTokenUuid) if uploadToken.ExpireTime.Before(time.Now()) { - panic("uploadToken已失效") + panic(result.BadRequest("uploadToken has expired")) } user := this.userDao.CheckByUuid(uploadToken.UserUuid) @@ -297,89 +273,71 @@ func (this *AlienController) CrawlToken(writer http.ResponseWriter, request *htt matter := this.matterService.AtomicCrawl(request, url, uploadToken.Filename, user, dirMatter, uploadToken.Privacy) - //更新这个uploadToken的信息. + //expire the upload token. uploadToken.ExpireTime = time.Now() this.uploadTokenDao.Save(uploadToken) return this.Success(matter) } -//通过一个url直接上传,无需借助uploadToken. +//crawl a url directly. only user can visit this method. func (this *AlienController) CrawlDirect(writer http.ResponseWriter, request *http.Request) *result.WebResult { - //文件名。 filename := request.FormValue("filename") - //文件公有或私有 privacyStr := request.FormValue("privacy") - //文件夹路径,以 / 开头。 - dir := request.FormValue("dir") + dirPath := request.FormValue("dirPath") url := request.FormValue("url") if filename == "" { - panic("文件名必填") + panic(result.BadRequest("filename cannot be null.")) } else if m, _ := regexp.MatchString(MATTER_NAME_PATTERN, filename); m { panic(result.BadRequestI18n(request, i18n.MatterNameContainSpecialChars)) } var privacy bool - if privacyStr == "" { - panic(`文件公有性必填`) - } else { - if privacyStr == TRUE { - privacy = true - } else if privacyStr == FALSE { - privacy = false - } else { - panic(`文件公有性不符合规范`) - } + if privacyStr == TRUE { + privacy = true } user := this.checkUser(request) - dirMatter := this.matterService.CreateDirectories(request, user, dir) + dirMatter := this.matterService.CreateDirectories(request, user, dirPath) matter := this.matterService.AtomicCrawl(request, url, filename, user, dirMatter, privacy) return this.Success(matter) } -//系统中的用户x要获取一个DownloadToken,用于提供给x信任的用户下载文件。 +//fetch a download token for guest. Guest can download file with this token. func (this *AlienController) FetchDownloadToken(writer http.ResponseWriter, request *http.Request) *result.WebResult { matterUuid := request.FormValue("matterUuid") + expireTimeStr := request.FormValue("expireTime") + if matterUuid == "" { - panic("matterUuid必填") + panic(result.BadRequest("matterUuid cannot be null.")) } user := this.checkUser(request) matter := this.matterDao.CheckByUuid(matterUuid) if matter.UserUuid != user.Uuid { - panic("文件不属于你") - } - if matter.Dir { - panic("不支持下载文件夹") + panic(result.BadRequest("matter not belong to you")) } - //什么时间后过期,默认24h - expireStr := request.FormValue("expire") - expire := 24 * 60 * 60 - if expireStr != "" { - var err error - expire, err = strconv.Atoi(expireStr) - if err != nil { - panic(`过期时间不符合规范`) - } - if expire < 1 { - panic(`过期时间不符合规范`) - } - + var expireTime time.Time + if expireTimeStr == "" { + panic(result.BadRequest("time format error")) + } else { + expireTime = util.ConvertDateTimeStringToTime(expireTimeStr) + } + if expireTime.Before(time.Now()) { + panic(result.BadRequest("expire time cannot before now")) } - mm, _ := time.ParseDuration(fmt.Sprintf("%ds", expire)) downloadToken := &DownloadToken{ UserUuid: user.Uuid, MatterUuid: matterUuid, - ExpireTime: time.Now().Add(mm), + ExpireTime: expireTime, Ip: util.GetIpAddress(request), } @@ -389,13 +347,13 @@ func (this *AlienController) FetchDownloadToken(writer http.ResponseWriter, requ } -//预览一个文件。既可以使用登录的方式,也可以使用授权的方式 +//preview a file. func (this *AlienController) Preview(writer http.ResponseWriter, request *http.Request, uuid string, filename string) { this.alienService.PreviewOrDownload(writer, request, uuid, filename, false) } -//下载一个文件。既可以使用登录的方式,也可以使用授权的方式 +//download a file. func (this *AlienController) Download(writer http.ResponseWriter, request *http.Request, uuid string, filename string) { this.alienService.PreviewOrDownload(writer, request, uuid, filename, true) diff --git a/code/rest/alien_service.go b/code/rest/alien_service.go index 16cd0db..a989af3 100644 --- a/code/rest/alien_service.go +++ b/code/rest/alien_service.go @@ -21,11 +21,9 @@ type AlienService struct { imageCacheService *ImageCacheService } -//初始化方法 func (this *AlienService) Init() { this.BaseBean.Init() - //手动装填本实例的Bean. 这里必须要用中间变量方可。 b := core.CONTEXT.GetBean(this.matterDao) if b, ok := b.(*MatterDao); ok { this.matterDao = b @@ -67,7 +65,6 @@ func (this *AlienService) Init() { } } -//预览或者下载的统一处理. func (this *AlienService) PreviewOrDownload( writer http.ResponseWriter, request *http.Request, @@ -78,23 +75,22 @@ func (this *AlienService) PreviewOrDownload( matter := this.matterDao.CheckByUuid(uuid) if matter.Name != filename { - panic("文件信息错误") + panic(result.BadRequest("filename in url incorrect")) } - //验证用户的权限问题。 - //文件如果是私有的才需要权限 + //only private file need auth. if matter.Privacy { - //1.如果带有downloadTokenUuid那么就按照token的信息去获取。 + //1.use downloadToken to auth. downloadTokenUuid := request.FormValue("downloadTokenUuid") if downloadTokenUuid != "" { downloadToken := this.downloadTokenDao.CheckByUuid(downloadTokenUuid) if downloadToken.ExpireTime.Before(time.Now()) { - panic("downloadToken已失效") + panic(result.BadRequest("downloadToken has expired")) } if downloadToken.MatterUuid != uuid { - panic("token和文件信息不一致") + panic(result.BadRequest("token and file info not match")) } tokenUser := this.userDao.CheckByUuid(downloadToken.UserUuid) @@ -102,16 +98,15 @@ func (this *AlienService) PreviewOrDownload( panic(result.UNAUTHORIZED) } - //下载之后立即过期掉。如果是分块下载的,必须以最终获取到完整的数据为准。 + //TODO: expire the download token. If download by chunk, do this later. downloadToken.ExpireTime = time.Now() this.downloadTokenDao.Save(downloadToken) } else { - //判断文件的所属人是否正确 operator := this.findUser(request) - //可以使用分享码的形式授权。 + //use share code to auth. shareUuid := request.FormValue("shareUuid") shareCode := request.FormValue("shareCode") shareRootUuid := request.FormValue("shareRootUuid") @@ -121,27 +116,25 @@ func (this *AlienService) PreviewOrDownload( } } - //文件夹下载 + //download directory if matter.Dir { - this.logger.Info("准备下载文件夹 %s", matter.Name) - - //目标地点 this.matterService.DownloadZip(writer, request, []*Matter{matter}) } else { - //对图片处理。 + //handle the image operation. needProcess, imageResizeM, imageResizeW, imageResizeH := this.imageCacheService.ResizeParams(request) if needProcess { - //如果是图片,那么能用缓存就用缓存 - imageCache := this.imageCacheDao.FindByMatterUuidAndMode(matter.Uuid, fmt.Sprintf("%s_%d_%d", imageResizeM, imageResizeW, imageResizeH)) + //if image, try to use cache. + mode := fmt.Sprintf("%s_%d_%d", imageResizeM, imageResizeW, imageResizeH) + imageCache := this.imageCacheDao.FindByMatterUuidAndMode(matter.Uuid, mode) if imageCache == nil { imageCache = this.imageCacheService.cacheImage(writer, request, matter) } - //直接使用缓存中的信息 + //download the cache image file. this.matterService.DownloadFile(writer, request, GetUserCacheRootDir(imageCache.Username)+imageCache.Path, imageCache.Name, withContentDisposition) } else { @@ -150,7 +143,7 @@ func (this *AlienService) PreviewOrDownload( } - //文件下载次数加一,为了加快访问速度,异步进行 + //async increase the download times. go core.RunWithRecovery(func() { this.matterDao.TimesIncrement(uuid) }) diff --git a/code/rest/base_bean.go b/code/rest/base_bean.go index e493663..90224e1 100644 --- a/code/rest/base_bean.go +++ b/code/rest/base_bean.go @@ -19,50 +19,48 @@ func (this *BaseBean) Bootstrap() { } -//系统大清理,一般时产品即将上线时,清除脏数据,只执行一次。 +//clean up the application. func (this *BaseBean) Cleanup() { } -//处理错误的统一方法 可以省去if err!=nil 这段代码 +//shortcut for panic check. func (this *BaseBean) PanicError(err error) { core.PanicError(err) } -//能找到一个user就找到一个 +//find the current user from request. func (this *BaseBean) findUser(request *http.Request) *User { - //验证用户是否已经登录。 - //登录身份有效期以数据库中记录的为准 + //try to find from SessionCache. sessionId := util.GetSessionUuidFromRequest(request, core.COOKIE_AUTH_KEY) if sessionId == "" { return nil } - //去缓存中捞取看看 cacheItem, err := core.CONTEXT.GetSessionCache().Value(sessionId) if err != nil { - this.logger.Warn("获取缓存时出错了" + err.Error()) + this.logger.Warn("error while get from session cache. sessionId = %s, error = %v", sessionId, err) return nil } if cacheItem == nil || cacheItem.Data() == nil { - this.logger.Warn("cache item中已经不存在了 ") + this.logger.Warn("cache item doesn't exist with sessionId = %s", sessionId) return nil } if value, ok := cacheItem.Data().(*User); ok { return value } else { - this.logger.Error("cache item中的类型不是*User ") + this.logger.Error("cache item not store the *User") } return nil } -//获取当前登录的用户,找不到就返回登录错误 +//find current error. If not found, panic the LOGIN error. func (this *BaseBean) checkUser(request *http.Request) *User { if this.findUser(request) == nil { panic(result.LOGIN) diff --git a/code/rest/base_controller.go b/code/rest/base_controller.go index 2c1e818..c586cfd 100644 --- a/code/rest/base_controller.go +++ b/code/rest/base_controller.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/eyebluecn/tank/code/core" "github.com/eyebluecn/tank/code/tool/result" + "github.com/eyebluecn/tank/code/tool/util" "github.com/json-iterator/go" "go/types" "net/http" @@ -19,7 +20,6 @@ func (this *BaseController) Init() { this.BaseBean.Init() - //手动装填本实例的Bean. b := core.CONTEXT.GetBean(this.userDao) if b, ok := b.(*UserDao); ok { this.userDao = b @@ -32,32 +32,29 @@ func (this *BaseController) Init() { } -//注册自己的路由。 func (this *BaseController) RegisterRoutes() map[string]func(writer http.ResponseWriter, request *http.Request) { - //每个Controller需要主动注册自己的路由。 + return make(map[string]func(writer http.ResponseWriter, request *http.Request)) } -//处理一些特殊的接口,比如参数包含在路径中,一般情况下,controller不将参数放在url路径中 +//handle some special routes, eg. params in the url. func (this *BaseController) HandleRoutes(writer http.ResponseWriter, request *http.Request) (func(writer http.ResponseWriter, request *http.Request), bool) { return nil, false } -//需要进行登录验证的wrap包装 +//wrap the handle method. func (this *BaseController) Wrap(f func(writer http.ResponseWriter, request *http.Request) *result.WebResult, qualifiedRole string) func(w http.ResponseWriter, r *http.Request) { return func(writer http.ResponseWriter, request *http.Request) { - //writer和request赋值给自己。 - var webResult *result.WebResult = nil - //只有游客接口不需要登录 + //if the api not annotated with GUEST. login is required. if qualifiedRole != USER_ROLE_GUEST { user := this.checkUser(request) if user.Status == USER_STATUS_DISABLED { - //判断用户是否被禁用。 + //check user's status webResult = result.ConstWebResult(result.USER_DISABLED) } else { if qualifiedRole == USER_ROLE_ADMINISTRATOR && user.Role != USER_ROLE_ADMINISTRATOR { @@ -71,12 +68,11 @@ func (this *BaseController) Wrap(f func(writer http.ResponseWriter, request *htt webResult = f(writer, request) } - //输出的是json格式 + //if webResult not nil. response a json. if webResult is nil, return empty body or binary content. if webResult != nil { - //返回的内容申明是json,utf-8 + writer.Header().Set("Content-Type", "application/json;charset=UTF-8") - //用json的方式输出返回值。 b, err := jsoniter.ConfigCompatibleWithStandardLibrary.Marshal(webResult) this.PanicError(err) @@ -85,36 +81,31 @@ func (this *BaseController) Wrap(f func(writer http.ResponseWriter, request *htt _, err = fmt.Fprintf(writer, string(b)) this.PanicError(err) - } else { - //输出的内容是二进制的。 - } } } -//返回成功的结果。支持放置三种类型 1.字符串 2. WebResult对象 3.空指针 4.任意类型 +//response a success result. 1.string 2. WebResult 3.nil pointer 4.any type func (this *BaseController) Success(data interface{}) *result.WebResult { var webResult *result.WebResult = nil if value, ok := data.(string); ok { - //返回一句普通的消息 + //a simple message webResult = &result.WebResult{Code: result.OK.Code, Msg: value} } else if value, ok := data.(*result.WebResult); ok { - //返回一个webResult对象 + //a webResult webResult = value } else if _, ok := data.(types.Nil); ok { - //返回一个空指针 + //nil pointer means OK. webResult = result.ConstWebResult(result.OK) } else { - //返回的类型不明确。 + //other type. webResult = &result.WebResult{Code: result.OK.Code, Data: data} } return webResult } -//允许跨域请求 +//allow cors. func (this *BaseController) allowCORS(writer http.ResponseWriter) { - writer.Header().Add("Access-Control-Allow-Origin", "*") - writer.Header().Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE") - writer.Header().Add("Access-Control-Max-Age", "3600") + util.AllowCORS(writer) } diff --git a/code/rest/base_dao.go b/code/rest/base_dao.go index 9c90e0d..d8434b3 100644 --- a/code/rest/base_dao.go +++ b/code/rest/base_dao.go @@ -1,12 +1,14 @@ package rest -import "github.com/eyebluecn/tank/code/tool/builder" +import ( + "github.com/eyebluecn/tank/code/tool/builder" +) type BaseDao struct { BaseBean } -//根据一个sortMap,获取到order字符串 +//get an order string by sortMap func (this *BaseDao) GetSortString(sortArray []builder.OrderPair) string { if sortArray == nil || len(sortArray) == 0 { @@ -14,7 +16,7 @@ func (this *BaseDao) GetSortString(sortArray []builder.OrderPair) string { } str := "" for _, pair := range sortArray { - if pair.Value == "DESC" || pair.Value == "ASC" { + if pair.Value == DIRECTION_DESC || pair.Value == DIRECTION_ASC { if str != "" { str = str + "," } diff --git a/code/rest/base_model.go b/code/rest/base_model.go index e5aa050..9af7ffd 100644 --- a/code/rest/base_model.go +++ b/code/rest/base_model.go @@ -1,9 +1,7 @@ package rest import ( - "github.com/eyebluecn/tank/code/core" "math" - "reflect" "time" ) @@ -16,11 +14,12 @@ const ( ) type IBase interface { - //返回其对应的数据库表名 + //name of db table TableName() string } -//Mysql 5.5只支持一个CURRENT_TIMESTAMP的默认值,因此时间的默认值都使用蓝眼云盘第一个发布版本时间 2018-01-01 00:00:00 +// Mysql 5.5 only support one CURRENT_TIMESTAMP +// so we use 2018-01-01 00:00:00 as default, which is the first release date of EyeblueTank type Base struct { Uuid string `json:"uuid" gorm:"type:char(36);primary_key;unique"` Sort int64 `json:"sort" gorm:"type:bigint(20) not null"` @@ -28,23 +27,11 @@ type Base struct { CreateTime time.Time `json:"createTime" gorm:"type:timestamp not null;default:'2018-01-01 00:00:00'"` } -//将 Struct 转换成map[string]interface{}类型 -func (this *Base) Map() map[string]interface{} { - t := reflect.TypeOf(this) - v := reflect.ValueOf(this) - - var data = make(map[string]interface{}) - for i := 0; i < t.NumField(); i++ { - data[t.Field(i).Name] = v.Field(i).Interface() - } - return data -} - func (this *Base) TableName() string { - return core.TABLE_PREFIX + "base" + panic("you should overwrite TableName()") } -//分页类 +//pager type Pager struct { Page int `json:"page"` PageSize int `json:"pageSize"` diff --git a/code/rest/bridge_dao.go b/code/rest/bridge_dao.go index 1c6aa2b..12758cb 100644 --- a/code/rest/bridge_dao.go +++ b/code/rest/bridge_dao.go @@ -14,43 +14,51 @@ type BridgeDao struct { BaseDao } -//按照Id查询文件 +//find by uuid. if not found return nil. func (this *BridgeDao) FindByUuid(uuid string) *Bridge { - // Read - var bridge Bridge - db := core.CONTEXT.GetDB().Where(&Bridge{Base: Base{Uuid: uuid}}).First(&bridge) + var bridge = &Bridge{} + db := core.CONTEXT.GetDB().Where("uuid = ?", uuid).First(bridge) if db.Error != nil { - return nil + if db.Error.Error() == result.DB_ERROR_NOT_FOUND { + return nil + } else { + panic(db.Error) + } } - return &bridge + return bridge + } -//按照Id查询文件 +//find by uuid. if not found panic NotFound error func (this *BridgeDao) CheckByUuid(uuid string) *Bridge { - // Read - var bridge Bridge - db := core.CONTEXT.GetDB().Where(&Bridge{Base: Base{Uuid: uuid}}).First(&bridge) - this.PanicError(db.Error) + entity := this.FindByUuid(uuid) + if entity == nil { + panic(result.NotFound("not found record with uuid = %s", uuid)) + } - return &bridge + return entity } -//按照shareUuid和matterUuid查找 +//find by shareUuid and matterUuid. if not found panic NotFound error. func (this *BridgeDao) CheckByShareUuidAndMatterUuid(shareUuid string, matterUuid string) *Bridge { - // Read - var bridge Bridge - db := core.CONTEXT.GetDB().Where("share_uuid = ? AND matter_uuid = ?", shareUuid, matterUuid).First(&bridge) - this.PanicError(db.Error) - - return &bridge + var bridge = &Bridge{} + db := core.CONTEXT.GetDB().Where("share_uuid = ? AND matter_uuid = ?", shareUuid, matterUuid).First(bridge) + if db.Error != nil { + if db.Error.Error() == result.DB_ERROR_NOT_FOUND { + panic(result.NotFound("not found record with shareUuid = %s and matterUuid = %s", shareUuid, matterUuid)) + } else { + panic(db.Error) + } + } + return bridge } -//按分页条件获取分页 +//get pager func (this *BridgeDao) Page(page int, pageSize int, shareUuid string, sortArray []builder.OrderPair) *Pager { var wp = &builder.WherePair{} @@ -74,7 +82,6 @@ func (this *BridgeDao) Page(page int, pageSize int, shareUuid string, sortArray return pager } -//创建 func (this *BridgeDao) Create(bridge *Bridge) *Bridge { timeUUID, _ := uuid.NewV4() @@ -88,7 +95,6 @@ func (this *BridgeDao) Create(bridge *Bridge) *Bridge { return bridge } -//修改一条记录 func (this *BridgeDao) Save(bridge *Bridge) *Bridge { bridge.UpdateTime = time.Now() @@ -98,39 +104,33 @@ func (this *BridgeDao) Save(bridge *Bridge) *Bridge { return bridge } -//删除一条记录 func (this *BridgeDao) Delete(bridge *Bridge) { db := core.CONTEXT.GetDB().Delete(&bridge) this.PanicError(db.Error) } -//删除一个matter对应的所有缓存 func (this *BridgeDao) DeleteByMatterUuid(matterUuid string) { var wp = &builder.WherePair{} wp = wp.And(&builder.WherePair{Query: "matter_uuid = ?", Args: []interface{}{matterUuid}}) - //删除文件记录 db := core.CONTEXT.GetDB().Where(wp.Query, wp.Args).Delete(Bridge{}) this.PanicError(db.Error) } -//删除一个share对应的所有缓存 func (this *BridgeDao) DeleteByShareUuid(shareUuid string) { var wp = &builder.WherePair{} wp = wp.And(&builder.WherePair{Query: "share_uuid = ?", Args: []interface{}{shareUuid}}) - //删除文件记录 db := core.CONTEXT.GetDB().Where(wp.Query, wp.Args).Delete(Bridge{}) this.PanicError(db.Error) } -//根据shareUuid获取关联的所有matter. -func (this *BridgeDao) ListByShareUuid(shareUuid string) []*Bridge { +func (this *BridgeDao) FindByShareUuid(shareUuid string) []*Bridge { if shareUuid == "" { panic(result.BadRequest("shareUuid cannot be nil")) @@ -146,9 +146,8 @@ func (this *BridgeDao) ListByShareUuid(shareUuid string) []*Bridge { return bridges } -//执行清理操作 func (this *BridgeDao) Cleanup() { - this.logger.Info("[BridgeDao]执行清理:清除数据库中所有Bridge记录。") + this.logger.Info("[BridgeDao] cleanup: delete all bridge records.") db := core.CONTEXT.GetDB().Where("uuid is not null").Delete(Bridge{}) this.PanicError(db.Error) } diff --git a/code/rest/bridge_model.go b/code/rest/bridge_model.go index 7da0e72..1165edc 100644 --- a/code/rest/bridge_model.go +++ b/code/rest/bridge_model.go @@ -5,7 +5,7 @@ import ( ) /** - * 分享记录和matter的关联表 + * the link table for Share and Matter. */ type Bridge struct { Base @@ -13,7 +13,6 @@ type Bridge struct { MatterUuid string `json:"matterUuid" gorm:"type:char(36)"` } -// set File's table name to be `profiles` func (this *Bridge) TableName() string { return core.TABLE_PREFIX + "bridge" } diff --git a/code/rest/bridge_service.go b/code/rest/bridge_service.go index fb4b824..cf39427 100644 --- a/code/rest/bridge_service.go +++ b/code/rest/bridge_service.go @@ -11,11 +11,9 @@ type BridgeService struct { userDao *UserDao } -//初始化方法 func (this *BridgeService) Init() { this.BaseBean.Init() - //手动装填本实例的Bean. 这里必须要用中间变量方可。 b := core.CONTEXT.GetBean(this.bridgeDao) if b, ok := b.(*BridgeDao); ok { this.bridgeDao = b @@ -28,7 +26,6 @@ func (this *BridgeService) Init() { } -//获取某个文件的详情,会把父级依次倒着装进去。如果中途出错,直接抛出异常。 func (this *BridgeService) Detail(uuid string) *Bridge { bridge := this.bridgeDao.CheckByUuid(uuid) diff --git a/code/rest/dashboard_controller.go b/code/rest/dashboard_controller.go index 51bac3c..7cc8449 100644 --- a/code/rest/dashboard_controller.go +++ b/code/rest/dashboard_controller.go @@ -14,11 +14,9 @@ type DashboardController struct { dashboardService *DashboardService } -//初始化方法 func (this *DashboardController) Init() { this.BaseController.Init() - //手动装填本实例的Bean. 这里必须要用中间变量方可。 b := core.CONTEXT.GetBean(this.dashboardDao) if b, ok := b.(*DashboardDao); ok { this.dashboardDao = b @@ -28,32 +26,20 @@ func (this *DashboardController) Init() { if b, ok := b.(*DashboardService); ok { this.dashboardService = b } - } -//注册自己的路由。 func (this *DashboardController) RegisterRoutes() map[string]func(writer http.ResponseWriter, request *http.Request) { routeMap := make(map[string]func(writer http.ResponseWriter, request *http.Request)) - //每个Controller需要主动注册自己的路由。 routeMap["/api/dashboard/page"] = this.Wrap(this.Page, USER_ROLE_ADMINISTRATOR) routeMap["/api/dashboard/active/ip/top10"] = this.Wrap(this.ActiveIpTop10, USER_ROLE_ADMINISTRATOR) return routeMap } -//过去七天分时调用量 -func (this *DashboardController) InvokeList(writer http.ResponseWriter, request *http.Request) *result.WebResult { - - return this.Success("") - -} - -//按照分页的方式获取某个图片缓存夹下图片缓存和子图片缓存夹的列表,通常情况下只有一页。 func (this *DashboardController) Page(writer http.ResponseWriter, request *http.Request) *result.WebResult { - //如果是根目录,那么就传入root. pageStr := request.FormValue("page") pageSizeStr := request.FormValue("pageSize") orderCreateTime := request.FormValue("orderCreateTime") @@ -99,6 +85,7 @@ func (this *DashboardController) Page(writer http.ResponseWriter, request *http. } func (this *DashboardController) ActiveIpTop10(writer http.ResponseWriter, request *http.Request) *result.WebResult { + //TODO: list := this.dashboardDao.ActiveIpTop10() return this.Success(list) } diff --git a/code/rest/dashboard_dao.go b/code/rest/dashboard_dao.go index 521ccd9..706aba2 100644 --- a/code/rest/dashboard_dao.go +++ b/code/rest/dashboard_dao.go @@ -12,7 +12,6 @@ type DashboardDao struct { BaseDao } -//创建 func (this *DashboardDao) Create(dashboard *Dashboard) *Dashboard { timeUUID, _ := uuid.NewV4() @@ -26,7 +25,6 @@ func (this *DashboardDao) Create(dashboard *Dashboard) *Dashboard { return dashboard } -//修改一条记录 func (this *DashboardDao) Save(dashboard *Dashboard) *Dashboard { dashboard.UpdateTime = time.Now() @@ -36,26 +34,22 @@ func (this *DashboardDao) Save(dashboard *Dashboard) *Dashboard { return dashboard } -//删除一条记录 func (this *DashboardDao) Delete(dashboard *Dashboard) { db := core.CONTEXT.GetDB().Delete(&dashboard) this.PanicError(db.Error) } -//按照dt查询 func (this *DashboardDao) FindByDt(dt string) *Dashboard { - // Read - var dashboard Dashboard - db := core.CONTEXT.GetDB().Where(&Dashboard{Dt: dt}).First(&dashboard) + var dashboard = &Dashboard{} + db := core.CONTEXT.GetDB().Where("dt = ?", dt).First(dashboard) if db.Error != nil { return nil } - return &dashboard + return dashboard } -//获取某个文件夹下所有的文件和子文件 func (this *DashboardDao) Page(page int, pageSize int, dt string, sortArray []builder.OrderPair) *Pager { var wp = &builder.WherePair{} @@ -79,7 +73,6 @@ func (this *DashboardDao) Page(page int, pageSize int, dt string, sortArray []bu return pager } -//获取最活跃的前10个ip func (this *DashboardDao) ActiveIpTop10() []*DashboardIpTimes { var dashboardIpTimes []*DashboardIpTimes @@ -102,7 +95,8 @@ func (this *DashboardDao) ActiveIpTop10() []*DashboardIpTimes { for rows.Next() { var ip string var times int64 = 0 - rows.Scan(&ip, ×) + err := rows.Scan(&ip, ×) + this.PanicError(err) item := &DashboardIpTimes{ Ip: ip, Times: times, @@ -113,9 +107,8 @@ func (this *DashboardDao) ActiveIpTop10() []*DashboardIpTimes { return dashboardIpTimes } -//执行清理操作 func (this *DashboardDao) Cleanup() { - this.logger.Info("[DashboardDao]执行清理:清除数据库中所有Dashboard记录。") + this.logger.Info("[DashboardDao] cleanup. Delete all Dashboard records") db := core.CONTEXT.GetDB().Where("uuid is not null").Delete(Dashboard{}) this.PanicError(db.Error) } diff --git a/code/rest/dashboard_model.go b/code/rest/dashboard_model.go index 0803299..202dd4f 100644 --- a/code/rest/dashboard_model.go +++ b/code/rest/dashboard_model.go @@ -3,20 +3,20 @@ package rest import "github.com/eyebluecn/tank/code/core" /** - * 系统的所有访问记录均记录在此 + * application's dashboard. */ type Dashboard struct { Base - InvokeNum int64 `json:"invokeNum" gorm:"type:bigint(20) not null"` //当日访问量 - TotalInvokeNum int64 `json:"totalInvokeNum" gorm:"type:bigint(20) not null;default:0"` //截至目前总访问量 - Uv int64 `json:"uv" gorm:"type:bigint(20) not null;default:0"` //当日UV - TotalUv int64 `json:"totalUv" gorm:"type:bigint(20) not null;default:0"` //截至目前总UV - MatterNum int64 `json:"matterNum" gorm:"type:bigint(20) not null;default:0"` //文件数量 - TotalMatterNum int64 `json:"totalMatterNum" gorm:"type:bigint(20) not null;default:0"` //截至目前文件数量 - FileSize int64 `json:"fileSize" gorm:"type:bigint(20) not null;default:0"` //当日文件大小 - TotalFileSize int64 `json:"totalFileSize" gorm:"type:bigint(20) not null;default:0"` //截至目前文件总大小 - AvgCost int64 `json:"avgCost" gorm:"type:bigint(20) not null;default:0"` //请求平均耗时 ms - Dt string `json:"dt" gorm:"type:varchar(45) not null;index:idx_dt"` //日期 + InvokeNum int64 `json:"invokeNum" gorm:"type:bigint(20) not null"` //api invoke num. + TotalInvokeNum int64 `json:"totalInvokeNum" gorm:"type:bigint(20) not null;default:0"` //total invoke num up to now. + Uv int64 `json:"uv" gorm:"type:bigint(20) not null;default:0"` //today's uv + TotalUv int64 `json:"totalUv" gorm:"type:bigint(20) not null;default:0"` //total uv + MatterNum int64 `json:"matterNum" gorm:"type:bigint(20) not null;default:0"` //file's num + TotalMatterNum int64 `json:"totalMatterNum" gorm:"type:bigint(20) not null;default:0"` //file's total number + FileSize int64 `json:"fileSize" gorm:"type:bigint(20) not null;default:0"` //today's file size + TotalFileSize int64 `json:"totalFileSize" gorm:"type:bigint(20) not null;default:0"` //total file's size + AvgCost int64 `json:"avgCost" gorm:"type:bigint(20) not null;default:0"` //api time cost in ms + Dt string `json:"dt" gorm:"type:varchar(45) not null;index:idx_dt"` //date } // set File's table name to be `profiles` @@ -25,7 +25,7 @@ func (this *Dashboard) TableName() string { } /** - * 统计IP活跃数的 + * ip */ type DashboardIpTimes struct { Ip string `json:"ip"` diff --git a/code/rest/dashboard_service.go b/code/rest/dashboard_service.go index 8044cda..cff2812 100644 --- a/code/rest/dashboard_service.go +++ b/code/rest/dashboard_service.go @@ -17,11 +17,9 @@ type DashboardService struct { userDao *UserDao } -//初始化方法 func (this *DashboardService) Init() { this.BaseBean.Init() - //手动装填本实例的Bean. 这里必须要用中间变量方可。 b := core.CONTEXT.GetBean(this.dashboardDao) if b, ok := b.(*DashboardDao); ok { this.dashboardDao = b @@ -49,81 +47,61 @@ func (this *DashboardService) Init() { } -//系统启动,数据库配置完毕后会调用该方法 func (this *DashboardService) Bootstrap() { - //每日00:05分清洗离线数据 + this.logger.Info("[cron job] Everyday 00:05 ETL dashboard data.") expression := "0 5 0 * * ?" cronJob := cron.New() err := cronJob.AddFunc(expression, this.etl) core.PanicError(err) cronJob.Start() - this.logger.Info("[cron job] 每日00:05清洗离线数据") - //立即执行一次数据清洗任务 + //do the etl method now. go core.RunWithRecovery(this.etl) - } -//每日清洗离线数据表。 +// handle the dashboard data. func (this *DashboardService) etl() { - this.logger.Info("每日定时数据清洗") + this.logger.Info("ETL dashboard data.") - //准备日期开始结尾 startTime := util.FirstSecondOfDay(util.Yesterday()) endTime := util.LastSecondOfDay(util.Yesterday()) dt := util.ConvertTimeToDateString(startTime) longTimeAgo := time.Now() longTimeAgo = longTimeAgo.AddDate(-20, 0, 0) - this.logger.Info("统计汇总表 %s -> %s", util.ConvertTimeToDateTimeString(startTime), util.ConvertTimeToDateTimeString(endTime)) + this.logger.Info("Time %s -> %s", util.ConvertTimeToDateTimeString(startTime), util.ConvertTimeToDateTimeString(endTime)) - //判断昨天的记录是否已经生成,如果生成了就直接删除掉 + //check whether the record has created. dbDashboard := this.dashboardDao.FindByDt(dt) if dbDashboard != nil { - this.logger.Info(" %s 的汇总已经存在了,删除以进行更新", dt) + this.logger.Info(" %s already exits. delete it and insert new one.", dt) this.dashboardDao.Delete(dbDashboard) } invokeNum := this.footprintDao.CountBetweenTime(startTime, endTime) - this.logger.Info("调用数:%d", invokeNum) - totalInvokeNum := this.footprintDao.CountBetweenTime(longTimeAgo, endTime) - this.logger.Info("历史总调用数:%d", totalInvokeNum) - uv := this.footprintDao.UvBetweenTime(startTime, endTime) - this.logger.Info("UV:%d", uv) - totalUv := this.footprintDao.UvBetweenTime(longTimeAgo, endTime) - this.logger.Info("历史总UV:%d", totalUv) - matterNum := this.matterDao.CountBetweenTime(startTime, endTime) - this.logger.Info("文件数量数:%d", matterNum) - totalMatterNum := this.matterDao.CountBetweenTime(longTimeAgo, endTime) - this.logger.Info("历史文件总数:%d", totalMatterNum) - var matterSize int64 - if matterNum != 0 { - matterSize = this.matterDao.SizeBetweenTime(startTime, endTime) - } - this.logger.Info("文件大小:%d", matterSize) + matterSize := this.matterDao.SizeBetweenTime(startTime, endTime) - var totalMatterSize int64 - if totalMatterNum != 0 { - totalMatterSize = this.matterDao.SizeBetweenTime(longTimeAgo, endTime) - } - this.logger.Info("历史文件总大小:%d", totalMatterSize) + totalMatterSize := this.matterDao.SizeBetweenTime(longTimeAgo, endTime) cacheSize := this.imageCacheDao.SizeBetweenTime(startTime, endTime) - this.logger.Info("缓存大小:%d", cacheSize) totalCacheSize := this.imageCacheDao.SizeBetweenTime(longTimeAgo, endTime) - this.logger.Info("历史缓存总大小:%d", totalCacheSize) avgCost := this.footprintDao.AvgCostBetweenTime(startTime, endTime) - this.logger.Info("平均耗时:%d ms", avgCost) + + this.logger.Info("Dashboard Summery 1. invokeNum = %d, totalInvokeNum = %d, UV = %d, totalUV = %d, matterNum = %d, totalMatterNum = %d", + invokeNum, totalInvokeNum, uv, totalUv, matterNum, totalMatterNum) + + this.logger.Info("Dashboard Summery 2. matterSize = %d, totalMatterSize = %d, cacheSize = %d, totalCacheSize = %d, avgCost = %d", + matterSize, totalMatterSize, cacheSize, totalCacheSize, avgCost) dashboard := &Dashboard{ InvokeNum: invokeNum, @@ -139,5 +117,4 @@ func (this *DashboardService) etl() { } this.dashboardDao.Create(dashboard) - } diff --git a/code/rest/dav_controller.go b/code/rest/dav_controller.go index 82ec0a0..0d980d7 100644 --- a/code/rest/dav_controller.go +++ b/code/rest/dav_controller.go @@ -15,7 +15,7 @@ import ( /** * - * WebDav协议文档 + * WebDav document * https://tools.ietf.org/html/rfc4918 * http://www.webdav.org/specs/rfc4918.html * @@ -32,11 +32,9 @@ type DavController struct { davService *DavService } -//初始化方法 func (this *DavController) Init() { this.BaseController.Init() - //手动装填本实例的Bean. b := core.CONTEXT.GetBean(this.uploadTokenDao) if c, ok := b.(*UploadTokenDao); ok { this.uploadTokenDao = c @@ -73,12 +71,12 @@ func (this *DavController) Init() { } } -//通过BasicAuth的方式授权。 +//Auth user by BasicAuth func (this *DavController) CheckCurrentUser(writer http.ResponseWriter, request *http.Request) *User { username, password, ok := request.BasicAuth() if !ok { - //要求前端使用Basic的形式授权 + // require the basic auth. writer.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`) panic(result.ConstWebResult(result.LOGIN)) } @@ -95,7 +93,6 @@ func (this *DavController) CheckCurrentUser(writer http.ResponseWriter, request return user } -//注册自己的路由。 func (this *DavController) RegisterRoutes() map[string]func(writer http.ResponseWriter, request *http.Request) { routeMap := make(map[string]func(writer http.ResponseWriter, request *http.Request)) @@ -103,23 +100,20 @@ func (this *DavController) RegisterRoutes() map[string]func(writer http.Response return routeMap } -//处理一些特殊的接口,比如参数包含在路径中,一般情况下,controller不将参数放在url路径中 +//handle some special routes, eg. params in the url. func (this *DavController) HandleRoutes(writer http.ResponseWriter, request *http.Request) (func(writer http.ResponseWriter, request *http.Request), bool) { path := request.URL.Path - //匹配 /api/dav{subPath} + //match /api/dav{subPath} pattern := fmt.Sprintf(`^%s(.*)$`, WEBDAV_PREFIX) reg := regexp.MustCompile(pattern) strs := reg.FindStringSubmatch(path) if len(strs) == 2 { var f = func(writer http.ResponseWriter, request *http.Request) { subPath := strs[1] - //保证subPath不是以/结尾的。 - //最后多余的/要去掉 - if strings.HasSuffix(subPath, "/") { - subPath = subPath[0 : len(subPath)-1] - } + //guarantee subPath not end with / + subPath = strings.TrimSuffix(subPath, "/") this.Index(writer, request, subPath) } return f, true @@ -128,12 +122,10 @@ func (this *DavController) HandleRoutes(writer http.ResponseWriter, request *htt return nil, false } -//完成系统安装 -func (this *DavController) Index(writer http.ResponseWriter, request *http.Request, subPath string) { +func (this *DavController) debug(writer http.ResponseWriter, request *http.Request, subPath string) { - /*打印所有HEADER以及请求参数*/ - - fmt.Printf("\n------ 请求: %s -- %s ------\n", request.URL, subPath) + //Print the Request info. + fmt.Printf("\n------ %s -- %s ------\n", request.URL, subPath) fmt.Printf("\n------Method:------\n") fmt.Println(request.Method) @@ -143,13 +135,13 @@ func (this *DavController) Index(writer http.ResponseWriter, request *http.Reque fmt.Printf("%s = %s\n", key, value) } - fmt.Printf("\n------请求参数:------\n") + fmt.Printf("\n------Params:------\n") for key, value := range request.Form { fmt.Printf("%s = %s\n", key, value) } fmt.Printf("\n------Body:------\n") - //ioutil.ReadAll 不可重复读,第二次读的时候就什么都没有了。 + //ioutil.ReadAll cannot read again. when read again, there is nothing. bodyBytes, err := ioutil.ReadAll(request.Body) if err != nil { @@ -157,7 +149,7 @@ func (this *DavController) Index(writer http.ResponseWriter, request *http.Reque } fmt.Println(string(bodyBytes)) - //关闭之后再重新赋值 + //close and resign err = request.Body.Close() if err != nil { panic(err) @@ -166,7 +158,12 @@ func (this *DavController) Index(writer http.ResponseWriter, request *http.Reque fmt.Println("------------------") - //获取请求者 +} + +func (this *DavController) Index(writer http.ResponseWriter, request *http.Request, subPath string) { + + //this.debug(writer, request, subPath) + user := this.CheckCurrentUser(writer, request) this.davService.HandleDav(writer, request, user, subPath) diff --git a/code/rest/dav_model.go b/code/rest/dav_model.go index e20a6fe..eb7c38d 100644 --- a/code/rest/dav_model.go +++ b/code/rest/dav_model.go @@ -9,16 +9,16 @@ import ( "strconv" ) -//访问前缀,这个是特殊入口 +//webdav url prefix. var WEBDAV_PREFIX = "/api/dav" -//动态的文件属性 +//live prop. type LiveProp struct { findFn func(user *User, matter *Matter) string dir bool } -//所有的动态属性定义及其值的获取方式 +//all live prop map. var LivePropMap = map[xml.Name]LiveProp{ {Space: "DAV:", Local: "resourcetype"}: { findFn: func(user *User, matter *Matter) string { @@ -106,7 +106,7 @@ var LivePropMap = map[xml.Name]LiveProp{ if user.SizeLimit >= 0 { size = user.SizeLimit } else { - //没有限制,默认100G + //TODO: no limit, default 100G. size = 100 * 1024 * 1024 * 1024 } return fmt.Sprintf(`%d`, size) @@ -115,7 +115,7 @@ var LivePropMap = map[xml.Name]LiveProp{ }, {Space: "DAV:", Local: "quota-used-bytes"}: { findFn: func(user *User, matter *Matter) string { - //已使用大小,默认0 + //TODO: default 0 return fmt.Sprintf(`%d`, 0) }, dir: true, diff --git a/code/rest/dav_service.go b/code/rest/dav_service.go index 14633cc..b9cab8f 100644 --- a/code/rest/dav_service.go +++ b/code/rest/dav_service.go @@ -16,10 +16,10 @@ import ( /** * - * WebDav协议文档 + * WebDav document * https://tools.ietf.org/html/rfc4918 - * 主要参考 golang.org/x/net/webdav - * 测试机:http://www.webdav.org/neon/litmus/ + * refer: golang.org/x/net/webdav + * test machine: http://www.webdav.org/neon/litmus/ */ //@Service type DavService struct { @@ -28,11 +28,9 @@ type DavService struct { matterService *MatterService } -//初始化方法 func (this *DavService) Init() { this.BaseBean.Init() - //手动装填本实例的Bean. 这里必须要用中间变量方可。 b := core.CONTEXT.GetBean(this.matterDao) if b, ok := b.(*MatterDao); ok { this.matterDao = b @@ -45,7 +43,7 @@ func (this *DavService) Init() { } -//获取Header头中的Depth值,暂不支持 infinity +//get the depth in header. Not support infinity yet. func (this *DavService) ParseDepth(request *http.Request) int { depth := 1 @@ -84,7 +82,7 @@ func (this *DavService) makePropstatResponse(href string, pstats []dav.Propstat) return &resp } -//从一个matter中获取其 []dav.Propstat +//fetch a matter's []dav.Propstat func (this *DavService) PropstatsFromXmlNames(user *User, matter *Matter, xmlNames []xml.Name) []dav.Propstat { propstats := make([]dav.Propstat, 0) @@ -92,7 +90,7 @@ func (this *DavService) PropstatsFromXmlNames(user *User, matter *Matter, xmlNam var properties []dav.Property for _, xmlName := range xmlNames { - //TODO: deadprops尚未考虑 + //TODO: deadprops not implement yet. // Otherwise, it must either be a live property or we don't know it. if liveProp := LivePropMap[xmlName]; liveProp.findFn != nil && (liveProp.dir || !matter.Dir) { @@ -103,7 +101,7 @@ func (this *DavService) PropstatsFromXmlNames(user *User, matter *Matter, xmlNam InnerXML: []byte(innerXML), }) } else { - this.logger.Info("%s的%s无法完成", matter.Path, xmlName.Local) + this.logger.Info("%s %s cannot finish.", matter.Path, xmlName.Local) } } @@ -119,7 +117,6 @@ func (this *DavService) PropstatsFromXmlNames(user *User, matter *Matter, xmlNam } -//从一个matter中获取所有的propsNames func (this *DavService) AllPropXmlNames(matter *Matter) []xml.Name { pnames := make([]xml.Name, 0) @@ -132,7 +129,6 @@ func (this *DavService) AllPropXmlNames(matter *Matter) []xml.Name { return pnames } -//从一个matter中获取其 []dav.Propstat func (this *DavService) Propstats(user *User, matter *Matter, propfind *dav.Propfind) []dav.Propstat { propstats := make([]dav.Propstat, 0) @@ -140,7 +136,7 @@ func (this *DavService) Propstats(user *User, matter *Matter, propfind *dav.Prop panic(result.BadRequest("TODO: propfind.Propname != nil ")) } else if propfind.Allprop != nil { - //TODO: 如果include中还有内容,那么包含进去。 + //TODO: if include other things. add to it. xmlNames := this.AllPropXmlNames(matter) propstats = this.PropstatsFromXmlNames(user, matter, xmlNames) @@ -153,48 +149,44 @@ func (this *DavService) Propstats(user *User, matter *Matter, propfind *dav.Prop } -//列出文件夹或者目录详情 +//list the directory. func (this *DavService) HandlePropfind(writer http.ResponseWriter, request *http.Request, user *User, subPath string) { fmt.Printf("PROPFIND %s\n", subPath) - //获取请求的层数。暂不支持 infinity depth := this.ParseDepth(request) - //读取请求参数。按照用户的参数请求返回内容。 propfind := dav.ReadPropfind(request.Body) - //寻找符合条件的matter. - //如果是空或者/就是请求根目录 + //find the matter, if subPath is null, means the root directory. matter := this.matterDao.CheckWithRootByPath(subPath, user) var matters []*Matter if depth == 0 { matters = []*Matter{matter} } else { - // len(matters) == 0 表示该文件夹下面是空文件夹 + // len(matters) == 0 means empty directory matters = this.matterDao.ListByPuuidAndUserUuid(matter.Uuid, user.Uuid, nil) - //将当前的matter添加到头部 + //add this matter to head. matters = append([]*Matter{matter}, matters...) } - //准备一个输出结果的Writer + //prepare a multiStatusWriter. multiStatusWriter := &dav.MultiStatusWriter{Writer: writer} for _, matter := range matters { - fmt.Printf("处理Matter %s\n", matter.Path) + fmt.Printf("handle Matter %s\n", matter.Path) propstats := this.Propstats(user, matter, propfind) - path := fmt.Sprintf("%s%s", WEBDAV_PREFIX, matter.Path) - response := this.makePropstatResponse(path, propstats) + visitPath := fmt.Sprintf("%s%s", WEBDAV_PREFIX, matter.Path) + response := this.makePropstatResponse(visitPath, propstats) err := multiStatusWriter.Write(response) this.PanicError(err) } - //闭合 err := multiStatusWriter.Close() this.PanicError(err) @@ -202,25 +194,25 @@ func (this *DavService) HandlePropfind(writer http.ResponseWriter, request *http } -//请求文件详情(下载) +//handle download func (this *DavService) HandleGetHeadPost(writer http.ResponseWriter, request *http.Request, user *User, subPath string) { fmt.Printf("GET %s\n", subPath) matter := this.matterDao.CheckWithRootByPath(subPath, user) - //如果是文件夹,相当于是 Propfind + //if this is a Directory, it means Propfind if matter.Dir { this.HandlePropfind(writer, request, user, subPath) return } - //下载一个文件。 + //download a file. this.matterService.DownloadFile(writer, request, matter.AbsolutePath(), matter.Name, false) } -//上传文件 +//upload a file func (this *DavService) HandlePut(writer http.ResponseWriter, request *http.Request, user *User, subPath string) { fmt.Printf("PUT %s\n", subPath) @@ -228,10 +220,9 @@ func (this *DavService) HandlePut(writer http.ResponseWriter, request *http.Requ filename := util.GetFilenameOfPath(subPath) dirPath := util.GetDirOfPath(subPath) - //寻找符合条件的matter. dirMatter := this.matterDao.CheckWithRootByPath(dirPath, user) - //如果存在,那么先删除再说。 + //if exist delete it. srcMatter := this.matterDao.findByUserUuidAndPath(user.Uuid, subPath) if srcMatter != nil { this.matterService.AtomicDelete(request, srcMatter) @@ -241,18 +232,17 @@ func (this *DavService) HandlePut(writer http.ResponseWriter, request *http.Requ } -//删除文件 +//delete file func (this *DavService) HandleDelete(writer http.ResponseWriter, request *http.Request, user *User, subPath string) { fmt.Printf("DELETE %s\n", subPath) - //寻找符合条件的matter. matter := this.matterDao.CheckWithRootByPath(subPath, user) this.matterService.AtomicDelete(request, matter) } -//创建文件夹 +//crate a directory func (this *DavService) HandleMkcol(writer http.ResponseWriter, request *http.Request, user *User, subPath string) { fmt.Printf("MKCOL %s\n", subPath) @@ -260,19 +250,17 @@ func (this *DavService) HandleMkcol(writer http.ResponseWriter, request *http.Re thisDirName := util.GetFilenameOfPath(subPath) dirPath := util.GetDirOfPath(subPath) - //寻找符合条件的matter. dirMatter := this.matterDao.CheckWithRootByPath(dirPath, user) this.matterService.AtomicCreateDirectory(request, dirMatter, thisDirName, user) } -//跨域请求的OPTIONS询问 +//cors options func (this *DavService) HandleOptions(w http.ResponseWriter, r *http.Request, user *User, subPath string) { fmt.Printf("OPTIONS %s\n", subPath) - //寻找符合条件的matter. matter := this.matterDao.CheckWithRootByPath(subPath, user) allow := "OPTIONS, LOCK, PUT, MKCOL" @@ -290,7 +278,7 @@ func (this *DavService) HandleOptions(w http.ResponseWriter, r *http.Request, us } -//移动或者复制的准备工作 +//prepare for moving or copying func (this *DavService) prepareMoveCopy( writer http.ResponseWriter, request *http.Request, @@ -302,22 +290,22 @@ func (this *DavService) prepareMoveCopy( destinationName string, overwrite bool) { - //解析出目标路径。 + //parse the destination. destinationStr := request.Header.Get("Destination") - //解析出Overwrite。 + //parse Overwrite。 overwriteStr := request.Header.Get("Overwrite") - //有前缀的目标path + //destination path with prefix var fullDestinationPath string - //去掉前缀的目标path + //destination path without prefix var destinationPath string if destinationStr == "" { panic(result.BadRequest("Header Destination cannot be null")) } - //如果是重命名,那么就不是http开头了。 + //if rename. not start with http if strings.HasPrefix(destinationStr, WEBDAV_PREFIX) { fullDestinationPath = destinationStr } else { @@ -329,10 +317,10 @@ func (this *DavService) prepareMoveCopy( fullDestinationPath = destinationUrl.Path } - //去除 路径中的相对路径 比如 /a/b/../ => /a/ + //clean the relative path. eg. /a/b/../ => /a/ fullDestinationPath = path.Clean(fullDestinationPath) - //去除前缀 + //clean the prefix pattern := fmt.Sprintf(`^%s(.*)$`, WEBDAV_PREFIX) reg := regexp.MustCompile(pattern) strs := reg.FindStringSubmatch(fullDestinationPath) @@ -351,133 +339,131 @@ func (this *DavService) prepareMoveCopy( overwrite = true } - //如果前后一致,那么相当于没有改变 + //if not change return. if destinationPath == subPath { return } - //源matter. - //寻找符合条件的matter. + //source matter srcMatter = this.matterDao.CheckWithRootByPath(subPath, user) - //如果是空或者/就是请求根目录 + //if source matter is root. if srcMatter.Uuid == MATTER_ROOT { panic(result.BadRequest("you cannot move the root directory")) } - //寻找目标文件夹matter destDirMatter = this.matterDao.CheckWithRootByPath(destinationDirPath, user) return srcMatter, destDirMatter, srcDirPath, destinationDirPath, destinationName, overwrite } -//移动或者重命名 +//move or rename. func (this *DavService) HandleMove(writer http.ResponseWriter, request *http.Request, user *User, subPath string) { fmt.Printf("MOVE %s\n", subPath) srcMatter, destDirMatter, srcDirPath, destinationDirPath, destinationName, overwrite := this.prepareMoveCopy(writer, request, user, subPath) - //移动到新目录中去。 + //move to the new directory if destinationDirPath == srcDirPath { - //文件夹没变化,相当于重命名。 + //if destination path not change. it means rename. this.matterService.AtomicRename(request, srcMatter, destinationName, user) } else { this.matterService.AtomicMove(request, srcMatter, destDirMatter, overwrite) } - this.logger.Info("完成移动 %s => %s", subPath, destDirMatter.Path) + this.logger.Info("finish moving %s => %s", subPath, destDirMatter.Path) } -//复制文件/文件夹 +//copy file/directory func (this *DavService) HandleCopy(writer http.ResponseWriter, request *http.Request, user *User, subPath string) { fmt.Printf("COPY %s\n", subPath) srcMatter, destDirMatter, _, _, destinationName, overwrite := this.prepareMoveCopy(writer, request, user, subPath) - //复制到新目录中去。 + //copy to the new directory this.matterService.AtomicCopy(request, srcMatter, destDirMatter, destinationName, overwrite) - this.logger.Info("完成复制 %s => %s", subPath, destDirMatter.Path) + this.logger.Info("finish copying %s => %s", subPath, destDirMatter.Path) } -//加锁 +//lock. func (this *DavService) HandleLock(writer http.ResponseWriter, request *http.Request, user *User, subPath string) { panic(result.BadRequest("not support LOCK yet.")) } -//解锁 +//unlock func (this *DavService) HandleUnlock(writer http.ResponseWriter, request *http.Request, user *User, subPath string) { panic(result.BadRequest("not support UNLOCK yet.")) } -//修改文件属性 +//change the file's property func (this *DavService) HandleProppatch(writer http.ResponseWriter, request *http.Request, user *User, subPath string) { panic(result.BadRequest("not support PROPPATCH yet.")) } -//处理所有的请求 +//hanle all the request. func (this *DavService) HandleDav(writer http.ResponseWriter, request *http.Request, user *User, subPath string) { method := request.Method if method == "OPTIONS" { - //跨域问询 + //cors option this.HandleOptions(writer, request, user, subPath) } else if method == "GET" || method == "HEAD" || method == "POST" { - //请求文件详情(下载) + //get the detail of file. download this.HandleGetHeadPost(writer, request, user, subPath) } else if method == "DELETE" { - //删除文件 + //delete file this.HandleDelete(writer, request, user, subPath) } else if method == "PUT" { - //上传文件 + //upload file this.HandlePut(writer, request, user, subPath) } else if method == "MKCOL" { - //创建文件夹 + //crate directory this.HandleMkcol(writer, request, user, subPath) } else if method == "COPY" { - //复制文件/文件夹 + //copy file/directory this.HandleCopy(writer, request, user, subPath) } else if method == "MOVE" { - //移动(重命名)文件/文件夹 + //move/rename a file or directory this.HandleMove(writer, request, user, subPath) } else if method == "LOCK" { - //加锁 + //lock this.HandleLock(writer, request, user, subPath) } else if method == "UNLOCK" { - //释放锁 + //unlock this.HandleUnlock(writer, request, user, subPath) } else if method == "PROPFIND" { - //列出文件夹或者目录详情 + //list a directory this.HandlePropfind(writer, request, user, subPath) } else if method == "PROPPATCH" { - //修改文件属性 + //change file's property. this.HandleProppatch(writer, request, user, subPath) } else { diff --git a/code/rest/download_token_dao.go b/code/rest/download_token_dao.go index 4b76c24..e902b45 100644 --- a/code/rest/download_token_dao.go +++ b/code/rest/download_token_dao.go @@ -2,6 +2,7 @@ package rest import ( "github.com/eyebluecn/tank/code/core" + "github.com/eyebluecn/tank/code/tool/result" "github.com/nu7hatch/gouuid" "time" ) @@ -10,31 +11,30 @@ type DownloadTokenDao struct { BaseDao } -//按照Id查询 +//find by uuid. if not found return nil. func (this *DownloadTokenDao) FindByUuid(uuid string) *DownloadToken { - - // Read - var downloadToken = &DownloadToken{} - db := core.CONTEXT.GetDB().Where(&DownloadToken{Base: Base{Uuid: uuid}}).First(downloadToken) + var entity = &DownloadToken{} + db := core.CONTEXT.GetDB().Where("uuid = ?", uuid).First(entity) if db.Error != nil { - return nil + if db.Error.Error() == result.DB_ERROR_NOT_FOUND { + return nil + } else { + panic(db.Error) + } } - return downloadToken + return entity } -//按照Id查询 +//find by uuid. if not found panic NotFound error func (this *DownloadTokenDao) CheckByUuid(uuid string) *DownloadToken { - - // Read - var downloadToken = &DownloadToken{} - db := core.CONTEXT.GetDB().Where(&DownloadToken{Base: Base{Uuid: uuid}}).First(downloadToken) - this.PanicError(db.Error) - return downloadToken - + entity := this.FindByUuid(uuid) + if entity == nil { + panic(result.NotFound("not found record with uuid = %s", uuid)) + } + return entity } -//创建一个session并且持久化到数据库中。 func (this *DownloadTokenDao) Create(downloadToken *DownloadToken) *DownloadToken { timeUUID, _ := uuid.NewV4() @@ -49,7 +49,6 @@ func (this *DownloadTokenDao) Create(downloadToken *DownloadToken) *DownloadToke return downloadToken } -//修改一个downloadToken func (this *DownloadTokenDao) Save(downloadToken *DownloadToken) *DownloadToken { downloadToken.UpdateTime = time.Now() @@ -59,9 +58,8 @@ func (this *DownloadTokenDao) Save(downloadToken *DownloadToken) *DownloadToken return downloadToken } -//执行清理操作 func (this *DownloadTokenDao) Cleanup() { - this.logger.Info("[DownloadTokenDao]执行清理:清除数据库中所有DownloadToken记录。") + this.logger.Info("[DownloadTokenDao] clean up. Delete all DownloadToken") db := core.CONTEXT.GetDB().Where("uuid is not null").Delete(DownloadToken{}) this.PanicError(db.Error) } diff --git a/code/rest/footprint_controller.go b/code/rest/footprint_controller.go index 54d5644..36cf87d 100644 --- a/code/rest/footprint_controller.go +++ b/code/rest/footprint_controller.go @@ -11,11 +11,9 @@ type FootprintController struct { footprintService *FootprintService } -//初始化方法 func (this *FootprintController) Init() { this.BaseController.Init() - //手动装填本实例的Bean. 这里必须要用中间变量方可。 b := core.CONTEXT.GetBean(this.footprintDao) if b, ok := b.(*FootprintDao); ok { this.footprintDao = b @@ -28,7 +26,6 @@ func (this *FootprintController) Init() { } -//注册自己的路由。 func (this *FootprintController) RegisterRoutes() map[string]func(writer http.ResponseWriter, request *http.Request) { routeMap := make(map[string]func(writer http.ResponseWriter, request *http.Request)) diff --git a/code/rest/footprint_dao.go b/code/rest/footprint_dao.go index 5bbfe86..bbd9af1 100644 --- a/code/rest/footprint_dao.go +++ b/code/rest/footprint_dao.go @@ -3,6 +3,7 @@ package rest import ( "github.com/eyebluecn/tank/code/core" "github.com/eyebluecn/tank/code/tool/builder" + "github.com/eyebluecn/tank/code/tool/result" "github.com/jinzhu/gorm" "github.com/nu7hatch/gouuid" @@ -13,31 +14,29 @@ type FootprintDao struct { BaseDao } -//按照Id查询文件 +//find by uuid. if not found return nil. func (this *FootprintDao) FindByUuid(uuid string) *Footprint { - - // Read - var footprint Footprint - db := core.CONTEXT.GetDB().Where(&Footprint{Base: Base{Uuid: uuid}}).First(&footprint) + var entity = &Footprint{} + db := core.CONTEXT.GetDB().Where("uuid = ?", uuid).First(entity) if db.Error != nil { - return nil + if db.Error.Error() == result.DB_ERROR_NOT_FOUND { + return nil + } else { + panic(db.Error) + } } - return &footprint + return entity } -//按照Id查询文件 +//find by uuid. if not found panic NotFound error func (this *FootprintDao) CheckByUuid(uuid string) *Footprint { - - // Read - var footprint Footprint - db := core.CONTEXT.GetDB().Where(&Footprint{Base: Base{Uuid: uuid}}).First(&footprint) - this.PanicError(db.Error) - - return &footprint - + entity := this.FindByUuid(uuid) + if entity == nil { + panic(result.NotFound("not found record with uuid = %s", uuid)) + } + return entity } -//按分页条件获取分页 func (this *FootprintDao) Page(page int, pageSize int, userUuid string, sortArray []builder.OrderPair) *Pager { var wp = &builder.WherePair{} @@ -61,7 +60,6 @@ func (this *FootprintDao) Page(page int, pageSize int, userUuid string, sortArra return pager } -//创建 func (this *FootprintDao) Create(footprint *Footprint) *Footprint { timeUUID, _ := uuid.NewV4() @@ -75,7 +73,6 @@ func (this *FootprintDao) Create(footprint *Footprint) *Footprint { return footprint } -//修改一条记录 func (this *FootprintDao) Save(footprint *Footprint) *Footprint { footprint.UpdateTime = time.Now() @@ -85,14 +82,12 @@ func (this *FootprintDao) Save(footprint *Footprint) *Footprint { return footprint } -//删除一条记录 func (this *FootprintDao) Delete(footprint *Footprint) { db := core.CONTEXT.GetDB().Delete(&footprint) this.PanicError(db.Error) } -//获取一段时间中,总的数量 func (this *FootprintDao) CountBetweenTime(startTime time.Time, endTime time.Time) int64 { var count int64 db := core.CONTEXT.GetDB().Model(&Footprint{}).Where("create_time >= ? AND create_time <= ?", startTime, endTime).Count(&count) @@ -100,35 +95,51 @@ func (this *FootprintDao) CountBetweenTime(startTime time.Time, endTime time.Tim return count } -//获取一段时间中UV的数量 func (this *FootprintDao) UvBetweenTime(startTime time.Time, endTime time.Time) int64 { + + var wp = &builder.WherePair{Query: "create_time >= ? AND create_time <= ?", Args: []interface{}{startTime, endTime}} + var count int64 - db := core.CONTEXT.GetDB().Model(&Footprint{}).Where("create_time >= ? AND create_time <= ?", startTime, endTime).Select("COUNT(DISTINCT(ip))") + db := core.CONTEXT.GetDB().Model(&Footprint{}).Where(wp.Query, wp.Args...).Count(&count) + if count == 0 { + return 0 + } + + db = core.CONTEXT.GetDB().Model(&Footprint{}).Where("create_time >= ? AND create_time <= ?", startTime, endTime).Select("COUNT(DISTINCT(ip))") this.PanicError(db.Error) row := db.Row() - row.Scan(&count) + err := row.Scan(&count) + this.PanicError(err) return count } -//获取一段时间中平均耗时 func (this *FootprintDao) AvgCostBetweenTime(startTime time.Time, endTime time.Time) int64 { + + var wp = &builder.WherePair{Query: "create_time >= ? AND create_time <= ?", Args: []interface{}{startTime, endTime}} + + var count int64 + db := core.CONTEXT.GetDB().Model(&Footprint{}).Where(wp.Query, wp.Args...).Count(&count) + if count == 0 { + return 0 + } + var cost float64 - db := core.CONTEXT.GetDB().Model(&Footprint{}).Where("create_time >= ? AND create_time <= ?", startTime, endTime).Select("AVG(cost)") + db = core.CONTEXT.GetDB().Model(&Footprint{}).Where(wp.Query, wp.Args...).Select("AVG(cost)") this.PanicError(db.Error) row := db.Row() - row.Scan(&cost) + err := row.Scan(&cost) + this.PanicError(err) return int64(cost) } -//删除某个时刻之前的记录 func (this *FootprintDao) DeleteByCreateTimeBefore(createTime time.Time) { db := core.CONTEXT.GetDB().Where("create_time < ?", createTime).Delete(Footprint{}) this.PanicError(db.Error) } -//执行清理操作 +//System cleanup. func (this *FootprintDao) Cleanup() { - this.logger.Info("[FootprintDao]执行清理:清除数据库中所有Footprint记录。") + this.logger.Info("[FootprintDao][DownloadTokenDao] clean up. Delete all Footprint") db := core.CONTEXT.GetDB().Where("uuid is not null").Delete(Footprint{}) this.PanicError(db.Error) } diff --git a/code/rest/footprint_model.go b/code/rest/footprint_model.go index df0f02c..37f0d57 100644 --- a/code/rest/footprint_model.go +++ b/code/rest/footprint_model.go @@ -3,7 +3,7 @@ package rest import "github.com/eyebluecn/tank/code/core" /** - * 系统的所有访问记录均记录在此 + * visit record. */ type Footprint struct { Base diff --git a/code/rest/footprint_service.go b/code/rest/footprint_service.go index 89bd4a4..414d33d 100644 --- a/code/rest/footprint_service.go +++ b/code/rest/footprint_service.go @@ -17,11 +17,9 @@ type FootprintService struct { userDao *UserDao } -//初始化方法 func (this *FootprintService) Init() { this.BaseBean.Init() - //手动装填本实例的Bean. 这里必须要用中间变量方可。 b := core.CONTEXT.GetBean(this.footprintDao) if b, ok := b.(*FootprintDao); ok { this.footprintDao = b @@ -34,7 +32,6 @@ func (this *FootprintService) Init() { } -//获取某个文件的详情,会把父级依次倒着装进去。如果中途出错,直接抛出异常。 func (this *FootprintService) Detail(uuid string) *Footprint { footprint := this.footprintDao.CheckByUuid(uuid) @@ -42,17 +39,17 @@ func (this *FootprintService) Detail(uuid string) *Footprint { return footprint } -//记录访问记录 +//log a request. func (this *FootprintService) Trace(request *http.Request, duration time.Duration, success bool) { params := make(map[string][]string) - //POST请求参数 + //POST params values := request.PostForm for key, val := range values { params[key] = val } - //GET请求参数 + //GET params values1 := request.URL.Query() for key, val := range values1 { params[key] = val @@ -65,14 +62,12 @@ func (this *FootprintService) Trace(request *http.Request, duration time.Duratio } } - //用json的方式输出返回值。 paramsString := "{}" paramsData, err := json.Marshal(params) if err == nil { paramsString = string(paramsData) } - //将文件信息存入数据库中。 footprint := &Footprint{ Ip: util.GetIpAddress(request), Host: request.Host, @@ -82,7 +77,7 @@ func (this *FootprintService) Trace(request *http.Request, duration time.Duratio Success: success, } - //有可能DB尚且没有配置 直接打印出内容,并且退出 + //if db not config just print content. if core.CONFIG.Installed() { user := this.findUser(request) userUuid := "" @@ -93,35 +88,30 @@ func (this *FootprintService) Trace(request *http.Request, duration time.Duratio footprint = this.footprintDao.Create(footprint) } - //用json的方式输出返回值。 this.logger.Info("Ip:%s Cost:%d Uri:%s Params:%s", footprint.Ip, int64(duration/time.Millisecond), footprint.Uri, paramsString) } -//系统启动,数据库配置完毕后会调用该方法 func (this *FootprintService) Bootstrap() { - //每日00:10 删除8日之前的访问数据 + this.logger.Info("[cron job] Every day 00:10 delete Footprint data 8 days ago.") expression := "0 10 0 * * ?" cronJob := cron.New() err := cronJob.AddFunc(expression, this.cleanOldData) core.PanicError(err) cronJob.Start() - this.logger.Info("[cron job] 每日00:10 删除8日之前的访问数据") - //立即执行一次数据清洗任务 go core.RunWithRecovery(this.cleanOldData) } -//定期删除8日前的数据。 func (this *FootprintService) cleanOldData() { day8Ago := time.Now() day8Ago = day8Ago.AddDate(0, 0, -8) day8Ago = util.FirstSecondOfDay(day8Ago) - this.logger.Info("删除%s之前的访问数据", util.ConvertTimeToDateTimeString(day8Ago)) + this.logger.Info("Delete footprint data before %s", util.ConvertTimeToDateTimeString(day8Ago)) this.footprintDao.DeleteByCreateTimeBefore(day8Ago) } diff --git a/code/rest/image_cache_controller.go b/code/rest/image_cache_controller.go index f346c6f..6ada1ee 100644 --- a/code/rest/image_cache_controller.go +++ b/code/rest/image_cache_controller.go @@ -15,11 +15,9 @@ type ImageCacheController struct { imageCacheService *ImageCacheService } -//初始化方法 func (this *ImageCacheController) Init() { this.BaseController.Init() - //手动装填本实例的Bean. 这里必须要用中间变量方可。 b := core.CONTEXT.GetBean(this.imageCacheDao) if b, ok := b.(*ImageCacheDao); ok { this.imageCacheDao = b @@ -32,12 +30,10 @@ func (this *ImageCacheController) Init() { } -//注册自己的路由。 func (this *ImageCacheController) RegisterRoutes() map[string]func(writer http.ResponseWriter, request *http.Request) { routeMap := make(map[string]func(writer http.ResponseWriter, request *http.Request)) - //每个Controller需要主动注册自己的路由。 routeMap["/api/image/cache/delete"] = this.Wrap(this.Delete, USER_ROLE_USER) routeMap["/api/image/cache/delete/batch"] = this.Wrap(this.DeleteBatch, USER_ROLE_USER) routeMap["/api/image/cache/detail"] = this.Wrap(this.Detail, USER_ROLE_USER) @@ -46,7 +42,6 @@ func (this *ImageCacheController) RegisterRoutes() map[string]func(writer http.R return routeMap } -//查看某个图片缓存的详情。 func (this *ImageCacheController) Detail(writer http.ResponseWriter, request *http.Request) *result.WebResult { uuid := request.FormValue("uuid") @@ -56,7 +51,6 @@ func (this *ImageCacheController) Detail(writer http.ResponseWriter, request *ht imageCache := this.imageCacheService.Detail(uuid) - //验证当前之人是否有权限查看这么详细。 user := this.checkUser(request) if imageCache.UserUuid != user.Uuid { panic(result.UNAUTHORIZED) @@ -66,9 +60,8 @@ func (this *ImageCacheController) Detail(writer http.ResponseWriter, request *ht } -//按照分页的方式获取某个图片缓存夹下图片缓存和子图片缓存夹的列表,通常情况下只有一页。 func (this *ImageCacheController) Page(writer http.ResponseWriter, request *http.Request) *result.WebResult { - //如果是根目录,那么就传入root. + pageStr := request.FormValue("page") pageSizeStr := request.FormValue("pageSize") orderCreateTime := request.FormValue("orderCreateTime") @@ -120,7 +113,6 @@ func (this *ImageCacheController) Page(writer http.ResponseWriter, request *http return this.Success(pager) } -//删除一个图片缓存 func (this *ImageCacheController) Delete(writer http.ResponseWriter, request *http.Request) *result.WebResult { uuid := request.FormValue("uuid") @@ -130,19 +122,16 @@ func (this *ImageCacheController) Delete(writer http.ResponseWriter, request *ht imageCache := this.imageCacheDao.FindByUuid(uuid) - //判断图片缓存的所属人是否正确 user := this.checkUser(request) if imageCache.UserUuid != user.Uuid { - - panic(result.Unauthorized("没有权限")) + panic(result.UNAUTHORIZED) } this.imageCacheDao.Delete(imageCache) - return this.Success("删除成功!") + return this.Success("OK") } -//删除一系列图片缓存。 func (this *ImageCacheController) DeleteBatch(writer http.ResponseWriter, request *http.Request) *result.WebResult { uuids := request.FormValue("uuids") @@ -156,15 +145,14 @@ func (this *ImageCacheController) DeleteBatch(writer http.ResponseWriter, reques imageCache := this.imageCacheDao.FindByUuid(uuid) - //判断图片缓存的所属人是否正确 user := this.checkUser(request) if imageCache.UserUuid != user.Uuid { - panic(result.Unauthorized("没有权限")) + panic(result.UNAUTHORIZED) } this.imageCacheDao.Delete(imageCache) } - return this.Success("删除成功!") + return this.Success("OK") } diff --git a/code/rest/image_cache_dao.go b/code/rest/image_cache_dao.go index 1886be9..f9a44dc 100644 --- a/code/rest/image_cache_dao.go +++ b/code/rest/image_cache_dao.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/eyebluecn/tank/code/core" "github.com/eyebluecn/tank/code/tool/builder" + "github.com/eyebluecn/tank/code/tool/result" "github.com/eyebluecn/tank/code/tool/util" "github.com/jinzhu/gorm" "github.com/nu7hatch/gouuid" @@ -16,31 +17,30 @@ type ImageCacheDao struct { BaseDao } -//按照Id查询文件 +//find by uuid. if not found return nil. func (this *ImageCacheDao) FindByUuid(uuid string) *ImageCache { - - // Read - var imageCache ImageCache - db := core.CONTEXT.GetDB().Where(&ImageCache{Base: Base{Uuid: uuid}}).First(&imageCache) + var entity = &ImageCache{} + db := core.CONTEXT.GetDB().Where("uuid = ?", uuid).First(entity) if db.Error != nil { - return nil + if db.Error.Error() == result.DB_ERROR_NOT_FOUND { + return nil + } else { + panic(db.Error) + } } - return &imageCache + return entity } -//按照Id查询文件 +//find by uuid. if not found panic NotFound error func (this *ImageCacheDao) CheckByUuid(uuid string) *ImageCache { - - // Read - var imageCache ImageCache - db := core.CONTEXT.GetDB().Where(&ImageCache{Base: Base{Uuid: uuid}}).First(&imageCache) - this.PanicError(db.Error) - - return &imageCache + entity := this.FindByUuid(uuid) + if entity == nil { + panic(result.NotFound("not found record with uuid = %s", uuid)) + } + return entity } -//按照名字查询文件夹 func (this *ImageCacheDao) FindByMatterUuidAndMode(matterUuid string, mode string) *ImageCache { var wp = &builder.WherePair{} @@ -63,7 +63,6 @@ func (this *ImageCacheDao) FindByMatterUuidAndMode(matterUuid string, mode strin return imageCache } -//按照id和userUuid来查找。找不到抛异常。 func (this *ImageCacheDao) CheckByUuidAndUserUuid(uuid string, userUuid string) *ImageCache { // Read @@ -75,8 +74,7 @@ func (this *ImageCacheDao) CheckByUuidAndUserUuid(uuid string, userUuid string) } -//获取某个用户的某个文件夹下的某个名字的文件(或文件夹)列表 -func (this *ImageCacheDao) ListByUserUuidAndPuuidAndDirAndName(userUuid string) []*ImageCache { +func (this *ImageCacheDao) FindByUserUuidAndPuuidAndDirAndName(userUuid string) []*ImageCache { var imageCaches []*ImageCache @@ -88,7 +86,6 @@ func (this *ImageCacheDao) ListByUserUuidAndPuuidAndDirAndName(userUuid string) return imageCaches } -//获取某个文件夹下所有的文件和子文件 func (this *ImageCacheDao) Page(page int, pageSize int, userUuid string, matterUuid string, sortArray []builder.OrderPair) *Pager { var wp = &builder.WherePair{} @@ -116,7 +113,6 @@ func (this *ImageCacheDao) Page(page int, pageSize int, userUuid string, matterU return pager } -//创建 func (this *ImageCacheDao) Create(imageCache *ImageCache) *ImageCache { timeUUID, _ := uuid.NewV4() @@ -130,7 +126,6 @@ func (this *ImageCacheDao) Create(imageCache *ImageCache) *ImageCache { return imageCache } -//修改一个文件 func (this *ImageCacheDao) Save(imageCache *ImageCache) *ImageCache { imageCache.UpdateTime = time.Now() @@ -140,25 +135,24 @@ func (this *ImageCacheDao) Save(imageCache *ImageCache) *ImageCache { return imageCache } -//删除一个文件包括文件夹 func (this *ImageCacheDao) deleteFileAndDir(imageCache *ImageCache) { filePath := GetUserCacheRootDir(imageCache.Username) + imageCache.Path dirPath := filepath.Dir(filePath) - //删除文件 + //delete file from disk. err := os.Remove(filePath) if err != nil { - this.logger.Error(fmt.Sprintf("删除磁盘上的文件%s出错 %s", filePath, err.Error())) + this.logger.Error(fmt.Sprintf("error while deleting %s from disk %s", filePath, err.Error())) } - //如果这一层文件夹是空的,那么删除文件夹本身。 + //if this level is empty. Delete the directory util.DeleteEmptyDirRecursive(dirPath) } -//删除一个文件,数据库中删除,物理磁盘上删除。 +//delete a file from db and disk. func (this *ImageCacheDao) Delete(imageCache *ImageCache) { db := core.CONTEXT.GetDB().Delete(&imageCache) @@ -168,42 +162,50 @@ func (this *ImageCacheDao) Delete(imageCache *ImageCache) { } -//删除一个matter对应的所有缓存 +//delete all the cache of a matter. func (this *ImageCacheDao) DeleteByMatterUuid(matterUuid string) { var wp = &builder.WherePair{} wp = wp.And(&builder.WherePair{Query: "matter_uuid = ?", Args: []interface{}{matterUuid}}) - //查询出即将删除的图片缓存 var imageCaches []*ImageCache db := core.CONTEXT.GetDB().Where(wp.Query, wp.Args).Find(&imageCaches) this.PanicError(db.Error) - //删除文件记录 + //delete from db. db = core.CONTEXT.GetDB().Where(wp.Query, wp.Args).Delete(ImageCache{}) this.PanicError(db.Error) - //删除文件实体 + //delete from disk. for _, imageCache := range imageCaches { this.deleteFileAndDir(imageCache) } } -//获取一段时间中文件总大小 func (this *ImageCacheDao) SizeBetweenTime(startTime time.Time, endTime time.Time) int64 { + + var wp = &builder.WherePair{Query: "create_time >= ? AND create_time <= ?", Args: []interface{}{startTime, endTime}} + + var count int64 + db := core.CONTEXT.GetDB().Model(&ImageCache{}).Where(wp.Query, wp.Args...).Count(&count) + if count == 0 { + return 0 + } + var size int64 - db := core.CONTEXT.GetDB().Model(&ImageCache{}).Where("create_time >= ? AND create_time <= ?", startTime, endTime).Select("SUM(size)") + db = core.CONTEXT.GetDB().Model(&ImageCache{}).Where("create_time >= ? AND create_time <= ?", startTime, endTime).Select("SUM(size)") this.PanicError(db.Error) row := db.Row() - row.Scan(&size) + err := row.Scan(&size) + this.PanicError(err) return size } -//执行清理操作 +//System cleanup. func (this *ImageCacheDao) Cleanup() { - this.logger.Info("[ImageCacheDao]执行清理:清除数据库中所有ImageCache记录。") + this.logger.Info("[ImageCacheDao]clean up. Delete all ImageCache ") db := core.CONTEXT.GetDB().Where("uuid is not null").Delete(ImageCache{}) this.PanicError(db.Error) } diff --git a/code/rest/image_cache_model.go b/code/rest/image_cache_model.go index 0eceaed..bc9c26e 100644 --- a/code/rest/image_cache_model.go +++ b/code/rest/image_cache_model.go @@ -5,7 +5,7 @@ import ( ) /** - * 图片缓存,对于那些处理过的图片,统一管理在这里。 + * image cache. */ type ImageCache struct { Base @@ -26,7 +26,7 @@ func (this *ImageCache) TableName() string { return core.TABLE_PREFIX + "image_cache" } -// 获取该ImageCache的绝对路径。path代表的是相对路径。 +// get the absolute path. path in db means relative path. func (this *ImageCache) AbsolutePath() string { return GetUserCacheRootDir(this.Username) + this.Path } diff --git a/code/rest/image_cache_service.go b/code/rest/image_cache_service.go index 1bdc0a3..e232b33 100644 --- a/code/rest/image_cache_service.go +++ b/code/rest/image_cache_service.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/disintegration/imaging" "github.com/eyebluecn/tank/code/core" + "github.com/eyebluecn/tank/code/tool/result" "github.com/eyebluecn/tank/code/tool/util" "image" "net/http" @@ -21,11 +22,9 @@ type ImageCacheService struct { matterDao *MatterDao } -//初始化方法 func (this *ImageCacheService) Init() { this.BaseBean.Init() - //手动装填本实例的Bean. 这里必须要用中间变量方可。 b := core.CONTEXT.GetBean(this.imageCacheDao) if b, ok := b.(*ImageCacheDao); ok { this.imageCacheDao = b @@ -43,7 +42,6 @@ func (this *ImageCacheService) Init() { } -//获取某个文件的详情,会把父级依次倒着装进去。如果中途出错,直接抛出异常。 func (this *ImageCacheService) Detail(uuid string) *ImageCache { imageCache := this.imageCacheDao.CheckByUuid(uuid) @@ -51,52 +49,23 @@ func (this *ImageCacheService) Detail(uuid string) *ImageCache { return imageCache } -//获取预处理时必要的参数 +// prepare the resize parameters. func (this *ImageCacheService) ResizeParams(request *http.Request) (needProcess bool, resizeMode string, resizeWidth int, resizeHeight int) { var err error - //1.0 模式准备逐步废弃掉 - if request.FormValue("imageProcess") == "resize" { - //老模式使用 imageResizeM,imageResizeW,imageResizeH - imageResizeM := request.FormValue("imageResizeM") - if imageResizeM == "" { - imageResizeM = "fit" - } else if imageResizeM != "fit" && imageResizeM != "fill" && imageResizeM != "fixed" { - panic("imageResizeM参数错误") - } - imageResizeWStr := request.FormValue("imageResizeW") - var imageResizeW int - if imageResizeWStr != "" { - imageResizeW, err = strconv.Atoi(imageResizeWStr) - this.PanicError(err) - if imageResizeW < 1 || imageResizeW > 4096 { - panic("缩放尺寸不能超过4096") - } - } - imageResizeHStr := request.FormValue("imageResizeH") - var imageResizeH int - if imageResizeHStr != "" { - imageResizeH, err = strconv.Atoi(imageResizeHStr) - this.PanicError(err) - if imageResizeH < 1 || imageResizeH > 4096 { - panic("缩放尺寸不能超过4096") - } - } - - return true, imageResizeM, imageResizeW, imageResizeH - } else if request.FormValue("ir") != "" { - //新模式使用 mode_w_h 如果w或者h为0表示这项值不设置 + if request.FormValue("ir") != "" { + //mode_w_h if w or h equal means not required. imageResizeStr := request.FormValue("ir") arr := strings.Split(imageResizeStr, "_") if len(arr) != 3 { - panic("参数不符合规范,格式要求为mode_w_h") + panic(result.BadRequest("param error. the format is mode_w_h")) } imageResizeM := arr[0] if imageResizeM == "" { imageResizeM = "fit" } else if imageResizeM != "fit" && imageResizeM != "fill" && imageResizeM != "fixed" { - panic("imageResizeM参数错误") + panic(result.BadRequest("mode can only be fit/fill/fixed")) } imageResizeWStr := arr[1] var imageResizeW int @@ -104,7 +73,7 @@ func (this *ImageCacheService) ResizeParams(request *http.Request) (needProcess imageResizeW, err = strconv.Atoi(imageResizeWStr) this.PanicError(err) if imageResizeW < 0 || imageResizeW > 4096 { - panic("缩放尺寸不能超过4096") + panic(result.BadRequest("zoom size cannot exceed 4096")) } } imageResizeHStr := arr[2] @@ -113,7 +82,7 @@ func (this *ImageCacheService) ResizeParams(request *http.Request) (needProcess imageResizeH, err = strconv.Atoi(imageResizeHStr) this.PanicError(err) if imageResizeH < 0 || imageResizeH > 4096 { - panic("缩放尺寸不能超过4096") + panic(result.BadRequest("zoom size cannot exceed 4096")) } } return true, imageResizeM, imageResizeW, imageResizeH @@ -123,7 +92,7 @@ func (this *ImageCacheService) ResizeParams(request *http.Request) (needProcess } -//图片预处理功能。 +//resize image. func (this *ImageCacheService) ResizeImage(request *http.Request, filePath string) *image.NRGBA { diskFile, err := os.Open(filePath) @@ -135,52 +104,54 @@ func (this *ImageCacheService) ResizeImage(request *http.Request, filePath strin _, imageResizeM, imageResizeW, imageResizeH := this.ResizeParams(request) - //单边缩略 if imageResizeM == "fit" { - //将图缩略成宽度为100,高度按比例处理。 + //fit mode. if imageResizeW != 0 { + //eg. width = 100 height auto in proportion + src, err := imaging.Decode(diskFile) this.PanicError(err) return imaging.Resize(src, imageResizeW, 0, imaging.Lanczos) } else if imageResizeH != 0 { - //将图缩略成高度为100,宽度按比例处理。 + //eg. height = 100 width auto in proportion + src, err := imaging.Decode(diskFile) this.PanicError(err) return imaging.Resize(src, 0, imageResizeH, imaging.Lanczos) } else { - panic("单边缩略必须指定宽或者高") + panic(result.BadRequest("mode fit required width or height")) } } else if imageResizeM == "fill" { - //固定宽高,自动裁剪 + //fill mode. specify the width and height if imageResizeW > 0 && imageResizeH > 0 { src, err := imaging.Decode(diskFile) this.PanicError(err) return imaging.Fill(src, imageResizeW, imageResizeH, imaging.Center, imaging.Lanczos) } else { - panic("固定宽高,自动裁剪 必须同时指定宽和高") + panic(result.BadRequest("mode fill required width and height")) } } else if imageResizeM == "fixed" { - //强制宽高缩略 + //fixed mode if imageResizeW > 0 && imageResizeH > 0 { src, err := imaging.Decode(diskFile) this.PanicError(err) return imaging.Resize(src, imageResizeW, imageResizeH, imaging.Lanczos) } else { - panic("强制宽高缩略必须同时指定宽和高") + panic(result.BadRequest("mode fixed required width and height")) } } else { - panic("不支持" + imageResizeM + "处理模式") + panic(result.BadRequest("not support mode %s", imageResizeM)) } } -//缓存一张图片 +//cache an image func (this *ImageCacheService) cacheImage(writer http.ResponseWriter, request *http.Request, matter *Matter) *ImageCache { - //当前的文件是否是图片,只有图片才能处理。 + //only these image can do. extension := util.GetExtension(matter.Name) formats := map[string]imaging.Format{ ".jpg": imaging.JPEG, @@ -197,19 +168,18 @@ func (this *ImageCacheService) cacheImage(writer http.ResponseWriter, request *h format, ok := formats[extension] if !ok { - panic("该图片格式不支持处理") + panic(result.BadRequest("not support this kind of image's (%s) resize", extension)) } user := this.userDao.FindByUuid(matter.UserUuid) - //resize图片 dstImage := this.ResizeImage(request, matter.AbsolutePath()) cacheImageName := util.GetSimpleFileName(matter.Name) + "_" + mode + extension cacheImageRelativePath := util.GetSimpleFileName(matter.Path) + "_" + mode + extension cacheImageAbsolutePath := GetUserCacheRootDir(user.Username) + util.GetSimpleFileName(matter.Path) + "_" + mode + extension - //创建目录。 + //create directory dir := filepath.Dir(cacheImageAbsolutePath) util.MakeDirAll(dir) @@ -220,15 +190,13 @@ func (this *ImageCacheService) cacheImage(writer http.ResponseWriter, request *h this.PanicError(e) }() - //处理后的图片存放在本地 + //store on disk after handle err = imaging.Encode(fileWriter, dstImage, format) this.PanicError(err) - //获取新文件的大小 fileInfo, err := fileWriter.Stat() this.PanicError(err) - //相关信息写到缓存中去 imageCache := &ImageCache{ Name: cacheImageName, UserUuid: matter.UserUuid, diff --git a/code/rest/install_controller.go b/code/rest/install_controller.go index 45f64c1..5f4b675 100644 --- a/code/rest/install_controller.go +++ b/code/rest/install_controller.go @@ -9,15 +9,13 @@ import ( "github.com/eyebluecn/tank/code/tool/util" "github.com/jinzhu/gorm" "github.com/nu7hatch/gouuid" - "go/build" - "io/ioutil" "net/http" "regexp" "strconv" "time" ) -//安装程序的接口,只有安装阶段可以访问。 +//install apis. Only when installing period can be visited. type InstallController struct { BaseController uploadTokenDao *UploadTokenDao @@ -29,11 +27,9 @@ type InstallController struct { tableNames []IBase } -//初始化方法 func (this *InstallController) Init() { this.BaseController.Init() - //手动装填本实例的Bean. b := core.CONTEXT.GetBean(this.uploadTokenDao) if c, ok := b.(*UploadTokenDao); ok { this.uploadTokenDao = c @@ -80,12 +76,10 @@ func (this *InstallController) Init() { } -//注册自己的路由。 func (this *InstallController) RegisterRoutes() map[string]func(writer http.ResponseWriter, request *http.Request) { routeMap := make(map[string]func(writer http.ResponseWriter, request *http.Request)) - //每个Controller需要主动注册自己的路由。 routeMap["/api/install/verify"] = this.Wrap(this.Verify, USER_ROLE_GUEST) routeMap["/api/install/table/info/list"] = this.Wrap(this.TableInfoList, USER_ROLE_GUEST) routeMap["/api/install/create/table"] = this.Wrap(this.CreateTable, USER_ROLE_GUEST) @@ -97,7 +91,6 @@ func (this *InstallController) RegisterRoutes() map[string]func(writer http.Resp return routeMap } -//获取数据库连接 func (this *InstallController) openDbConnection(writer http.ResponseWriter, request *http.Request) *gorm.DB { mysqlPortStr := request.FormValue("mysqlPort") mysqlHost := request.FormValue("mysqlHost") @@ -114,7 +107,7 @@ func (this *InstallController) openDbConnection(writer http.ResponseWriter, requ mysqlUrl := util.GetMysqlUrl(mysqlPort, mysqlHost, mysqlSchema, mysqlUsername, mysqlPassword) - this.logger.Info("连接MySQL %s", mysqlUrl) + this.logger.Info("Connect MySQL %s", mysqlUrl) var err error = nil db, err := gorm.Open("mysql", mysqlUrl) @@ -126,50 +119,18 @@ func (this *InstallController) openDbConnection(writer http.ResponseWriter, requ } -//关闭数据库连接 func (this *InstallController) closeDbConnection(db *gorm.DB) { if db != nil { err := db.Close() if err != nil { - this.logger.Error("关闭数据库连接出错 %v", err) + this.logger.Error("occur error when close db. %v", err) } } } -//根据表名获取建表SQL语句 -func (this *InstallController) getCreateSQLFromFile(tableName string) string { - - //1. 从当前安装目录db下去寻找建表文件。 - homePath := util.GetHomePath() - filePath := homePath + "/db/" + tableName + ".sql" - exists := util.PathExists(filePath) - - //2. 从GOPATH下面去找,因为可能是开发环境 - if !exists { - - this.logger.Info("GOPATH = %s", build.Default.GOPATH) - - filePath1 := filePath - filePath = build.Default.GOPATH + "/src/tank/build/db/" + tableName + ".sql" - exists = util.PathExists(filePath) - - if !exists { - panic(result.Server("%s 或 %s 均不存在,请检查你的安装情况。", filePath1, filePath)) - } - } - - //读取文件内容. - bytes, err := ioutil.ReadFile(filePath) - this.PanicError(err) - - return string(bytes) -} - -//根据表名获取建表SQL语句 func (this *InstallController) getTableMeta(gormDb *gorm.DB, entity IBase) (bool, []*gorm.StructField, []*gorm.StructField) { - //挣扎一下,尝试获取建表语句。 db := gormDb.Unscoped() scope := db.NewScope(entity) @@ -197,7 +158,6 @@ func (this *InstallController) getTableMeta(gormDb *gorm.DB, entity IBase) (bool } -//根据表名获取建表SQL语句 func (this *InstallController) getTableMetaList(db *gorm.DB) []*InstallTableInfo { var installTableInfos []*InstallTableInfo @@ -215,7 +175,7 @@ func (this *InstallController) getTableMetaList(db *gorm.DB) []*InstallTableInfo return installTableInfos } -//验证表结构是否完整。会直接抛出异常 +// validate table whether integrity. if not panic err. func (this *InstallController) validateTableMetaList(tableInfoList []*InstallTableInfo) { for _, tableInfo := range tableInfoList { @@ -236,20 +196,19 @@ func (this *InstallController) validateTableMetaList(tableInfoList []*InstallTab } -//验证数据库连接 +//Ping db. func (this *InstallController) Verify(writer http.ResponseWriter, request *http.Request) *result.WebResult { db := this.openDbConnection(writer, request) defer this.closeDbConnection(db) - this.logger.Info("Ping一下数据库") + this.logger.Info("Ping DB") err := db.DB().Ping() this.PanicError(err) return this.Success("OK") } -//获取需要安装的数据库表 func (this *InstallController) TableInfoList(writer http.ResponseWriter, request *http.Request) *result.WebResult { db := this.openDbConnection(writer, request) @@ -258,7 +217,6 @@ func (this *InstallController) TableInfoList(writer http.ResponseWriter, request return this.Success(this.getTableMetaList(db)) } -//创建缺失数据库和表 func (this *InstallController) CreateTable(writer http.ResponseWriter, request *http.Request) *result.WebResult { var installTableInfos []*InstallTableInfo @@ -268,7 +226,7 @@ func (this *InstallController) CreateTable(writer http.ResponseWriter, request * for _, iBase := range this.tableNames { - //补全缺失字段或者创建数据库表 + //complete the missing fields or create table. db1 := db.AutoMigrate(iBase) this.PanicError(db1.Error) @@ -286,7 +244,7 @@ func (this *InstallController) CreateTable(writer http.ResponseWriter, request * } -//获取管理员列表(10条记录) +//get the list of admin. func (this *InstallController) AdminList(writer http.ResponseWriter, request *http.Request) *result.WebResult { db := this.openDbConnection(writer, request) @@ -304,7 +262,7 @@ func (this *InstallController) AdminList(writer http.ResponseWriter, request *ht return this.Success(users) } -//创建管理员 +//create admin func (this *InstallController) CreateAdmin(writer http.ResponseWriter, request *http.Request) *result.WebResult { db := this.openDbConnection(writer, request) @@ -313,7 +271,7 @@ func (this *InstallController) CreateAdmin(writer http.ResponseWriter, request * adminUsername := request.FormValue("adminUsername") adminPassword := request.FormValue("adminPassword") - //验证超级管理员的信息 + //validate admin's username if m, _ := regexp.MatchString(`^[0-9a-zA-Z_]+$`, adminUsername); !m { panic(result.BadRequest(`admin's username cannot oly be alphabet, number or '_'`)) } @@ -322,7 +280,7 @@ func (this *InstallController) CreateAdmin(writer http.ResponseWriter, request * panic(result.BadRequest(`admin's password at least 6 chars'`)) } - //检查是否有重复。 + //check whether duplicate var count2 int64 db2 := db.Model(&User{}).Where("username = ?", adminUsername).Count(&count2) this.PanicError(db2.Error) @@ -350,7 +308,7 @@ func (this *InstallController) CreateAdmin(writer http.ResponseWriter, request * } -//(如果数据库中本身存在管理员了)验证管理员 +//(if there is admin in db)Validate admin. func (this *InstallController) ValidateAdmin(writer http.ResponseWriter, request *http.Request) *result.WebResult { db := this.openDbConnection(writer, request) @@ -359,7 +317,6 @@ func (this *InstallController) ValidateAdmin(writer http.ResponseWriter, request adminUsername := request.FormValue("adminUsername") adminPassword := request.FormValue("adminPassword") - //验证超级管理员的信息 if adminUsername == "" { panic(result.BadRequest(`admin's username cannot be null'`)) } @@ -385,7 +342,7 @@ func (this *InstallController) ValidateAdmin(writer http.ResponseWriter, request } -//完成系统安装 +//Finish the installation func (this *InstallController) Finish(writer http.ResponseWriter, request *http.Request) *result.WebResult { mysqlPortStr := request.FormValue("mysqlPort") @@ -401,15 +358,15 @@ func (this *InstallController) Finish(writer http.ResponseWriter, request *http. mysqlPort = tmp } - //要求数据库连接通畅 + //Recheck the db connection db := this.openDbConnection(writer, request) defer this.closeDbConnection(db) - //要求数据库完整。 + //Recheck the integrity of tables. tableMetaList := this.getTableMetaList(db) this.validateTableMetaList(tableMetaList) - //要求至少有一名管理员。 + //At least one admin var count1 int64 db1 := db.Model(&User{}).Where("role = ?", USER_ROLE_ADMINISTRATOR).Count(&count1) this.PanicError(db1.Error) @@ -417,10 +374,10 @@ func (this *InstallController) Finish(writer http.ResponseWriter, request *http. panic(result.BadRequest(`please config at least one admin user`)) } - //通知配置文件安装完毕。 + //announce the config to write config to tank.json core.CONFIG.FinishInstall(mysqlPort, mysqlHost, mysqlSchema, mysqlUsername, mysqlPassword) - //通知全局上下文,说系统安装好了 + //announce the context to broadcast the installation news to bean. core.CONTEXT.InstallOk() return this.Success("OK") diff --git a/code/rest/install_model.go b/code/rest/install_model.go index 44f4a06..d6ba79b 100644 --- a/code/rest/install_model.go +++ b/code/rest/install_model.go @@ -3,7 +3,7 @@ package rest import "github.com/jinzhu/gorm" /** - * 表名对应的表结构 + * table meta info. */ type InstallTableInfo struct { Name string `json:"name"` diff --git a/code/rest/matter_controller.go b/code/rest/matter_controller.go index 94a90c9..9c79e58 100644 --- a/code/rest/matter_controller.go +++ b/code/rest/matter_controller.go @@ -22,11 +22,9 @@ type MatterController struct { imageCacheService *ImageCacheService } -//初始化方法 start to develop v3. func (this *MatterController) Init() { this.BaseController.Init() - //手动装填本实例的Bean. 这里必须要用中间变量方可。 b := core.CONTEXT.GetBean(this.matterDao) if b, ok := b.(*MatterDao); ok { this.matterDao = b @@ -68,12 +66,10 @@ func (this *MatterController) Init() { } } -//注册自己的路由。 func (this *MatterController) RegisterRoutes() map[string]func(writer http.ResponseWriter, request *http.Request) { routeMap := make(map[string]func(writer http.ResponseWriter, request *http.Request)) - //每个Controller需要主动注册自己的路由。 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) @@ -85,14 +81,13 @@ func (this *MatterController) RegisterRoutes() map[string]func(writer http.Respo routeMap["/api/matter/detail"] = this.Wrap(this.Detail, USER_ROLE_USER) routeMap["/api/matter/page"] = this.Wrap(this.Page, USER_ROLE_GUEST) - //本地文件映射 + //mirror local files. routeMap["/api/matter/mirror"] = this.Wrap(this.Mirror, USER_ROLE_USER) routeMap["/api/matter/zip"] = this.Wrap(this.Zip, USER_ROLE_USER) return routeMap } -//查看某个文件的详情。 func (this *MatterController) Detail(writer http.ResponseWriter, request *http.Request) *result.WebResult { uuid := request.FormValue("uuid") @@ -102,7 +97,6 @@ func (this *MatterController) Detail(writer http.ResponseWriter, request *http.R matter := this.matterService.Detail(request, uuid) - //验证当前之人是否有权限查看这么详细。 user := this.checkUser(request) if matter.UserUuid != user.Uuid { panic(result.UNAUTHORIZED) @@ -112,10 +106,8 @@ func (this *MatterController) Detail(writer http.ResponseWriter, request *http.R } -//按照分页的方式获取某个文件夹下文件和子文件夹的列表,通常情况下只有一页。 func (this *MatterController) Page(writer http.ResponseWriter, request *http.Request) *result.WebResult { - //如果是根目录,那么就传入root. pageStr := request.FormValue("page") pageSizeStr := request.FormValue("pageSize") orderCreateTime := request.FormValue("orderCreateTime") @@ -133,7 +125,7 @@ func (this *MatterController) Page(writer http.ResponseWriter, request *http.Req var userUuid string - //使用分享提取码的形式授权。 + //auth by shareUuid. shareUuid := request.FormValue("shareUuid") shareCode := request.FormValue("shareCode") shareRootUuid := request.FormValue("shareRootUuid") @@ -149,12 +141,12 @@ func (this *MatterController) Page(writer http.ResponseWriter, request *http.Req } user := this.findUser(request) - //根据某个shareUuid和code,某个用户是否有权限获取 shareRootUuid 下面的 matterUuid + this.shareService.ValidateMatter(shareUuid, shareCode, user, shareRootUuid, dirMatter) userUuid = dirMatter.Uuid } else { - //非分享模式要求必须登录 + //if cannot auth by share. Then login is required. user := this.checkUser(request) userUuid = user.Uuid @@ -173,7 +165,6 @@ func (this *MatterController) Page(writer http.ResponseWriter, request *http.Req } } - //筛选后缀名 var extensions []string if extensionsStr != "" { extensions = strings.Split(extensionsStr, ",") @@ -215,28 +206,19 @@ func (this *MatterController) Page(writer http.ResponseWriter, request *http.Req return this.Success(pager) } -//创建一个文件夹。 func (this *MatterController) CreateDirectory(writer http.ResponseWriter, request *http.Request) *result.WebResult { puuid := request.FormValue("puuid") name := request.FormValue("name") - //管理员可以指定给某个用户创建文件夹。 user := this.checkUser(request) - //找到父级matter - var dirMatter *Matter - if puuid == MATTER_ROOT { - dirMatter = NewRootMatter(user) - } else { - dirMatter = this.matterDao.CheckByUuid(puuid) - } + var dirMatter = this.matterDao.CheckWithRootByUuid(puuid, user) matter := this.matterService.AtomicCreateDirectory(request, dirMatter, name, user) return this.Success(matter) } -//上传文件 func (this *MatterController) Upload(writer http.ResponseWriter, request *http.Request) *result.WebResult { puuid := request.FormValue("puuid") @@ -255,7 +237,7 @@ func (this *MatterController) Upload(writer http.ResponseWriter, request *http.R err = request.ParseMultipartForm(32 << 20) this.PanicError(err) - //对于IE浏览器,filename可能包含了路径。 + //for IE browser. filename may contains filepath. fileName := handler.Filename pos := strings.LastIndex(fileName, "\\") if pos != -1 { @@ -268,13 +250,13 @@ func (this *MatterController) Upload(writer http.ResponseWriter, request *http.R dirMatter := this.matterDao.CheckWithRootByUuid(puuid, user) - //为了支持多文件同时上传 + //support upload simultaneously matter := this.matterService.Upload(request, file, user, dirMatter, fileName, privacy) return this.Success(matter) } -//从一个Url中去爬取资源 +//crawl a file by url. func (this *MatterController) Crawl(writer http.ResponseWriter, request *http.Request) *result.WebResult { url := request.FormValue("url") @@ -286,11 +268,11 @@ func (this *MatterController) Crawl(writer http.ResponseWriter, request *http.Re dirMatter := this.matterService.CreateDirectories(request, user, destPath) if url == "" || (!strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://")) { - panic("资源url必填,并且应该以http://或者https://开头") + panic(" url must start with http:// or https://") } if filename == "" { - panic("filename 必填") + panic("filename cannot be null") } matter := this.matterService.AtomicCrawl(request, url, filename, user, dirMatter, true) @@ -298,7 +280,6 @@ func (this *MatterController) Crawl(writer http.ResponseWriter, request *http.Re return this.Success(matter) } -//删除一个文件 func (this *MatterController) Delete(writer http.ResponseWriter, request *http.Request) *result.WebResult { uuid := request.FormValue("uuid") @@ -308,7 +289,6 @@ func (this *MatterController) Delete(writer http.ResponseWriter, request *http.R matter := this.matterDao.CheckByUuid(uuid) - //判断文件的所属人是否正确 user := this.checkUser(request) if matter.UserUuid != user.Uuid { panic(result.UNAUTHORIZED) @@ -316,10 +296,9 @@ func (this *MatterController) Delete(writer http.ResponseWriter, request *http.R this.matterService.AtomicDelete(request, matter) - return this.Success("删除成功!") + return this.Success("OK") } -//删除一系列文件。 func (this *MatterController) DeleteBatch(writer http.ResponseWriter, request *http.Request) *result.WebResult { uuids := request.FormValue("uuids") @@ -333,13 +312,11 @@ func (this *MatterController) DeleteBatch(writer http.ResponseWriter, request *h matter := this.matterDao.FindByUuid(uuid) - //如果matter已经是nil了,直接跳过 if matter == nil { this.logger.Warn("%s not exist anymore", uuid) continue } - //判断文件的所属人是否正确 user := this.checkUser(request) if matter.UserUuid != user.Uuid { panic(result.UNAUTHORIZED) @@ -349,10 +326,9 @@ func (this *MatterController) DeleteBatch(writer http.ResponseWriter, request *h } - return this.Success("删除成功!") + return this.Success("OK") } -//重命名一个文件或一个文件夹 func (this *MatterController) Rename(writer http.ResponseWriter, request *http.Request) *result.WebResult { uuid := request.FormValue("uuid") @@ -360,7 +336,6 @@ func (this *MatterController) Rename(writer http.ResponseWriter, request *http.R user := this.checkUser(request) - //找出该文件或者文件夹 matter := this.matterDao.CheckByUuid(uuid) if matter.UserUuid != user.Uuid { @@ -372,7 +347,6 @@ func (this *MatterController) Rename(writer http.ResponseWriter, request *http.R return this.Success(matter) } -//改变一个文件的公私有属性 func (this *MatterController) ChangePrivacy(writer http.ResponseWriter, request *http.Request) *result.WebResult { uuid := request.FormValue("uuid") privacyStr := request.FormValue("privacy") @@ -380,14 +354,13 @@ func (this *MatterController) ChangePrivacy(writer http.ResponseWriter, request if privacyStr == TRUE { privacy = true } - //找出该文件或者文件夹 + matter := this.matterDao.CheckByUuid(uuid) if matter.Privacy == privacy { - panic("公私有属性没有改变!") + panic(result.BadRequest("not changed. Invalid operation.")) } - //权限验证 user := this.checkUser(request) if matter.UserUuid != user.Uuid { panic(result.UNAUTHORIZED) @@ -396,17 +369,15 @@ func (this *MatterController) ChangePrivacy(writer http.ResponseWriter, request matter.Privacy = privacy this.matterDao.Save(matter) - return this.Success("设置成功") + return this.Success("OK") } -//将一个文件夹或者文件移入到另一个文件夹下。 func (this *MatterController) Move(writer http.ResponseWriter, request *http.Request) *result.WebResult { srcUuidsStr := request.FormValue("srcUuids") destUuid := request.FormValue("destUuid") var srcUuids []string - //验证参数。 if srcUuidsStr == "" { panic(result.BadRequest("srcUuids cannot be null")) } else { @@ -415,7 +386,6 @@ func (this *MatterController) Move(writer http.ResponseWriter, request *http.Req user := this.checkUser(request) - //验证dest是否有问题 var destMatter = this.matterDao.CheckWithRootByUuid(destUuid, user) if !destMatter.Dir { panic(result.BadRequest("destination is not a directory")) @@ -426,23 +396,20 @@ func (this *MatterController) Move(writer http.ResponseWriter, request *http.Req } var srcMatters []*Matter - //验证src是否有问题。 for _, uuid := range srcUuids { - //找出该文件或者文件夹 srcMatter := this.matterDao.CheckByUuid(uuid) if srcMatter.Puuid == destMatter.Uuid { panic(result.BadRequest("no move, invalid operation")) } - //判断同级文件夹中是否有同名的文件 + //check whether there are files with the same name. count := this.matterDao.CountByUserUuidAndPuuidAndDirAndName(user.Uuid, destMatter.Uuid, srcMatter.Dir, srcMatter.Name) if count > 0 { panic(result.BadRequestI18n(request, i18n.MatterExist, srcMatter.Name)) } - //判断和目标文件夹是否是同一个主人。 if srcMatter.UserUuid != destMatter.UserUuid { panic("owner not the same") } @@ -455,7 +422,7 @@ func (this *MatterController) Move(writer http.ResponseWriter, request *http.Req return this.Success(nil) } -//将本地文件映射到蓝眼云盘中去。 +//mirror local files to EyeblueTank func (this *MatterController) Mirror(writer http.ResponseWriter, request *http.Request) *result.WebResult { srcPath := request.FormValue("srcPath") @@ -479,7 +446,7 @@ func (this *MatterController) Mirror(writer http.ResponseWriter, request *http.R } -//下载压缩包 +//download zip. func (this *MatterController) Zip(writer http.ResponseWriter, request *http.Request) *result.WebResult { uuids := request.FormValue("uuids") diff --git a/code/rest/matter_dao.go b/code/rest/matter_dao.go index bfccb3f..0b4d0b0 100644 --- a/code/rest/matter_dao.go +++ b/code/rest/matter_dao.go @@ -17,11 +17,9 @@ type MatterDao struct { bridgeDao *BridgeDao } -//初始化方法 func (this *MatterDao) Init() { this.BaseDao.Init() - //手动装填本实例的Bean. 这里必须要用中间变量方可。 b := core.CONTEXT.GetBean(this.imageCacheDao) if b, ok := b.(*ImageCacheDao); ok { this.imageCacheDao = b @@ -34,32 +32,29 @@ func (this *MatterDao) Init() { } -//按照Id查询文件 func (this *MatterDao) FindByUuid(uuid string) *Matter { - - // Read - var matter Matter - db := core.CONTEXT.GetDB().Where(&Matter{Base: Base{Uuid: uuid}}).First(&matter) + var entity = &Matter{} + db := core.CONTEXT.GetDB().Where("uuid = ?", uuid).First(entity) if db.Error != nil { if db.Error.Error() == result.DB_ERROR_NOT_FOUND { return nil } else { - this.PanicError(db.Error) + panic(db.Error) } } - return &matter + return entity } -//按照Id查询文件 +//find by uuid. if not found panic NotFound error func (this *MatterDao) CheckByUuid(uuid string) *Matter { - matter := this.FindByUuid(uuid) - if matter == nil { - panic(result.NotFound("%s 对应的matter不存在", uuid)) + entity := this.FindByUuid(uuid) + if entity == nil { + panic(result.NotFound("not found record with uuid = %s", uuid)) } - return matter + return entity } -//按照uuid查找一个文件夹,可能返回root对应的matter. +// find by uuid. if uuid=root, then return the Root Matter func (this *MatterDao) CheckWithRootByUuid(uuid string, user *User) *Matter { if uuid == "" { @@ -79,7 +74,7 @@ func (this *MatterDao) CheckWithRootByUuid(uuid string, user *User) *Matter { return matter } -//按照path查找一个matter,可能返回root对应的matter. +// find by path. if path=/, then return the Root Matter func (this *MatterDao) CheckWithRootByPath(path string, user *User) *Matter { var matter *Matter @@ -88,7 +83,6 @@ func (this *MatterDao) CheckWithRootByPath(path string, user *User) *Matter { panic(result.BadRequest("user cannot be null.")) } - //目标文件夹matter if path == "" || path == "/" { matter = NewRootMatter(user) } else { @@ -98,7 +92,6 @@ func (this *MatterDao) CheckWithRootByPath(path string, user *User) *Matter { return matter } -//按照名字查询文件夹 func (this *MatterDao) FindByUserUuidAndPuuidAndNameAndDirTrue(userUuid string, puuid string, name string) *Matter { var wp = &builder.WherePair{} @@ -127,10 +120,8 @@ func (this *MatterDao) FindByUserUuidAndPuuidAndNameAndDirTrue(userUuid string, return matter } -//按照id和userUuid来查找。找不到抛异常。 func (this *MatterDao) CheckByUuidAndUserUuid(uuid string, userUuid string) *Matter { - // Read var matter = &Matter{} db := core.CONTEXT.GetDB().Where(&Matter{Base: Base{Uuid: uuid}, UserUuid: userUuid}).First(matter) this.PanicError(db.Error) @@ -139,7 +130,6 @@ func (this *MatterDao) CheckByUuidAndUserUuid(uuid string, userUuid string) *Mat } -//统计某个用户的某个文件夹下的某个名字的文件(或文件夹)数量。 func (this *MatterDao) CountByUserUuidAndPuuidAndDirAndName(userUuid string, puuid string, dir bool, name string) int { var matter Matter @@ -170,7 +160,6 @@ func (this *MatterDao) CountByUserUuidAndPuuidAndDirAndName(userUuid string, puu return count } -//统计某个用户的某个文件夹下的某个名字的文件(或文件夹)数量。 func (this *MatterDao) FindByUserUuidAndPuuidAndDirAndName(userUuid string, puuid string, dir bool, name string) *Matter { var matter = &Matter{} @@ -204,7 +193,6 @@ func (this *MatterDao) FindByUserUuidAndPuuidAndDirAndName(userUuid string, puui return matter } -//获取某个用户的某个文件夹下的某个名字的文件(或文件夹)列表 func (this *MatterDao) ListByUserUuidAndPuuidAndDirAndName(userUuid string, puuid string, dir bool, name string) []*Matter { var matters []*Matter @@ -217,13 +205,11 @@ func (this *MatterDao) ListByUserUuidAndPuuidAndDirAndName(userUuid string, puui return matters } -//获取某个文件夹下所有的文件和子文件 func (this *MatterDao) ListByPuuidAndUserUuid(puuid string, userUuid string, sortArray []builder.OrderPair) []*Matter { var matters []*Matter if sortArray == nil { - //顺序按照文件夹,创建时间 sortArray = []builder.OrderPair{ { Key: "dir", @@ -242,7 +228,6 @@ func (this *MatterDao) ListByPuuidAndUserUuid(puuid string, userUuid string, sor return matters } -//根据uuid查找对应的Matters func (this *MatterDao) ListByUuids(uuids []string, sortArray []builder.OrderPair) []*Matter { var matters []*Matter @@ -252,7 +237,6 @@ func (this *MatterDao) ListByUuids(uuids []string, sortArray []builder.OrderPair return matters } -//获取某个文件夹下所有的文件和子文件 func (this *MatterDao) Page(page int, pageSize int, puuid string, userUuid string, name string, dir string, extensions []string, sortArray []builder.OrderPair) *Pager { var wp = &builder.WherePair{} @@ -300,7 +284,6 @@ func (this *MatterDao) Page(page int, pageSize int, puuid string, userUuid strin return pager } -//创建 func (this *MatterDao) Create(matter *Matter) *Matter { timeUUID, _ := uuid.NewV4() @@ -314,7 +297,6 @@ func (this *MatterDao) Create(matter *Matter) *Matter { return matter } -//修改一个文件 func (this *MatterDao) Save(matter *Matter) *Matter { matter.UpdateTime = time.Now() @@ -324,13 +306,12 @@ func (this *MatterDao) Save(matter *Matter) *Matter { return matter } -//计数器加一 +//download time add 1 func (this *MatterDao) TimesIncrement(matterUuid string) { db := core.CONTEXT.GetDB().Model(&Matter{}).Where("uuid = ?", matterUuid).Update("times", gorm.Expr("times + 1")) 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}} @@ -351,15 +332,14 @@ func (this *MatterDao) SizeByPuuidAndUserUuid(matterUuid string, userUuid string return sumSize } -//统计某个文件/文件夹的大小(会自动往上统计,直到根目录) +// compute route size. It will compute upward until root directory func (this *MatterDao) ComputeRouteSize(matterUuid string, userUuid string) { - //如果更新到了根目录,那么更新到用户身上。 + //if to root directory, then update to user's info. 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) @@ -368,28 +348,27 @@ func (this *MatterDao) ComputeRouteSize(matterUuid string, userUuid string) { matter := this.CheckByUuid(matterUuid) - //只有文件夹才去统计 + //only compute dir if matter.Dir { - //计算该目录下的直系文件/文件夹总大小 + //compute the total size. size := this.SizeByPuuidAndUserUuid(matterUuid, userUuid) - //大小有变化才更新 + //when changed, we update if matter.Size != size { - //更新大小。 db := core.CONTEXT.GetDB().Model(&Matter{}).Where("uuid = ?", matterUuid).Update("size", size) this.PanicError(db.Error) } } - //更新自己的上一级目录。 + //update parent recursively. this.ComputeRouteSize(matter.Puuid, userUuid) } -//删除一个文件,数据库中删除,物理磁盘上删除。 +//delete a file from db and disk. func (this *MatterDao) Delete(matter *Matter) { - //目录的话递归删除。 + // recursive if dir if matter.Dir { matters := this.ListByPuuidAndUserUuid(matter.Uuid, matter.UserUuid, nil) @@ -397,37 +376,34 @@ func (this *MatterDao) Delete(matter *Matter) { this.Delete(f) } - //删除数据库中文件夹本身 + //delete from db. db := core.CONTEXT.GetDB().Delete(&matter) this.PanicError(db.Error) - //从磁盘中删除该文件夹。 + //delete dir from disk. util.DeleteEmptyDir(matter.AbsolutePath()) } else { - //删除数据库中文件记录 + //delete from db. db := core.CONTEXT.GetDB().Delete(&matter) this.PanicError(db.Error) - //删除对应的缓存图片。 + //delete its image cache. this.imageCacheDao.DeleteByMatterUuid(matter.Uuid) - //删除所有的分享文件 + //delete all the share. this.bridgeDao.DeleteByMatterUuid(matter.Uuid) - //删除文件 + //delete from disk. err := os.Remove(matter.AbsolutePath()) if err != nil { - this.logger.Error("删除磁盘上的文件出错 %s", err.Error()) + this.logger.Error("occur error when deleting file. %v", err) } - //由于目录和物理结构一一对应,这里不能删除上级文件夹。 - } } -//获取一段时间中,总的数量 func (this *MatterDao) CountBetweenTime(startTime time.Time, endTime time.Time) int64 { var count int64 db := core.CONTEXT.GetDB().Model(&Matter{}).Where("create_time >= ? AND create_time <= ?", startTime, endTime).Count(&count) @@ -435,12 +411,18 @@ func (this *MatterDao) CountBetweenTime(startTime time.Time, endTime time.Time) return count } -//获取一段时间中文件总大小 func (this *MatterDao) SizeBetweenTime(startTime time.Time, endTime time.Time) int64 { - //TODO: 所有函数汇总的SQL均需要先count询问,再处理。 + var wp = &builder.WherePair{Query: "create_time >= ? AND create_time <= ?", Args: []interface{}{startTime, endTime}} + + var count int64 + db := core.CONTEXT.GetDB().Model(&Matter{}).Where(wp.Query, wp.Args...).Count(&count) + if count == 0 { + return 0 + } + var size int64 - db := core.CONTEXT.GetDB().Model(&Matter{}).Where("create_time >= ? AND create_time <= ?", startTime, endTime).Select("SUM(size)") + db = core.CONTEXT.GetDB().Model(&Matter{}).Where(wp.Query, wp.Args...).Select("SUM(size)") this.PanicError(db.Error) row := db.Row() err := row.Scan(&size) @@ -448,7 +430,6 @@ func (this *MatterDao) SizeBetweenTime(startTime time.Time, endTime time.Time) i return size } -//根据userUuid和path来查找 func (this *MatterDao) findByUserUuidAndPath(userUuid string, path string) *Matter { var wp = &builder.WherePair{Query: "user_uuid = ? AND path = ?", Args: []interface{}{userUuid, path}} @@ -467,7 +448,6 @@ func (this *MatterDao) findByUserUuidAndPath(userUuid string, path string) *Matt return matter } -//根据userUuid和path来查找 func (this *MatterDao) checkByUserUuidAndPath(userUuid string, path string) *Matter { if path == "" { @@ -481,7 +461,6 @@ func (this *MatterDao) checkByUserUuidAndPath(userUuid string, path string) *Mat return matter } -//获取一个文件夹中文件总大小 func (this *MatterDao) SumSizeByUserUuidAndPath(userUuid string, path string) int64 { var wp = &builder.WherePair{Query: "user_uuid = ? AND path like ?", Args: []interface{}{userUuid, path + "%"}} @@ -503,7 +482,6 @@ func (this *MatterDao) SumSizeByUserUuidAndPath(userUuid string, path string) in } -//一个文件夹中的数量 func (this *MatterDao) CountByUserUuidAndPath(userUuid string, path string) int64 { var wp = &builder.WherePair{Query: "user_uuid = ? AND path like ?", Args: []interface{}{userUuid, path + "%"}} @@ -516,9 +494,9 @@ func (this *MatterDao) CountByUserUuidAndPath(userUuid string, path string) int6 } -//执行清理操作 +//System cleanup. func (this *MatterDao) Cleanup() { - this.logger.Info("[MatterDao]执行清理:清除数据库中所有Matter记录。删除磁盘中所有Matter文件。") + this.logger.Info("[MatterDao] clean up. Delete all Matter record in db and on disk.") db := core.CONTEXT.GetDB().Where("uuid is not null").Delete(Matter{}) this.PanicError(db.Error) diff --git a/code/rest/matter_model.go b/code/rest/matter_model.go index 806e8f3..ac9fc6d 100644 --- a/code/rest/matter_model.go +++ b/code/rest/matter_model.go @@ -7,9 +7,9 @@ import ( ) const ( - //根目录的uuid + //root matter's uuid MATTER_ROOT = "root" - //cache文件夹名称 + //cache directory name. MATTER_CACHE = "cache" //压缩文件的临时目录 MATTER_ZIP = "zip" diff --git a/code/rest/matter_service.go b/code/rest/matter_service.go index 867a0ba..77f4ff4 100644 --- a/code/rest/matter_service.go +++ b/code/rest/matter_service.go @@ -32,11 +32,9 @@ type MatterService struct { preferenceService *PreferenceService } -//初始化方法 func (this *MatterService) Init() { this.BaseBean.Init() - //手动装填本实例的Bean. 这里必须要用中间变量方可。 b := core.CONTEXT.GetBean(this.matterDao) if b, ok := b.(*MatterDao); ok { this.matterDao = b @@ -368,20 +366,6 @@ func (this *MatterService) Upload(request *http.Request, file io.Reader, user *U return matter } -//上传文件 -func (this *MatterService) AtomicUpload(request *http.Request, file io.Reader, user *User, dirMatter *Matter, filename string, privacy bool) *Matter { - - if user == nil { - panic(result.BadRequest("user cannot be nil.")) - } - - //操作锁 - this.userService.MatterLock(user.Uuid) - defer this.userService.MatterUnlock(user.Uuid) - - return this.Upload(request, file, user, dirMatter, filename, privacy) -} - //内部创建文件,不带操作锁。 func (this *MatterService) createDirectory(request *http.Request, dirMatter *Matter, name string, user *User) *Matter { diff --git a/code/rest/preference_controller.go b/code/rest/preference_controller.go index 5634abe..3656af0 100644 --- a/code/rest/preference_controller.go +++ b/code/rest/preference_controller.go @@ -14,11 +14,9 @@ type PreferenceController struct { preferenceService *PreferenceService } -//初始化方法 func (this *PreferenceController) Init() { this.BaseController.Init() - //手动装填本实例的Bean. 这里必须要用中间变量方可。 b := core.CONTEXT.GetBean(this.preferenceDao) if b, ok := b.(*PreferenceDao); ok { this.preferenceDao = b @@ -31,12 +29,10 @@ func (this *PreferenceController) Init() { } -//注册自己的路由。 func (this *PreferenceController) RegisterRoutes() map[string]func(writer http.ResponseWriter, request *http.Request) { routeMap := make(map[string]func(writer http.ResponseWriter, request *http.Request)) - //每个Controller需要主动注册自己的路由。 routeMap["/api/preference/ping"] = this.Wrap(this.Ping, USER_ROLE_GUEST) routeMap["/api/preference/fetch"] = this.Wrap(this.Fetch, USER_ROLE_GUEST) routeMap["/api/preference/edit"] = this.Wrap(this.Edit, USER_ROLE_ADMINISTRATOR) diff --git a/code/rest/preference_dao.go b/code/rest/preference_dao.go index 96a5d59..38c5879 100644 --- a/code/rest/preference_dao.go +++ b/code/rest/preference_dao.go @@ -11,7 +11,7 @@ type PreferenceDao struct { BaseDao } -//按照Id查询偏好设置 +//find by uuid. if not found return nil. func (this *PreferenceDao) Fetch() *Preference { // Read @@ -57,10 +57,10 @@ func (this *PreferenceDao) Save(preference *Preference) *Preference { return preference } -//执行清理操作 +//System cleanup. func (this *PreferenceDao) Cleanup() { - this.logger.Info("[PreferenceDao]执行清理:清除数据库中所有Preference记录。") + this.logger.Info("[PreferenceDao] clean up. Delete all Preference") db := core.CONTEXT.GetDB().Where("uuid is not null").Delete(Preference{}) this.PanicError(db.Error) } diff --git a/code/rest/preference_service.go b/code/rest/preference_service.go index 6679ef3..2180c88 100644 --- a/code/rest/preference_service.go +++ b/code/rest/preference_service.go @@ -9,11 +9,9 @@ type PreferenceService struct { preference *Preference } -//初始化方法 func (this *PreferenceService) Init() { this.BaseBean.Init() - //手动装填本实例的Bean. 这里必须要用中间变量方可。 b := core.CONTEXT.GetBean(this.preferenceDao) if b, ok := b.(*PreferenceDao); ok { this.preferenceDao = b @@ -38,10 +36,10 @@ func (this *PreferenceService) Reset() { } -//执行清理操作 +//System cleanup. func (this *PreferenceService) Cleanup() { - this.logger.Info("[PreferenceService]执行清理:重置缓存中的preference。") + this.logger.Info("[PreferenceService] clean up. Delete all preference") this.Reset() } diff --git a/code/rest/session_dao.go b/code/rest/session_dao.go index 0d0d7fa..6df3f0a 100644 --- a/code/rest/session_dao.go +++ b/code/rest/session_dao.go @@ -2,6 +2,7 @@ package rest import ( "github.com/eyebluecn/tank/code/core" + "github.com/eyebluecn/tank/code/tool/result" "github.com/nu7hatch/gouuid" "time" ) @@ -10,26 +11,27 @@ type SessionDao struct { BaseDao } -//按照Id查询session. +//find by uuid. if not found return nil. func (this *SessionDao) FindByUuid(uuid string) *Session { - - // Read - var session = &Session{} - db := core.CONTEXT.GetDB().Where(&Session{Base: Base{Uuid: uuid}}).First(session) + var entity = &Session{} + db := core.CONTEXT.GetDB().Where("uuid = ?", uuid).First(entity) if db.Error != nil { - return nil + if db.Error.Error() == result.DB_ERROR_NOT_FOUND { + return nil + } else { + panic(db.Error) + } } - return session + return entity } -//按照Id查询session. +//find by uuid. if not found panic NotFound error func (this *SessionDao) CheckByUuid(uuid string) *Session { - - // Read - var session = &Session{} - db := core.CONTEXT.GetDB().Where(&Session{Base: Base{Uuid: uuid}}).First(session) - this.PanicError(db.Error) - return session + entity := this.FindByUuid(uuid) + if entity == nil { + panic(result.NotFound("not found record with uuid = %s", uuid)) + } + return entity } //创建一个session并且持久化到数据库中。 @@ -67,9 +69,9 @@ func (this *SessionDao) Delete(uuid string) { } -//执行清理操作 +//System cleanup. func (this *SessionDao) Cleanup() { - this.logger.Info("[SessionDao]执行清理:清除数据库中所有Session记录。") + this.logger.Info("[SessionDao] clean up. Delete all Session") db := core.CONTEXT.GetDB().Where("uuid is not null").Delete(Session{}) this.PanicError(db.Error) } diff --git a/code/rest/session_service.go b/code/rest/session_service.go index 58e5e16..d41713d 100644 --- a/code/rest/session_service.go +++ b/code/rest/session_service.go @@ -9,11 +9,9 @@ type SessionService struct { sessionDao *SessionDao } -//初始化方法 func (this *SessionService) Init() { this.BaseBean.Init() - //手动装填本实例的Bean. 这里必须要用中间变量方可。 b := core.CONTEXT.GetBean(this.userDao) if b, ok := b.(*UserDao); ok { this.userDao = b @@ -26,10 +24,10 @@ func (this *SessionService) Init() { } -//执行清理操作 +//System cleanup. func (this *SessionService) Cleanup() { - this.logger.Info("[SessionService]执行清理:清除缓存中所有Session记录,共%d条。", core.CONTEXT.GetSessionCache().Count()) + this.logger.Info("[SessionService] clean up. Delete all Session. total:%d", core.CONTEXT.GetSessionCache().Count()) core.CONTEXT.GetSessionCache().Truncate() } diff --git a/code/rest/share_controller.go b/code/rest/share_controller.go index b803077..9894ef1 100644 --- a/code/rest/share_controller.go +++ b/code/rest/share_controller.go @@ -21,11 +21,9 @@ type ShareController struct { shareService *ShareService } -//初始化方法 func (this *ShareController) Init() { this.BaseController.Init() - //手动装填本实例的Bean. 这里必须要用中间变量方可。 b := core.CONTEXT.GetBean(this.shareDao) if b, ok := b.(*ShareDao); ok { this.shareDao = b @@ -53,12 +51,10 @@ func (this *ShareController) Init() { } -//注册自己的路由。 func (this *ShareController) RegisterRoutes() map[string]func(writer http.ResponseWriter, request *http.Request) { routeMap := make(map[string]func(writer http.ResponseWriter, request *http.Request)) - //每个Controller需要主动注册自己的路由。 routeMap["/api/share/create"] = this.Wrap(this.Create, USER_ROLE_USER) routeMap["/api/share/delete"] = this.Wrap(this.Delete, USER_ROLE_USER) routeMap["/api/share/delete/batch"] = this.Wrap(this.DeleteBatch, USER_ROLE_USER) @@ -170,7 +166,6 @@ func (this *ShareController) Create(writer http.ResponseWriter, request *http.Re return this.Success(share) } -//删除一条记录 func (this *ShareController) Delete(writer http.ResponseWriter, request *http.Request) *result.WebResult { uuid := request.FormValue("uuid") @@ -297,7 +292,7 @@ func (this *ShareController) Browse(writer http.ResponseWriter, request *http.Re user := this.findUser(request) share := this.shareService.CheckShare(shareUuid, code, user) - bridges := this.bridgeDao.ListByShareUuid(share.Uuid) + bridges := this.bridgeDao.FindByShareUuid(share.Uuid) if puuid == MATTER_ROOT { @@ -379,7 +374,7 @@ func (this *ShareController) Zip(writer http.ResponseWriter, request *http.Reque //下载分享全部内容。 share := this.shareService.CheckShare(shareUuid, code, user) - bridges := this.bridgeDao.ListByShareUuid(share.Uuid) + bridges := this.bridgeDao.FindByShareUuid(share.Uuid) var matterUuids []string for _, bridge := range bridges { matterUuids = append(matterUuids, bridge.MatterUuid) diff --git a/code/rest/share_dao.go b/code/rest/share_dao.go index e789b26..f783c9a 100644 --- a/code/rest/share_dao.go +++ b/code/rest/share_dao.go @@ -3,6 +3,7 @@ package rest import ( "github.com/eyebluecn/tank/code/core" "github.com/eyebluecn/tank/code/tool/builder" + "github.com/eyebluecn/tank/code/tool/result" "github.com/jinzhu/gorm" "github.com/nu7hatch/gouuid" @@ -13,28 +14,27 @@ type ShareDao struct { BaseDao } -//按照Id查询文件 +//find by uuid. if not found return nil. func (this *ShareDao) FindByUuid(uuid string) *Share { - - // Read - var share Share - db := core.CONTEXT.GetDB().Where(&Share{Base: Base{Uuid: uuid}}).First(&share) + var entity = &Share{} + db := core.CONTEXT.GetDB().Where("uuid = ?", uuid).First(entity) if db.Error != nil { - return nil + if db.Error.Error() == result.DB_ERROR_NOT_FOUND { + return nil + } else { + panic(db.Error) + } } - return &share + return entity } -//按照Id查询文件 +//find by uuid. if not found panic NotFound error func (this *ShareDao) CheckByUuid(uuid string) *Share { - - // Read - var share Share - db := core.CONTEXT.GetDB().Where(&Share{Base: Base{Uuid: uuid}}).First(&share) - this.PanicError(db.Error) - - return &share - + entity := this.FindByUuid(uuid) + if entity == nil { + panic(result.NotFound("not found record with uuid = %s", uuid)) + } + return entity } //按分页条件获取分页 @@ -85,7 +85,6 @@ func (this *ShareDao) Save(share *Share) *Share { return share } -//删除一条记录 func (this *ShareDao) Delete(share *Share) { db := core.CONTEXT.GetDB().Delete(&share) @@ -93,9 +92,9 @@ func (this *ShareDao) Delete(share *Share) { } -//执行清理操作 +//System cleanup. func (this *ShareDao) Cleanup() { - this.logger.Info("[ShareDao]执行清理:清除数据库中所有Share记录。") + this.logger.Info("[ShareDao] clean up. Delete all Share") db := core.CONTEXT.GetDB().Where("uuid is not null").Delete(Share{}) this.PanicError(db.Error) } diff --git a/code/rest/share_service.go b/code/rest/share_service.go index e0e42fe..d9007ef 100644 --- a/code/rest/share_service.go +++ b/code/rest/share_service.go @@ -16,11 +16,9 @@ type ShareService struct { userDao *UserDao } -//初始化方法 func (this *ShareService) Init() { this.BaseBean.Init() - //手动装填本实例的Bean. 这里必须要用中间变量方可。 b := core.CONTEXT.GetBean(this.shareDao) if b, ok := b.(*ShareDao); ok { this.shareDao = b diff --git a/code/rest/upload_token_dao.go b/code/rest/upload_token_dao.go index 89d6ffc..1cd6dd6 100644 --- a/code/rest/upload_token_dao.go +++ b/code/rest/upload_token_dao.go @@ -2,6 +2,7 @@ package rest import ( "github.com/eyebluecn/tank/code/core" + "github.com/eyebluecn/tank/code/tool/result" "github.com/nu7hatch/gouuid" "time" ) @@ -10,18 +11,27 @@ type UploadTokenDao struct { BaseDao } -//按照Id查询 +//find by uuid. if not found return nil. func (this *UploadTokenDao) FindByUuid(uuid string) *UploadToken { - - // Read - var uploadToken = &UploadToken{} - db := core.CONTEXT.GetDB().Where(&UploadToken{Base: Base{Uuid: uuid}}).First(uploadToken) + var entity = &UploadToken{} + db := core.CONTEXT.GetDB().Where("uuid = ?", uuid).First(entity) if db.Error != nil { - return nil + if db.Error.Error() == result.DB_ERROR_NOT_FOUND { + return nil + } else { + panic(db.Error) + } } + return entity +} - return uploadToken - +//find by uuid. if not found panic NotFound error +func (this *UploadTokenDao) CheckByUuid(uuid string) *UploadToken { + entity := this.FindByUuid(uuid) + if entity == nil { + panic(result.NotFound("not found record with uuid = %s", uuid)) + } + return entity } //创建一个session并且持久化到数据库中。 diff --git a/code/rest/user_controller.go b/code/rest/user_controller.go index 041c041..f18f36c 100644 --- a/code/rest/user_controller.go +++ b/code/rest/user_controller.go @@ -17,7 +17,6 @@ type UserController struct { preferenceService *PreferenceService } -//初始化方法 func (this *UserController) Init() { this.BaseController.Init() @@ -27,12 +26,10 @@ func (this *UserController) Init() { } } -//注册自己的路由。 func (this *UserController) RegisterRoutes() map[string]func(writer http.ResponseWriter, request *http.Request) { routeMap := make(map[string]func(writer http.ResponseWriter, request *http.Request)) - //每个Controller需要主动注册自己的路由。 routeMap["/api/user/login"] = this.Wrap(this.Login, USER_ROLE_GUEST) routeMap["/api/user/authentication/login"] = this.Wrap(this.AuthenticationLogin, USER_ROLE_GUEST) routeMap["/api/user/register"] = this.Wrap(this.Register, USER_ROLE_GUEST) diff --git a/code/rest/user_dao.go b/code/rest/user_dao.go index c347898..e03cc06 100644 --- a/code/rest/user_dao.go +++ b/code/rest/user_dao.go @@ -12,7 +12,6 @@ type UserDao struct { BaseDao } -//初始化方法 func (this *UserDao) Init() { this.BaseDao.Init() } @@ -37,30 +36,27 @@ func (this *UserDao) Create(user *User) *User { return user } -//按照Id查询用户,找不到返回nil +//find by uuid. if not found return nil. func (this *UserDao) FindByUuid(uuid string) *User { - - // Read - var user *User = &User{} - db := core.CONTEXT.GetDB().Where(&User{Base: Base{Uuid: uuid}}).First(user) + var entity = &User{} + db := core.CONTEXT.GetDB().Where("uuid = ?", uuid).First(entity) if db.Error != nil { - return nil + if db.Error.Error() == result.DB_ERROR_NOT_FOUND { + return nil + } else { + panic(db.Error) + } } - return user + return entity } -//按照Id查询用户,找不到抛panic +//find by uuid. if not found panic NotFound error func (this *UserDao) CheckByUuid(uuid string) *User { - - if uuid == "" { - panic("uuid必须指定") + entity := this.FindByUuid(uuid) + if entity == nil { + panic(result.NotFound("not found record with uuid = %s", uuid)) } - - // Read - var user = &User{} - db := core.CONTEXT.GetDB().Where(&User{Base: Base{Uuid: uuid}}).First(user) - this.PanicError(db.Error) - return user + return entity } //查询用户。 @@ -139,9 +135,9 @@ func (this *UserDao) Save(user *User) *User { return user } -//执行清理操作 +//System cleanup. func (this *UserDao) Cleanup() { - this.logger.Info("[UserDao]执行清理:清除数据库中所有User记录。") + this.logger.Info("[UserDao] clean up. Delete all User") db := core.CONTEXT.GetDB().Where("uuid is not null and role != ?", USER_ROLE_ADMINISTRATOR).Delete(User{}) this.PanicError(db.Error) } diff --git a/code/rest/user_service.go b/code/rest/user_service.go index cb24bbe..35d9d77 100644 --- a/code/rest/user_service.go +++ b/code/rest/user_service.go @@ -20,11 +20,9 @@ type UserService struct { locker *cache.Table } -//初始化方法 func (this *UserService) Init() { this.BaseBean.Init() - //手动装填本实例的Bean. 这里必须要用中间变量方可。 b := core.CONTEXT.GetBean(this.userDao) if b, ok := b.(*UserDao); ok { this.userDao = b diff --git a/code/tool/result/web_result.go b/code/tool/result/web_result.go index d9538e2..e9c11e4 100644 --- a/code/tool/result/web_result.go +++ b/code/tool/result/web_result.go @@ -23,23 +23,18 @@ type CodeWrapper struct { } var ( - OK = &CodeWrapper{Code: "OK", HttpStatus: http.StatusOK, Description: "成功"} - BAD_REQUEST = &CodeWrapper{Code: "BAD_REQUEST", HttpStatus: http.StatusBadRequest, Description: "请求不合法"} - CAPTCHA_ERROR = &CodeWrapper{Code: "CAPTCHA_ERROR", HttpStatus: http.StatusBadRequest, Description: "验证码错误"} - NEED_CAPTCHA = &CodeWrapper{Code: "NEED_CAPTCHA", HttpStatus: http.StatusBadRequest, Description: "验证码必填"} - NEED_SHARE_CODE = &CodeWrapper{Code: "NEED_SHARE_CODE", HttpStatus: http.StatusUnauthorized, Description: "分享提取码必填"} - SHARE_CODE_ERROR = &CodeWrapper{Code: "SHARE_CODE_ERROR", HttpStatus: http.StatusUnauthorized, Description: "分享提取码错误"} - USERNAME_PASSWORD_ERROR = &CodeWrapper{Code: "USERNAME_PASSWORD_ERROR", HttpStatus: http.StatusBadRequest, Description: "用户名或密码错误"} - PARAMS_ERROR = &CodeWrapper{Code: "PARAMS_ERROR", HttpStatus: http.StatusBadRequest, Description: "用户名或密码错误"} - LOGIN = &CodeWrapper{Code: "LOGIN", HttpStatus: http.StatusUnauthorized, Description: "未登录,禁止访问"} - LOGIN_EXPIRE = &CodeWrapper{Code: "LOGIN_EXPIRE", HttpStatus: http.StatusUnauthorized, Description: "登录过期,请重新登录"} - USER_DISABLED = &CodeWrapper{Code: "USER_DISABLED", HttpStatus: http.StatusForbidden, Description: "账户被禁用,禁止访问"} - UNAUTHORIZED = &CodeWrapper{Code: "UNAUTHORIZED", HttpStatus: http.StatusUnauthorized, Description: "没有权限,禁止访问"} - NOT_FOUND = &CodeWrapper{Code: "NOT_FOUND", HttpStatus: http.StatusNotFound, Description: "内容不存在"} - RANGE_NOT_SATISFIABLE = &CodeWrapper{Code: "RANGE_NOT_SATISFIABLE", HttpStatus: http.StatusRequestedRangeNotSatisfiable, Description: "文件范围读取错误"} - NOT_INSTALLED = &CodeWrapper{Code: "NOT_INSTALLED", HttpStatus: http.StatusInternalServerError, Description: "系统尚未安装"} - SERVER = &CodeWrapper{Code: "SERVER", HttpStatus: http.StatusInternalServerError, Description: "服务器出错"} - UNKNOWN = &CodeWrapper{Code: "UNKNOWN", HttpStatus: http.StatusInternalServerError, Description: "服务器未知错误"} + OK = &CodeWrapper{Code: "OK", HttpStatus: http.StatusOK, Description: "ok"} + BAD_REQUEST = &CodeWrapper{Code: "BAD_REQUEST", HttpStatus: http.StatusBadRequest, Description: "bad request"} + NEED_SHARE_CODE = &CodeWrapper{Code: "NEED_SHARE_CODE", HttpStatus: http.StatusUnauthorized, Description: "share code required"} + SHARE_CODE_ERROR = &CodeWrapper{Code: "SHARE_CODE_ERROR", HttpStatus: http.StatusUnauthorized, Description: "share code error"} + LOGIN = &CodeWrapper{Code: "LOGIN", HttpStatus: http.StatusUnauthorized, Description: "not login"} + USER_DISABLED = &CodeWrapper{Code: "USER_DISABLED", HttpStatus: http.StatusForbidden, Description: "user disabled"} + UNAUTHORIZED = &CodeWrapper{Code: "UNAUTHORIZED", HttpStatus: http.StatusUnauthorized, Description: "unauthorized"} + NOT_FOUND = &CodeWrapper{Code: "NOT_FOUND", HttpStatus: http.StatusNotFound, Description: "404 not found"} + RANGE_NOT_SATISFIABLE = &CodeWrapper{Code: "RANGE_NOT_SATISFIABLE", HttpStatus: http.StatusRequestedRangeNotSatisfiable, Description: "range not satisfiable"} + NOT_INSTALLED = &CodeWrapper{Code: "NOT_INSTALLED", HttpStatus: http.StatusInternalServerError, Description: "application not installed"} + SERVER = &CodeWrapper{Code: "SERVER", HttpStatus: http.StatusInternalServerError, Description: "server error"} + UNKNOWN = &CodeWrapper{Code: "UNKNOWN", HttpStatus: http.StatusInternalServerError, Description: "server unknow error"} ) //根据 CodeWrapper来获取对应的HttpStatus @@ -48,22 +43,12 @@ func FetchHttpStatus(code string) int { return OK.HttpStatus } else if code == BAD_REQUEST.Code { return BAD_REQUEST.HttpStatus - } else if code == CAPTCHA_ERROR.Code { - return CAPTCHA_ERROR.HttpStatus - } else if code == NEED_CAPTCHA.Code { - return NEED_CAPTCHA.HttpStatus } else if code == NEED_SHARE_CODE.Code { return NEED_SHARE_CODE.HttpStatus } else if code == SHARE_CODE_ERROR.Code { return SHARE_CODE_ERROR.HttpStatus - } else if code == USERNAME_PASSWORD_ERROR.Code { - return USERNAME_PASSWORD_ERROR.HttpStatus - } else if code == PARAMS_ERROR.Code { - return PARAMS_ERROR.HttpStatus } else if code == LOGIN.Code { return LOGIN.HttpStatus - } else if code == LOGIN_EXPIRE.Code { - return LOGIN_EXPIRE.HttpStatus } else if code == USER_DISABLED.Code { return USER_DISABLED.HttpStatus } else if code == UNAUTHORIZED.Code {