diff --git a/code/rest/bridge_controller.go b/code/rest/bridge_controller.go new file mode 100644 index 0000000..51217cd --- /dev/null +++ b/code/rest/bridge_controller.go @@ -0,0 +1,89 @@ +package rest + +import ( + "github.com/eyebluecn/tank/code/core" + "github.com/eyebluecn/tank/code/tool/builder" + "github.com/eyebluecn/tank/code/tool/result" + "net/http" + "strconv" +) + +type BridgeController struct { + BaseController + bridgeDao *BridgeDao + shareDao *ShareDao + bridgeService *BridgeService +} + +//初始化方法 +func (this *BridgeController) Init() { + this.BaseController.Init() + + //手动装填本实例的Bean. 这里必须要用中间变量方可。 + b := core.CONTEXT.GetBean(this.bridgeDao) + if b, ok := b.(*BridgeDao); ok { + this.bridgeDao = b + } + + b = core.CONTEXT.GetBean(this.shareDao) + if b, ok := b.(*ShareDao); ok { + this.shareDao = b + } + b = core.CONTEXT.GetBean(this.bridgeService) + if b, ok := b.(*BridgeService); ok { + this.bridgeService = b + } + +} + +//注册自己的路由。 +func (this *BridgeController) RegisterRoutes() map[string]func(writer http.ResponseWriter, request *http.Request) { + + routeMap := make(map[string]func(writer http.ResponseWriter, request *http.Request)) + + //每个Controller需要主动注册自己的路由。 + routeMap["/api/bridge/page"] = this.Wrap(this.Page, USER_ROLE_USER) + + return routeMap +} + +//按照分页的方式查询 +func (this *BridgeController) Page(writer http.ResponseWriter, request *http.Request) *result.WebResult { + + //如果是根目录,那么就传入root. + pageStr := request.FormValue("page") + pageSizeStr := request.FormValue("pageSize") + shareUuid := request.FormValue("shareUuid") + orderCreateTime := request.FormValue("orderCreateTime") + orderSize := request.FormValue("orderSize") + + share := this.shareDao.CheckByUuid(shareUuid) + + var page int + if pageStr != "" { + page, _ = strconv.Atoi(pageStr) + } + + pageSize := 200 + if pageSizeStr != "" { + tmp, err := strconv.Atoi(pageSizeStr) + if err == nil { + pageSize = tmp + } + } + + sortArray := []builder.OrderPair{ + { + Key: "create_time", + Value: orderCreateTime, + }, + { + Key: "size", + Value: orderSize, + }, + } + + pager := this.bridgeDao.Page(page, pageSize, share.Uuid, sortArray) + + return this.Success(pager) +} diff --git a/code/rest/bridge_dao.go b/code/rest/bridge_dao.go new file mode 100644 index 0000000..c9ba4c5 --- /dev/null +++ b/code/rest/bridge_dao.go @@ -0,0 +1,100 @@ +package rest + +import ( + "github.com/eyebluecn/tank/code/core" + "github.com/eyebluecn/tank/code/tool/builder" + "github.com/jinzhu/gorm" + + "github.com/nu7hatch/gouuid" + "time" +) + +type BridgeDao struct { + BaseDao +} + +//按照Id查询文件 +func (this *BridgeDao) FindByUuid(uuid string) *Bridge { + + // Read + var bridge Bridge + db := core.CONTEXT.GetDB().Where(&Bridge{Base: Base{Uuid: uuid}}).First(&bridge) + if db.Error != nil { + return nil + } + return &bridge +} + +//按照Id查询文件 +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) + + return &bridge + +} + +//按分页条件获取分页 +func (this *BridgeDao) Page(page int, pageSize int, shareUuid string, sortArray []builder.OrderPair) *Pager { + + var wp = &builder.WherePair{} + + if shareUuid != "" { + wp = wp.And(&builder.WherePair{Query: "share_uuid = ?", Args: []interface{}{shareUuid}}) + } + + var conditionDB *gorm.DB + conditionDB = core.CONTEXT.GetDB().Model(&Bridge{}).Where(wp.Query, wp.Args...) + + count := 0 + db := conditionDB.Count(&count) + this.PanicError(db.Error) + + var bridges []*Bridge + db = conditionDB.Order(this.GetSortString(sortArray)).Offset(page * pageSize).Limit(pageSize).Find(&bridges) + this.PanicError(db.Error) + pager := NewPager(page, pageSize, count, bridges) + + return pager +} + +//创建 +func (this *BridgeDao) Create(bridge *Bridge) *Bridge { + + timeUUID, _ := uuid.NewV4() + bridge.Uuid = string(timeUUID.String()) + bridge.CreateTime = time.Now() + bridge.UpdateTime = time.Now() + bridge.Sort = time.Now().UnixNano() / 1e6 + db := core.CONTEXT.GetDB().Create(bridge) + this.PanicError(db.Error) + + return bridge +} + +//修改一条记录 +func (this *BridgeDao) Save(bridge *Bridge) *Bridge { + + bridge.UpdateTime = time.Now() + db := core.CONTEXT.GetDB().Save(bridge) + this.PanicError(db.Error) + + return bridge +} + +//删除一条记录 +func (this *BridgeDao) Delete(bridge *Bridge) { + + db := core.CONTEXT.GetDB().Delete(&bridge) + this.PanicError(db.Error) +} + +//执行清理操作 +func (this *BridgeDao) Cleanup() { + this.logger.Info("[BridgeDao]执行清理:清除数据库中所有Bridge记录。") + db := core.CONTEXT.GetDB().Where("uuid is not null").Delete(Bridge{}) + this.PanicError(db.Error) +} diff --git a/code/rest/bridge_model.go b/code/rest/bridge_model.go new file mode 100644 index 0000000..7da0e72 --- /dev/null +++ b/code/rest/bridge_model.go @@ -0,0 +1,19 @@ +package rest + +import ( + "github.com/eyebluecn/tank/code/core" +) + +/** + * 分享记录和matter的关联表 + */ +type Bridge struct { + Base + ShareUuid string `json:"shareUuid" gorm:"type:char(36)"` + MatterUuid string `json:"matterUuid" gorm:"type:char(36)"` +} + +// set File's table name to be `profiles` +func (this *Bridge) TableName() string { + return core.TABLE_PREFIX + "bridge" +} diff --git a/code/rest/bridge_service.go b/code/rest/bridge_service.go new file mode 100644 index 0000000..fb4b824 --- /dev/null +++ b/code/rest/bridge_service.go @@ -0,0 +1,37 @@ +package rest + +import ( + "github.com/eyebluecn/tank/code/core" +) + +//@Service +type BridgeService struct { + BaseBean + bridgeDao *BridgeDao + 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 + } + + b = core.CONTEXT.GetBean(this.userDao) + if b, ok := b.(*UserDao); ok { + this.userDao = b + } + +} + +//获取某个文件的详情,会把父级依次倒着装进去。如果中途出错,直接抛出异常。 +func (this *BridgeService) Detail(uuid string) *Bridge { + + bridge := this.bridgeDao.CheckByUuid(uuid) + + return bridge +} diff --git a/code/rest/footprint_model.go b/code/rest/footprint_model.go index ec177c3..df0f02c 100644 --- a/code/rest/footprint_model.go +++ b/code/rest/footprint_model.go @@ -8,7 +8,7 @@ import "github.com/eyebluecn/tank/code/core" type Footprint struct { Base UserUuid string `json:"userUuid" gorm:"type:char(36)"` - Ip string `json:"ip" gorm:"type:varchar(128) not null;index:idx_dt"` + Ip string `json:"ip" gorm:"type:varchar(128) not null"` Host string `json:"host" gorm:"type:varchar(45) not null"` Uri string `json:"uri" gorm:"type:varchar(255) not null"` Params string `json:"params" gorm:"type:text"` diff --git a/code/rest/share_controller.go b/code/rest/share_controller.go new file mode 100644 index 0000000..7527d12 --- /dev/null +++ b/code/rest/share_controller.go @@ -0,0 +1,198 @@ +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/eyebluecn/tank/code/tool/util" + "net/http" + "strconv" + "strings" + "time" +) + +type ShareController struct { + BaseController + shareDao *ShareDao + bridgeDao *BridgeDao + matterDao *MatterDao + 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 + } + + b = core.CONTEXT.GetBean(this.bridgeDao) + if b, ok := b.(*BridgeDao); ok { + this.bridgeDao = b + } + + b = core.CONTEXT.GetBean(this.matterDao) + if b, ok := b.(*MatterDao); ok { + this.matterDao = b + } + + b = core.CONTEXT.GetBean(this.shareService) + if b, ok := b.(*ShareService); ok { + this.shareService = b + } + +} + +//注册自己的路由。 +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/detail"] = this.Wrap(this.Detail, USER_ROLE_USER) + routeMap["/api/share/page"] = this.Wrap(this.Page, USER_ROLE_USER) + + return routeMap +} + +//删除一条记录 +func (this *ShareController) Create(writer http.ResponseWriter, request *http.Request) *result.WebResult { + + matterUuids := request.FormValue("matterUuids") + expireTimeStr := request.FormValue("expireTime") + + if matterUuids == "" { + panic(result.BadRequest("matterUuids必填")) + } + + var expireTime time.Time + if expireTimeStr == "" { + panic(result.BadRequest("时间格式错误!")) + } else { + expireTime = util.ConvertDateTimeStringToTime(expireTimeStr) + } + + if expireTime.Before(time.Now()) { + panic(result.BadRequest("过期时间错误!")) + } + + uuidArray := strings.Split(matterUuids, ",") + + if len(uuidArray) == 0 { + panic(result.BadRequest("请至少分享一个文件")) + } + + user := this.checkUser(writer, request) + for _, uuid := range uuidArray { + + matter := this.matterDao.CheckByUuid(uuid) + + //判断文件的所属人是否正确 + if matter.UserUuid != user.Uuid { + panic(result.Unauthorized("没有权限")) + } + } + + //创建share记录 + share := &Share{ + UserUuid: user.Uuid, + DownloadTimes: 0, + Code: util.RandomString4(), + ExpireTime: expireTime, + } + this.shareDao.Create(share) + + //创建关联的matter + for _, matterUuid := range uuidArray { + bridge := &Bridge{ + ShareUuid: share.Uuid, + MatterUuid: matterUuid, + } + this.bridgeDao.Create(bridge) + } + + return this.Success(share) +} + +//删除一条记录 +func (this *ShareController) Delete(writer http.ResponseWriter, request *http.Request) *result.WebResult { + + uuid := request.FormValue("uuid") + if uuid == "" { + panic(result.BadRequest("uuid必填")) + } + + share := this.shareDao.FindByUuid(uuid) + + if share != nil { + this.shareDao.Delete(share) + } + + return this.Success(nil) +} + +//查看详情。 +func (this *ShareController) Detail(writer http.ResponseWriter, request *http.Request) *result.WebResult { + + uuid := request.FormValue("uuid") + if uuid == "" { + panic(result.BadRequest("分享的uuid必填")) + } + + share := this.shareDao.CheckByUuid(uuid) + + //验证当前之人是否有权限查看这么详细。 + user := this.checkUser(writer, request) + if user.Role != USER_ROLE_ADMINISTRATOR { + if share.UserUuid != user.Uuid { + panic(result.Unauthorized("没有权限")) + } + } + + return this.Success(share) + +} + +//按照分页的方式查询 +func (this *ShareController) Page(writer http.ResponseWriter, request *http.Request) *result.WebResult { + + //如果是根目录,那么就传入root. + pageStr := request.FormValue("page") + pageSizeStr := request.FormValue("pageSize") + userUuid := request.FormValue("userUuid") + orderCreateTime := request.FormValue("orderCreateTime") + + user := this.checkUser(writer, request) + if user.Role != USER_ROLE_ADMINISTRATOR { + userUuid = user.Uuid + } + + var page int + if pageStr != "" { + page, _ = strconv.Atoi(pageStr) + } + + pageSize := 200 + if pageSizeStr != "" { + tmp, err := strconv.Atoi(pageSizeStr) + if err == nil { + pageSize = tmp + } + } + + sortArray := []builder.OrderPair{ + { + Key: "create_time", + Value: orderCreateTime, + }, + } + + pager := this.shareDao.Page(page, pageSize, userUuid, sortArray) + + return this.Success(pager) +} diff --git a/code/rest/share_dao.go b/code/rest/share_dao.go new file mode 100644 index 0000000..e052582 --- /dev/null +++ b/code/rest/share_dao.go @@ -0,0 +1,100 @@ +package rest + +import ( + "github.com/eyebluecn/tank/code/core" + "github.com/eyebluecn/tank/code/tool/builder" + "github.com/jinzhu/gorm" + + "github.com/nu7hatch/gouuid" + "time" +) + +type ShareDao struct { + BaseDao +} + +//按照Id查询文件 +func (this *ShareDao) FindByUuid(uuid string) *Share { + + // Read + var share Share + db := core.CONTEXT.GetDB().Where(&Share{Base: Base{Uuid: uuid}}).First(&share) + if db.Error != nil { + return nil + } + return &share +} + +//按照Id查询文件 +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 + +} + +//按分页条件获取分页 +func (this *ShareDao) Page(page int, pageSize int, userUuid string, sortArray []builder.OrderPair) *Pager { + + var wp = &builder.WherePair{} + + if userUuid != "" { + wp = wp.And(&builder.WherePair{Query: "user_uuid = ?", Args: []interface{}{userUuid}}) + } + + var conditionDB *gorm.DB + conditionDB = core.CONTEXT.GetDB().Model(&Share{}).Where(wp.Query, wp.Args...) + + count := 0 + db := conditionDB.Count(&count) + this.PanicError(db.Error) + + var shares []*Share + db = conditionDB.Order(this.GetSortString(sortArray)).Offset(page * pageSize).Limit(pageSize).Find(&shares) + this.PanicError(db.Error) + pager := NewPager(page, pageSize, count, shares) + + return pager +} + +//创建 +func (this *ShareDao) Create(share *Share) *Share { + + timeUUID, _ := uuid.NewV4() + share.Uuid = string(timeUUID.String()) + share.CreateTime = time.Now() + share.UpdateTime = time.Now() + share.Sort = time.Now().UnixNano() / 1e6 + db := core.CONTEXT.GetDB().Create(share) + this.PanicError(db.Error) + + return share +} + +//修改一条记录 +func (this *ShareDao) Save(share *Share) *Share { + + share.UpdateTime = time.Now() + db := core.CONTEXT.GetDB().Save(share) + this.PanicError(db.Error) + + return share +} + +//删除一条记录 +func (this *ShareDao) Delete(share *Share) { + + db := core.CONTEXT.GetDB().Delete(&share) + this.PanicError(db.Error) +} + +//执行清理操作 +func (this *ShareDao) Cleanup() { + this.logger.Info("[ShareDao]执行清理:清除数据库中所有Share记录。") + db := core.CONTEXT.GetDB().Where("uuid is not null").Delete(Share{}) + this.PanicError(db.Error) +} diff --git a/code/rest/share_model.go b/code/rest/share_model.go new file mode 100644 index 0000000..ffe1618 --- /dev/null +++ b/code/rest/share_model.go @@ -0,0 +1,22 @@ +package rest + +import ( + "github.com/eyebluecn/tank/code/core" + "time" +) + +/** + * 分享记录 + */ +type Share struct { + Base + UserUuid string `json:"userUuid" gorm:"type:char(36)"` + DownloadTimes int64 `json:"downloadTimes" gorm:"type:bigint(20) not null;default:0"` + Code string `json:"code" gorm:"type:varchar(45) not null"` + ExpireTime time.Time `json:"expireTime" gorm:"type:timestamp not null;default:'2018-01-01 00:00:00'"` +} + +// set File's table name to be `profiles` +func (this *Share) TableName() string { + return core.TABLE_PREFIX + "share" +} diff --git a/code/rest/share_service.go b/code/rest/share_service.go new file mode 100644 index 0000000..a740bd5 --- /dev/null +++ b/code/rest/share_service.go @@ -0,0 +1,37 @@ +package rest + +import ( + "github.com/eyebluecn/tank/code/core" +) + +//@Service +type ShareService struct { + BaseBean + shareDao *ShareDao + 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 + } + + b = core.CONTEXT.GetBean(this.userDao) + if b, ok := b.(*UserDao); ok { + this.userDao = b + } + +} + +//获取某个分享的详情。 +func (this *ShareService) Detail(uuid string) *Share { + + share := this.shareDao.CheckByUuid(uuid) + + return share +} diff --git a/code/rest/upload_token_model.go b/code/rest/upload_token_model.go index 0062cdf..2ea3880 100644 --- a/code/rest/upload_token_model.go +++ b/code/rest/upload_token_model.go @@ -7,14 +7,14 @@ import ( type UploadToken struct { Base - UserUuid string `json:"userUuid"` - FolderUuid string `json:"folderUuid"` - MatterUuid string `json:"matterUuid"` - ExpireTime time.Time `json:"expireTime"` - Filename string `json:"filename"` - Privacy bool `json:"privacy"` - Size int64 `json:"size"` - Ip string `json:"ip"` + UserUuid string `json:"userUuid" gorm:"type:char(36) not null"` + FolderUuid string `json:"folderUuid" gorm:"type:char(36) not null"` + MatterUuid string `json:"matterUuid" gorm:"type:char(36) not null"` + ExpireTime time.Time `json:"expireTime" gorm:"type:timestamp not null;default:'2018-01-01 00:00:00'"` + Filename string `json:"filename" gorm:"type:varchar(255) not null"` + Privacy bool `json:"privacy" gorm:"type:tinyint(1) not null;default:0"` + Size int64 `json:"size" gorm:"type:bigint(20) not null;default:0"` + Ip string `json:"ip" gorm:"type:varchar(128) not null"` } func (this *UploadToken) TableName() string { diff --git a/code/support/tank_context.go b/code/support/tank_context.go index cf3e8b5..42cf352 100644 --- a/code/support/tank_context.go +++ b/code/support/tank_context.go @@ -130,6 +130,11 @@ func (this *TankContext) registerBeans() { this.registerBean(new(rest.AlienController)) this.registerBean(new(rest.AlienService)) + //bridge + this.registerBean(new(rest.BridgeController)) + this.registerBean(new(rest.BridgeDao)) + this.registerBean(new(rest.BridgeService)) + //dashboard this.registerBean(new(rest.DashboardController)) this.registerBean(new(rest.DashboardDao)) @@ -165,6 +170,11 @@ func (this *TankContext) registerBeans() { this.registerBean(new(rest.SessionDao)) this.registerBean(new(rest.SessionService)) + //share + this.registerBean(new(rest.ShareController)) + this.registerBean(new(rest.ShareDao)) + this.registerBean(new(rest.ShareService)) + //uploadToken this.registerBean(new(rest.UploadTokenDao)) diff --git a/code/tool/util/util_string.go b/code/tool/util/util_string.go index bfc3e66..8fd06c0 100644 --- a/code/tool/util/util_string.go +++ b/code/tool/util/util_string.go @@ -2,7 +2,9 @@ package util import ( "fmt" + "math/rand" "strconv" + "time" ) //把一个大小转变成方便读的格式 @@ -40,3 +42,21 @@ func GetMysqlUrl( mysqlPassword string) string { return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&parseTime=True&loc=Local", mysqlUsername, mysqlPassword, mysqlHost, mysqlPort, mysqlSchema) } + +//获取四位随机数字 +func RandomNumber4() string { + return fmt.Sprintf("%04v", rand.New(rand.NewSource(time.Now().UnixNano())).Int31()%10000) +} + +//获取四位随机数字 +func RandomString4() string { + + var letterRunes = []rune("abcdefghijklmnopqrstuvwxyz0123456789") + + b := make([]rune, 4) + for i := range b { + b[i] = letterRunes[rand.New(rand.NewSource(time.Now().UnixNano())).Intn(len(letterRunes))] + } + + return string(b) +}