Finish half translation work.
This commit is contained in:
parent
900924d196
commit
5625149766
@ -1,9 +1,6 @@
|
||||
package core
|
||||
|
||||
/**
|
||||
* 从命令行输入的相关信息
|
||||
*/
|
||||
type Application interface {
|
||||
//启动整个应用
|
||||
//start the application
|
||||
Start()
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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{})
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
})
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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 + ","
|
||||
}
|
||||
|
@ -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"`
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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"
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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"`
|
||||
|
@ -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)
|
||||
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ package rest
|
||||
import "github.com/eyebluecn/tank/code/core"
|
||||
|
||||
/**
|
||||
* 系统的所有访问记录均记录在此
|
||||
* visit record.
|
||||
*/
|
||||
type Footprint struct {
|
||||
Base
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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")
|
||||
|
@ -3,7 +3,7 @@ package rest
|
||||
import "github.com/jinzhu/gorm"
|
||||
|
||||
/**
|
||||
* 表名对应的表结构
|
||||
* table meta info.
|
||||
*/
|
||||
type InstallTableInfo struct {
|
||||
Name string `json:"name"`
|
||||
|
@ -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")
|
||||
|
@ -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)
|
||||
|
||||
|
@ -7,9 +7,9 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
//根目录的uuid
|
||||
//root matter's uuid
|
||||
MATTER_ROOT = "root"
|
||||
//cache文件夹名称
|
||||
//cache directory name.
|
||||
MATTER_CACHE = "cache"
|
||||
//压缩文件的临时目录
|
||||
MATTER_ZIP = "zip"
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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并且持久化到数据库中。
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user