mirror of
				https://github.com/cloudreve/cloudreve.git
				synced 2025-10-31 08:39:10 +08:00 
			
		
		
		
	Feat: list files for shared folder
This commit is contained in:
		| @ -49,6 +49,30 @@ func ShareCanPreview() gin.HandlerFunc { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // CheckShareUnlocked 检查分享是否已解锁 | ||||||
|  | func CheckShareUnlocked() gin.HandlerFunc { | ||||||
|  | 	return func(c *gin.Context) { | ||||||
|  | 		if shareCtx, ok := c.Get("share"); ok { | ||||||
|  | 			share := shareCtx.(*model.Share) | ||||||
|  | 			// 分享是否已解锁 | ||||||
|  | 			if share.Password != "" { | ||||||
|  | 				sessionKey := fmt.Sprintf("share_unlock_%d", share.ID) | ||||||
|  | 				unlocked := util.GetSession(c, sessionKey) != nil | ||||||
|  | 				if !unlocked { | ||||||
|  | 					c.JSON(200, serializer.Err(serializer.CodeNoPermissionErr, | ||||||
|  | 						"无权访问此分享", nil)) | ||||||
|  | 					c.Abort() | ||||||
|  | 					return | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			c.Next() | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		c.Abort() | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| // BeforeShareDownload 分享被下载前的检查 | // BeforeShareDownload 分享被下载前的检查 | ||||||
| func BeforeShareDownload() gin.HandlerFunc { | func BeforeShareDownload() gin.HandlerFunc { | ||||||
| 	return func(c *gin.Context) { | 	return func(c *gin.Context) { | ||||||
| @ -66,18 +90,6 @@ func BeforeShareDownload() gin.HandlerFunc { | |||||||
| 					return | 					return | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
| 				// 分享是否已解锁 |  | ||||||
| 				if share.Password != "" { |  | ||||||
| 					sessionKey := fmt.Sprintf("share_unlock_%d", share.ID) |  | ||||||
| 					unlocked := util.GetSession(c, sessionKey) != nil |  | ||||||
| 					if !unlocked { |  | ||||||
| 						c.JSON(200, serializer.Err(serializer.CodeNoPermissionErr, |  | ||||||
| 							"无权访问此分享", nil)) |  | ||||||
| 						c.Abort() |  | ||||||
| 						return |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				// 对积分、下载次数进行更新 | 				// 对积分、下载次数进行更新 | ||||||
| 				err = share.DownloadBy(user, c) | 				err = share.DownloadBy(user, c) | ||||||
| 				if err != nil { | 				if err != nil { | ||||||
|  | |||||||
| @ -20,13 +20,22 @@ func (fs *FileSystem) IsPathExist(path string) (bool, *model.Folder) { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// 递归步入目录 | 	// 递归步入目录 | ||||||
| 	// TODO:装入树形缓存 | 	// TODO:测试新增 | ||||||
| 	var currentFolder *model.Folder | 	var currentFolder *model.Folder | ||||||
|  |  | ||||||
|  | 	// 如果已设定目录对象,则从给定目录向下遍历 | ||||||
|  | 	if len(fs.DirTarget) > 0 { | ||||||
|  | 		currentFolder = &fs.DirTarget[0] | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	for _, folderName := range pathList { | 	for _, folderName := range pathList { | ||||||
| 		var err error | 		var err error | ||||||
|  |  | ||||||
| 		// 根目录 | 		// 根目录 | ||||||
| 		if folderName == "/" { | 		if folderName == "/" { | ||||||
|  | 			if currentFolder != nil { | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
| 			currentFolder, err = fs.User.Root() | 			currentFolder, err = fs.User.Root() | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return false, nil | 				return false, nil | ||||||
|  | |||||||
| @ -31,6 +31,8 @@ func BuildSiteConfig(settings map[string]string, user *model.User) Response { | |||||||
| 	var userRes User | 	var userRes User | ||||||
| 	if user != nil { | 	if user != nil { | ||||||
| 		userRes = BuildUser(*user) | 		userRes = BuildUser(*user) | ||||||
|  | 	} else { | ||||||
|  | 		userRes = BuildUser(*model.NewAnonymousUser()) | ||||||
| 	} | 	} | ||||||
| 	return Response{ | 	return Response{ | ||||||
| 		Data: SiteConfig{ | 		Data: SiteConfig{ | ||||||
|  | |||||||
| @ -43,6 +43,7 @@ type group struct { | |||||||
| 	AllowTorrentDownload bool   `json:"allowTorrentDownload"` | 	AllowTorrentDownload bool   `json:"allowTorrentDownload"` | ||||||
| 	AllowArchiveDownload bool   `json:"allowArchiveDownload"` | 	AllowArchiveDownload bool   `json:"allowArchiveDownload"` | ||||||
| 	ShareFreeEnabled     bool   `json:"shareFree"` | 	ShareFreeEnabled     bool   `json:"shareFree"` | ||||||
|  | 	ShareDownload        bool   `json:"shareDownload"` | ||||||
| } | } | ||||||
|  |  | ||||||
| type storage struct { | type storage struct { | ||||||
| @ -78,6 +79,7 @@ func BuildUser(user model.User) User { | |||||||
| 			AllowTorrentDownload: aria2Option[2], | 			AllowTorrentDownload: aria2Option[2], | ||||||
| 			AllowArchiveDownload: user.Group.OptionsSerialized.ArchiveDownloadEnabled, | 			AllowArchiveDownload: user.Group.OptionsSerialized.ArchiveDownloadEnabled, | ||||||
| 			ShareFreeEnabled:     user.Group.OptionsSerialized.ShareFreeEnabled, | 			ShareFreeEnabled:     user.Group.OptionsSerialized.ShareFreeEnabled, | ||||||
|  | 			ShareDownload:        user.Group.OptionsSerialized.ShareDownloadEnabled, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | |||||||
| @ -30,7 +30,7 @@ func GetShare(c *gin.Context) { | |||||||
|  |  | ||||||
| // GetShareDownload 创建分享下载会话 | // GetShareDownload 创建分享下载会话 | ||||||
| func GetShareDownload(c *gin.Context) { | func GetShareDownload(c *gin.Context) { | ||||||
| 	var service share.SingleFileService | 	var service share.ShareService | ||||||
| 	if err := c.ShouldBindQuery(&service); err == nil { | 	if err := c.ShouldBindQuery(&service); err == nil { | ||||||
| 		res := service.CreateDownloadSession(c) | 		res := service.CreateDownloadSession(c) | ||||||
| 		c.JSON(200, res) | 		c.JSON(200, res) | ||||||
| @ -45,7 +45,7 @@ func PreviewShare(c *gin.Context) { | |||||||
| 	ctx, cancel := context.WithCancel(context.Background()) | 	ctx, cancel := context.WithCancel(context.Background()) | ||||||
| 	defer cancel() | 	defer cancel() | ||||||
|  |  | ||||||
| 	var service share.SingleFileService | 	var service share.ShareService | ||||||
| 	if err := c.ShouldBindQuery(&service); err == nil { | 	if err := c.ShouldBindQuery(&service); err == nil { | ||||||
| 		res := service.PreviewContent(ctx, c, false) | 		res := service.PreviewContent(ctx, c, false) | ||||||
| 		// 是否需要重定向 | 		// 是否需要重定向 | ||||||
| @ -68,7 +68,7 @@ func PreviewShareText(c *gin.Context) { | |||||||
| 	ctx, cancel := context.WithCancel(context.Background()) | 	ctx, cancel := context.WithCancel(context.Background()) | ||||||
| 	defer cancel() | 	defer cancel() | ||||||
|  |  | ||||||
| 	var service share.SingleFileService | 	var service share.ShareService | ||||||
| 	if err := c.ShouldBindQuery(&service); err == nil { | 	if err := c.ShouldBindQuery(&service); err == nil { | ||||||
| 		res := service.PreviewContent(ctx, c, true) | 		res := service.PreviewContent(ctx, c, true) | ||||||
| 		// 是否有错误发生 | 		// 是否有错误发生 | ||||||
| @ -82,7 +82,7 @@ func PreviewShareText(c *gin.Context) { | |||||||
|  |  | ||||||
| // GetShareDocPreview 创建分享Office文档预览地址 | // GetShareDocPreview 创建分享Office文档预览地址 | ||||||
| func GetShareDocPreview(c *gin.Context) { | func GetShareDocPreview(c *gin.Context) { | ||||||
| 	var service share.SingleFileService | 	var service share.ShareService | ||||||
| 	if err := c.ShouldBindQuery(&service); err == nil { | 	if err := c.ShouldBindQuery(&service); err == nil { | ||||||
| 		res := service.CreateDocPreviewSession(c) | 		res := service.CreateDocPreviewSession(c) | ||||||
| 		c.JSON(200, res) | 		c.JSON(200, res) | ||||||
| @ -93,7 +93,7 @@ func GetShareDocPreview(c *gin.Context) { | |||||||
|  |  | ||||||
| // SaveShare 转存他人分享 | // SaveShare 转存他人分享 | ||||||
| func SaveShare(c *gin.Context) { | func SaveShare(c *gin.Context) { | ||||||
| 	var service share.SingleFileService | 	var service share.ShareService | ||||||
| 	if err := c.ShouldBindJSON(&service); err == nil { | 	if err := c.ShouldBindJSON(&service); err == nil { | ||||||
| 		res := service.SaveToMyFile(c) | 		res := service.SaveToMyFile(c) | ||||||
| 		c.JSON(200, res) | 		c.JSON(200, res) | ||||||
| @ -101,3 +101,14 @@ func SaveShare(c *gin.Context) { | |||||||
| 		c.JSON(200, ErrorResponse(err)) | 		c.JSON(200, ErrorResponse(err)) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // ListSharedFolder 列出分享的目录下的对象 | ||||||
|  | func ListSharedFolder(c *gin.Context) { | ||||||
|  | 	var service share.ShareService | ||||||
|  | 	if err := c.ShouldBindUri(&service); err == nil { | ||||||
|  | 		res := service.List(c) | ||||||
|  | 		c.JSON(200, res) | ||||||
|  | 	} else { | ||||||
|  | 		c.JSON(200, ErrorResponse(err)) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | |||||||
| @ -174,25 +174,35 @@ func InitMasterRouter() *gin.Engine { | |||||||
| 			share.GET("info/:id", controllers.GetShare) | 			share.GET("info/:id", controllers.GetShare) | ||||||
| 			// 创建文件下载会话 | 			// 创建文件下载会话 | ||||||
| 			share.POST("download/:id", | 			share.POST("download/:id", | ||||||
|  | 				middleware.CheckShareUnlocked(), | ||||||
| 				middleware.BeforeShareDownload(), | 				middleware.BeforeShareDownload(), | ||||||
| 				controllers.GetShareDownload, | 				controllers.GetShareDownload, | ||||||
| 			) | 			) | ||||||
| 			// 预览分享文件 | 			// 预览分享文件 | ||||||
| 			share.GET("preview/:id", | 			share.GET("preview/:id", | ||||||
|  | 				middleware.CheckShareUnlocked(), | ||||||
| 				middleware.ShareCanPreview(), | 				middleware.ShareCanPreview(), | ||||||
| 				middleware.BeforeShareDownload(), | 				middleware.BeforeShareDownload(), | ||||||
| 				controllers.PreviewShare, | 				controllers.PreviewShare, | ||||||
| 			) | 			) | ||||||
| 			// 取得Office文档预览地址 | 			// 取得Office文档预览地址 | ||||||
| 			share.GET("doc/:id", middleware.ShareCanPreview(), | 			share.GET("doc/:id", | ||||||
|  | 				middleware.CheckShareUnlocked(), | ||||||
|  | 				middleware.ShareCanPreview(), | ||||||
| 				middleware.BeforeShareDownload(), | 				middleware.BeforeShareDownload(), | ||||||
| 				controllers.GetShareDocPreview, | 				controllers.GetShareDocPreview, | ||||||
| 			) | 			) | ||||||
| 			// 获取文本文件内容 | 			// 获取文本文件内容 | ||||||
| 			share.GET("content/:id", | 			share.GET("content/:id", | ||||||
|  | 				middleware.CheckShareUnlocked(), | ||||||
| 				middleware.BeforeShareDownload(), | 				middleware.BeforeShareDownload(), | ||||||
| 				controllers.PreviewShareText, | 				controllers.PreviewShareText, | ||||||
| 			) | 			) | ||||||
|  | 			// 分享目录列文件 | ||||||
|  | 			share.GET("list/:id/*path", | ||||||
|  | 				middleware.CheckShareUnlocked(), | ||||||
|  | 				controllers.ListSharedFolder, | ||||||
|  | 			) | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// 需要登录保护的 | 		// 需要登录保护的 | ||||||
| @ -272,6 +282,7 @@ func InitMasterRouter() *gin.Engine { | |||||||
| 				// 转存他人分享 | 				// 转存他人分享 | ||||||
| 				share.POST("save/:id", | 				share.POST("save/:id", | ||||||
| 					middleware.ShareAvailable(), | 					middleware.ShareAvailable(), | ||||||
|  | 					middleware.CheckShareUnlocked(), | ||||||
| 					middleware.BeforeShareDownload(), | 					middleware.BeforeShareDownload(), | ||||||
| 					controllers.SaveShare, | 					controllers.SaveShare, | ||||||
| 				) | 				) | ||||||
|  | |||||||
| @ -10,6 +10,7 @@ import ( | |||||||
| 	"github.com/HFO4/cloudreve/pkg/util" | 	"github.com/HFO4/cloudreve/pkg/util" | ||||||
| 	"github.com/HFO4/cloudreve/service/explorer" | 	"github.com/HFO4/cloudreve/service/explorer" | ||||||
| 	"github.com/gin-gonic/gin" | 	"github.com/gin-gonic/gin" | ||||||
|  | 	"path" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // ShareGetService 获取分享服务 | // ShareGetService 获取分享服务 | ||||||
| @ -17,9 +18,10 @@ type ShareGetService struct { | |||||||
| 	Password string `form:"password" binding:"max=255"` | 	Password string `form:"password" binding:"max=255"` | ||||||
| } | } | ||||||
|  |  | ||||||
| // SingleFileService 对单文件进行操作的服务,path为可选文件完整路径 | // ShareService 对分享进行操作的服务, | ||||||
| type SingleFileService struct { | // path 为可选文件完整路径,在目录分享下有效 | ||||||
| 	Path string `form:"path" binding:"max=65535"` | type ShareService struct { | ||||||
|  | 	Path string `form:"path" uri:"path" binding:"max=65535"` | ||||||
| } | } | ||||||
|  |  | ||||||
| // Get 获取分享内容 | // Get 获取分享内容 | ||||||
| @ -59,7 +61,7 @@ func (service *ShareGetService) Get(c *gin.Context) serializer.Response { | |||||||
| } | } | ||||||
|  |  | ||||||
| // CreateDownloadSession 创建下载会话 | // CreateDownloadSession 创建下载会话 | ||||||
| func (service *SingleFileService) CreateDownloadSession(c *gin.Context) serializer.Response { | func (service *ShareService) CreateDownloadSession(c *gin.Context) serializer.Response { | ||||||
| 	shareCtx, _ := c.Get("share") | 	shareCtx, _ := c.Get("share") | ||||||
| 	share := shareCtx.(*model.Share) | 	share := shareCtx.(*model.Share) | ||||||
| 	userCtx, _ := c.Get("user") | 	userCtx, _ := c.Get("user") | ||||||
| @ -92,7 +94,7 @@ func (service *SingleFileService) CreateDownloadSession(c *gin.Context) serializ | |||||||
|  |  | ||||||
| // PreviewContent 预览文件,需要登录会话, isText - 是否为文本文件,文本文件会 | // PreviewContent 预览文件,需要登录会话, isText - 是否为文本文件,文本文件会 | ||||||
| // 强制经由服务端中转 | // 强制经由服务端中转 | ||||||
| func (service *SingleFileService) PreviewContent(ctx context.Context, c *gin.Context, isText bool) serializer.Response { | func (service *ShareService) PreviewContent(ctx context.Context, c *gin.Context, isText bool) serializer.Response { | ||||||
| 	shareCtx, _ := c.Get("share") | 	shareCtx, _ := c.Get("share") | ||||||
| 	share := shareCtx.(*model.Share) | 	share := shareCtx.(*model.Share) | ||||||
|  |  | ||||||
| @ -106,7 +108,7 @@ func (service *SingleFileService) PreviewContent(ctx context.Context, c *gin.Con | |||||||
| } | } | ||||||
|  |  | ||||||
| // CreateDocPreviewSession 创建Office预览会话,返回预览地址 | // CreateDocPreviewSession 创建Office预览会话,返回预览地址 | ||||||
| func (service *SingleFileService) CreateDocPreviewSession(c *gin.Context) serializer.Response { | func (service *ShareService) CreateDocPreviewSession(c *gin.Context) serializer.Response { | ||||||
| 	shareCtx, _ := c.Get("share") | 	shareCtx, _ := c.Get("share") | ||||||
| 	share := shareCtx.(*model.Share) | 	share := shareCtx.(*model.Share) | ||||||
|  |  | ||||||
| @ -120,7 +122,7 @@ func (service *SingleFileService) CreateDocPreviewSession(c *gin.Context) serial | |||||||
| } | } | ||||||
|  |  | ||||||
| // SaveToMyFile 将此分享转存到自己的网盘 | // SaveToMyFile 将此分享转存到自己的网盘 | ||||||
| func (service *SingleFileService) SaveToMyFile(c *gin.Context) serializer.Response { | func (service *ShareService) SaveToMyFile(c *gin.Context) serializer.Response { | ||||||
| 	shareCtx, _ := c.Get("share") | 	shareCtx, _ := c.Get("share") | ||||||
| 	share := shareCtx.(*model.Share) | 	share := shareCtx.(*model.Share) | ||||||
| 	userCtx, _ := c.Get("user") | 	userCtx, _ := c.Get("user") | ||||||
| @ -151,3 +153,43 @@ func (service *SingleFileService) SaveToMyFile(c *gin.Context) serializer.Respon | |||||||
|  |  | ||||||
| 	return serializer.Response{} | 	return serializer.Response{} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // List 列出分享的目录下的对象 | ||||||
|  | func (service *ShareService) List(c *gin.Context) serializer.Response { | ||||||
|  | 	shareCtx, _ := c.Get("share") | ||||||
|  | 	share := shareCtx.(*model.Share) | ||||||
|  |  | ||||||
|  | 	if !share.IsDir { | ||||||
|  | 		return serializer.ParamErr("此分享无法列目录", nil) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if !path.IsAbs(service.Path) { | ||||||
|  | 		return serializer.ParamErr("路径无效", nil) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// 创建文件系统 | ||||||
|  | 	fs, err := filesystem.NewFileSystem(share.GetCreator()) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return serializer.Err(serializer.CodePolicyNotAllowed, err.Error(), err) | ||||||
|  | 	} | ||||||
|  | 	defer fs.Recycle() | ||||||
|  |  | ||||||
|  | 	// 上下文 | ||||||
|  | 	ctx, cancel := context.WithCancel(context.Background()) | ||||||
|  | 	defer cancel() | ||||||
|  |  | ||||||
|  | 	// 重设根目录 | ||||||
|  | 	fs.SetTargetDir(&[]model.Folder{*share.GetSource().(*model.Folder)}) | ||||||
|  | 	fs.DirTarget[0].Name = "/" | ||||||
|  |  | ||||||
|  | 	// 获取子项目 | ||||||
|  | 	objects, err := fs.List(ctx, service.Path, nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return serializer.Err(serializer.CodeCreateFolderFailed, err.Error(), err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return serializer.Response{ | ||||||
|  | 		Code: 0, | ||||||
|  | 		Data: objects, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 HFO4
					HFO4