@@ -105,6 +105,104 @@ func globalCopyFiles(c *gin.Context) {
105105 model .IncSync ()
106106}
107107
108+ func workspaceCopyFiles (c * gin.Context ) {
109+ ret := gulu .Ret .NewResult ()
110+ defer c .JSON (http .StatusOK , ret )
111+
112+ arg , ok := util .JsonArg (c , ret )
113+ if ! ok {
114+ return
115+ }
116+
117+ var srcsArg []any
118+ var destDirArg string // 相对于工作空间的路径
119+ if ! util .ParseJsonArgs (arg , ret ,
120+ util .BindJsonArg ("srcs" , & srcsArg , true , true ),
121+ util .BindJsonArg ("destDir" , & destDirArg , true , true ),
122+ ) {
123+ return
124+ }
125+
126+ var relSrcs []string
127+ for _ , s := range srcsArg {
128+ str , ok := s .(string ) // 相对于工作空间的路径
129+ if ! ok {
130+ ret .Code = - 1
131+ ret .Msg = "Field [srcs]: each element should be of type [String]"
132+ return
133+ }
134+ str = strings .TrimSpace (str )
135+ if str == "" {
136+ ret .Code = - 1
137+ ret .Msg = "src path must not be empty"
138+ return
139+ }
140+ relSrcs = append (relSrcs , str )
141+ }
142+
143+ destDir , err := util .GetAbsPathInWorkspace (destDirArg )
144+ if err != nil {
145+ ret .Code = http .StatusForbidden
146+ ret .Msg = err .Error ()
147+ return
148+ }
149+ if filelock .IsExist (destDir ) {
150+ destInfo , err := os .Stat (destDir )
151+ if err != nil {
152+ ret .Code = - 1
153+ ret .Msg = err .Error ()
154+ return
155+ }
156+ if ! destInfo .IsDir () {
157+ ret .Code = - 1
158+ ret .Msg = fmt .Sprintf ("destDir [%s] is not a directory" , destDirArg )
159+ return
160+ }
161+ } else {
162+ if err = os .MkdirAll (destDir , 0755 ); err != nil {
163+ logging .LogErrorf ("make dir [%s] failed: %s" , destDir , err )
164+ ret .Code = - 1
165+ ret .Msg = err .Error ()
166+ return
167+ }
168+ }
169+
170+ var absSrcs []string
171+ for _ , src := range relSrcs {
172+ absSrc , err := util .GetAbsPathInWorkspace (src )
173+ if err != nil {
174+ ret .Code = http .StatusForbidden
175+ ret .Msg = err .Error ()
176+ return
177+ }
178+ if ! filelock .IsExist (absSrc ) {
179+ logging .LogErrorf ("file [%s] does not exist" , src )
180+ ret .Code = - 1
181+ ret .Msg = fmt .Sprintf ("file [%s] does not exist" , src )
182+ return
183+ }
184+ if util .IsSensitivePath (absSrc ) {
185+ logging .LogErrorf ("refuse to copy sensitive file [%s]" , src )
186+ ret .Code = - 2
187+ ret .Msg = fmt .Sprintf ("refuse to copy sensitive file [%s]" , src )
188+ return
189+ }
190+ absSrcs = append (absSrcs , absSrc )
191+ }
192+
193+ for _ , absSrc := range absSrcs {
194+ dest := filepath .Join (destDir , filepath .Base (absSrc ))
195+ if err := filelock .Copy (absSrc , dest ); err != nil {
196+ logging .LogErrorf ("copy file [%s] to [%s] failed: %s" , absSrc , dest , err )
197+ ret .Code = - 1
198+ ret .Msg = err .Error ()
199+ return
200+ }
201+ }
202+
203+ model .IncSync ()
204+ }
205+
108206func copyFile (c * gin.Context ) {
109207 ret := gulu .Ret .NewResult ()
110208 defer c .JSON (http .StatusOK , ret )
0 commit comments