Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
S
SR2-projet1-VANDEWAETER
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Fabio Vandewaeter
SR2-projet1-VANDEWAETER
Commits
d5fbc88b
Commit
d5fbc88b
authored
1 month ago
by
Fabio Vandewaeter
Browse files
Options
Downloads
Patches
Plain Diff
correction download dossiers
parent
2407e888
Branches
Branches containing commit
Tags
Tags containing commit
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
src/main/java/fil/sr2/flopbox/FTPResource.java
+241
-58
241 additions, 58 deletions
src/main/java/fil/sr2/flopbox/FTPResource.java
with
241 additions
and
58 deletions
src/main/java/fil/sr2/flopbox/FTPResource.java
+
241
−
58
View file @
d5fbc88b
...
...
@@ -3,10 +3,14 @@ package fil.sr2.flopbox;
import
jakarta.ws.rs.*
;
import
jakarta.ws.rs.core.*
;
import
java.io.ByteArrayOutputStream
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.net.URI
;
import
java.util.List
;
import
java.util.zip.ZipEntry
;
import
java.util.zip.ZipInputStream
;
import
java.util.zip.ZipOutputStream
;
import
org.apache.commons.net.ftp.FTP
;
import
org.apache.commons.net.ftp.FTPClient
;
...
...
@@ -15,6 +19,7 @@ import org.apache.commons.net.ftp.FTPFile;
@Path
(
"/ftps"
)
public
class
FTPResource
{
// ======== FTP Servers ========
// GET /ftps - liste des serveurs FTP enregistrés
@GET
@Produces
(
MediaType
.
APPLICATION_JSON
)
...
...
@@ -24,18 +29,48 @@ public class FTPResource {
return
Response
.
ok
(
servers
).
build
();
}
// returns the content of the directory as an array it is a directory OR the
// content of the file
// POST /ftps - enregistre un nouveau serveur FTP
@POST
@Consumes
(
MediaType
.
APPLICATION_JSON
)
public
Response
addFTPServer
(
FTPServerConfig
config
,
@Context
UriInfo
uriInfo
)
{
System
.
out
.
println
(
"addFTPServer()"
);
boolean
created
=
FTPServerRepository
.
getInstance
().
addServer
(
config
);
if
(!
created
)
{
return
Response
.
status
(
Response
.
Status
.
CONFLICT
).
entity
(
"Alias déjà utilisé"
).
build
();
}
UriBuilder
builder
=
uriInfo
.
getAbsolutePathBuilder
();
builder
.
path
(
config
.
getAlias
());
return
Response
.
created
(
builder
.
build
()).
build
();
}
@DELETE
@Path
(
"/{alias}"
)
public
Response
removeFTPServer
(
@PathParam
(
"alias"
)
String
alias
)
{
System
.
out
.
println
(
"removeFTPServer()"
);
boolean
removed
=
FTPServerRepository
.
getInstance
().
removeServer
(
alias
);
return
removed
?
Response
.
noContent
().
build
()
:
Response
.
status
(
Response
.
Status
.
NOT_FOUND
).
build
();
}
@PUT
@Path
(
"/{alias}"
)
@Consumes
(
MediaType
.
APPLICATION_JSON
)
public
Response
updateFTPServer
(
@PathParam
(
"alias"
)
String
alias
,
FTPServerConfig
newConfig
)
{
System
.
out
.
println
(
"updateFTPServer()"
);
boolean
updated
=
FTPServerRepository
.
getInstance
().
updateServer
(
alias
,
newConfig
);
return
updated
?
Response
.
ok
(
newConfig
).
build
()
:
Response
.
status
(
Response
.
Status
.
NOT_FOUND
).
build
();
}
// =============================
// ========= Resources =========
@GET
@Path
(
"/{alias}/{path: .+}"
)
@Produces
(
MediaType
.
APPLICATION_
JSON
)
@Produces
(
{
MediaType
.
APPLICATION_
OCTET_STREAM
,
"application/zip"
}
)
public
Response
getFTPResource
(
@PathParam
(
"alias"
)
String
alias
,
@PathParam
(
"path"
)
String
path
,
@HeaderParam
(
"X-FTP-User"
)
String
user
,
@HeaderParam
(
"X-FTP-Pass"
)
String
pass
)
{
System
.
out
.
println
(
"GetFTPResource()"
);
FTPServerConfig
config
=
FTPServerRepository
.
getInstance
().
getServer
(
alias
);
if
(
config
==
null
)
{
return
Response
.
status
(
Response
.
Status
.
NOT_FOUND
)
...
...
@@ -50,42 +85,161 @@ public class FTPResource {
}
ftpClient
.
enterLocalPassiveMode
();
ftpClient
.
setFileType
(
FTP
.
BINARY_FILE_TYPE
);
// Normaliser le chemin en retirant le slash final
// Normaliser le chemin
if
(
path
.
endsWith
(
"/"
))
{
path
=
path
.
substring
(
0
,
path
.
length
()
-
1
);
}
// Vérifier si le chemin est un répertoire
// Vérifier si c'est un dossier
boolean
isDirectory
=
ftpClient
.
changeWorkingDirectory
(
path
);
if
(
isDirectory
)
{
String
currentDirectory
=
ftpClient
.
printWorkingDirectory
();
System
.
out
.
println
(
"Répertoire courant : "
+
currentDirectory
);
// Créer un ZIP du dossier
ByteArrayOutputStream
baos
=
new
ByteArrayOutputStream
();
ZipOutputStream
zos
=
new
ZipOutputStream
(
baos
);
addDirectoryToZip
(
ftpClient
,
currentDirectory
,
""
,
zos
);
zos
.
close
();
return
Response
.
ok
(
baos
.
toByteArray
())
.
type
(
"application/zip"
)
.
header
(
"Content-Disposition"
,
"attachment; filename=\""
+
getFileName
(
path
)
+
".zip\""
)
.
build
();
}
else
{
// Télécharger le fichier
InputStream
is
=
ftpClient
.
retrieveFileStream
(
path
);
if
(
is
!=
null
)
{
ByteArrayOutputStream
outputStream
=
new
ByteArrayOutputStream
();
byte
[]
buffer
=
new
byte
[
4096
];
int
bytesRead
;
while
((
bytesRead
=
is
.
read
(
buffer
))
!=
-
1
)
{
outputStream
.
write
(
buffer
,
0
,
bytesRead
);
}
is
.
close
();
ftpClient
.
completePendingCommand
();
return
Response
.
ok
(
outputStream
.
toByteArray
())
.
type
(
determineContentType
(
path
))
.
header
(
"Content-Disposition"
,
"attachment; filename=\""
+
getFileName
(
path
)
+
"\""
)
.
build
();
}
else
{
return
Response
.
status
(
Response
.
Status
.
NOT_FOUND
)
.
entity
(
"Ressource non trouvée"
).
build
();
}
}
}
catch
(
IOException
e
)
{
return
Response
.
status
(
Response
.
Status
.
INTERNAL_SERVER_ERROR
)
.
entity
(
"Erreur FTP: "
+
e
.
getMessage
()).
build
();
}
finally
{
try
{
if
(
ftpClient
.
isConnected
())
{
ftpClient
.
logout
();
ftpClient
.
disconnect
();
}
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
}
private
String
determineContentType
(
String
path
)
{
if
(
path
.
endsWith
(
".txt"
))
return
MediaType
.
TEXT_PLAIN
;
if
(
path
.
endsWith
(
".html"
))
return
MediaType
.
TEXT_HTML
;
if
(
path
.
endsWith
(
".json"
))
return
MediaType
.
APPLICATION_JSON
;
return
MediaType
.
APPLICATION_OCTET_STREAM
;
}
private
void
addDirectoryToZip
(
FTPClient
ftpClient
,
String
remotePath
,
String
basePath
,
ZipOutputStream
zos
)
throws
IOException
{
FTPFile
[]
files
=
ftpClient
.
listFiles
(
remotePath
);
if
(
files
==
null
||
files
.
length
==
0
)
{
System
.
out
.
println
(
"Aucun fichier trouvé dans le dossier : "
+
remotePath
);
return
;
}
for
(
FTPFile
file
:
files
)
{
String
filePath
=
remotePath
.
isEmpty
()
?
file
.
getName
()
:
remotePath
+
"/"
+
file
.
getName
();
String
zipEntryPath
=
basePath
.
isEmpty
()
?
file
.
getName
()
:
basePath
+
"/"
+
file
.
getName
();
if
(
file
.
isDirectory
())
{
// Ajouter une entrée de dossier au ZIP
zos
.
putNextEntry
(
new
ZipEntry
(
zipEntryPath
+
"/"
));
zos
.
closeEntry
();
// Explorer le sous-dossier récursivement
addDirectoryToZip
(
ftpClient
,
filePath
,
zipEntryPath
,
zos
);
}
else
{
// Ajouter un fichier au ZIP
ZipEntry
entry
=
new
ZipEntry
(
zipEntryPath
);
zos
.
putNextEntry
(
entry
);
InputStream
is
=
ftpClient
.
retrieveFileStream
(
filePath
);
if
(
is
==
null
)
{
System
.
out
.
println
(
"Impossible de lire le fichier : "
+
filePath
);
continue
;
}
byte
[]
buffer
=
new
byte
[
4096
];
int
bytesRead
;
while
((
bytesRead
=
is
.
read
(
buffer
))
!=
-
1
)
{
zos
.
write
(
buffer
,
0
,
bytesRead
);
}
is
.
close
();
ftpClient
.
completePendingCommand
();
// Important pour finaliser la lecture
zos
.
closeEntry
();
}
}
}
@GET
@Path
(
"/list/{alias}/{path: .+}"
)
@Produces
(
MediaType
.
APPLICATION_JSON
)
public
Response
listDirectory
(
@PathParam
(
"alias"
)
String
alias
,
@PathParam
(
"path"
)
String
path
,
@HeaderParam
(
"X-FTP-User"
)
String
user
,
@HeaderParam
(
"X-FTP-Pass"
)
String
pass
)
{
FTPServerConfig
config
=
FTPServerRepository
.
getInstance
().
getServer
(
alias
);
if
(
config
==
null
)
{
return
Response
.
status
(
Response
.
Status
.
NOT_FOUND
)
.
entity
(
"Serveur FTP non trouvé"
).
build
();
}
FTPClient
ftpClient
=
new
FTPClient
();
try
{
ftpClient
.
connect
(
config
.
getHost
(),
config
.
getPort
());
if
(!
ftpClient
.
login
(
user
,
pass
))
{
return
Response
.
status
(
Response
.
Status
.
UNAUTHORIZED
)
.
entity
(
"Authentification FTP échouée"
).
build
();
}
ftpClient
.
enterLocalPassiveMode
();
ftpClient
.
setFileType
(
FTP
.
BINARY_FILE_TYPE
);
if
(
path
.
endsWith
(
"/"
))
{
path
=
path
.
substring
(
0
,
path
.
length
()
-
1
);
}
FTPFile
[]
files
=
ftpClient
.
listFiles
(
path
);
if
(
files
==
null
||
files
.
length
==
0
)
{
return
Response
.
status
(
Response
.
Status
.
NOT_FOUND
)
.
entity
(
"Ressource non trouvée
: "
+
path
).
build
();
.
entity
(
"Ressource non trouvée: "
+
path
).
build
();
}
// Construire la structure JSON
FtpNode
root
=
buildFtpTree
(
ftpClient
,
path
);
ftpClient
.
logout
();
ftpClient
.
disconnect
();
return
Response
.
ok
(
root
).
build
();
}
catch
(
IOException
e
)
{
return
Response
.
status
(
Response
.
Status
.
INTERNAL_SERVER_ERROR
)
.
entity
(
"Erreur FTP : "
+
e
.
getMessage
()).
build
();
}
}
// Fonction récursive pour construire l'arborescence FTP
private
FtpNode
buildFtpTree
(
FTPClient
ftpClient
,
String
path
)
throws
IOException
{
FTPFile
[]
files
=
ftpClient
.
listFiles
(
path
);
FtpNode
node
=
new
FtpNode
(
getFileName
(
path
),
true
);
// Root est un dossier
if
(
files
!=
null
)
{
for
(
FTPFile
file
:
files
)
{
String
fullPath
=
path
+
"/"
+
file
.
getName
();
if
(
file
.
isDirectory
())
{
node
.
children
.
add
(
buildFtpTree
(
ftpClient
,
fullPath
));
// Récursif pour les dossiers
}
else
{
node
.
children
.
add
(
new
FtpNode
(
file
.
getName
(),
false
));
// Ajouter fichier
.
entity
(
"Erreur FTP: "
+
e
.
getMessage
()).
build
();
}
finally
{
try
{
if
(
ftpClient
.
isConnected
())
{
ftpClient
.
logout
();
ftpClient
.
disconnect
();
}
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
return
node
;
}
// Classe représentant un nœud JSON (fichier ou dossier)
...
...
@@ -103,35 +257,21 @@ public class FTPResource {
}
}
// POST /ftps - enregistre un nouveau serveur FTP
@POST
@Consumes
(
MediaType
.
APPLICATION_JSON
)
public
Response
addFTPServer
(
FTPServerConfig
config
,
@Context
UriInfo
uriInfo
)
{
System
.
out
.
println
(
"addFTPServer()"
);
boolean
created
=
FTPServerRepository
.
getInstance
().
addServer
(
config
);
if
(!
created
)
{
return
Response
.
status
(
Response
.
Status
.
CONFLICT
).
entity
(
"Alias déjà utilisé"
).
build
();
// Fonction récursive pour construire l'arborescence FTP
private
FtpNode
buildFtpTree
(
FTPClient
ftpClient
,
String
path
)
throws
IOException
{
FTPFile
[]
files
=
ftpClient
.
listFiles
(
path
);
FtpNode
node
=
new
FtpNode
(
getFileName
(
path
),
true
);
// Root est un dossier
if
(
files
!=
null
)
{
for
(
FTPFile
file
:
files
)
{
String
fullPath
=
path
+
"/"
+
file
.
getName
();
if
(
file
.
isDirectory
())
{
node
.
children
.
add
(
buildFtpTree
(
ftpClient
,
fullPath
));
// Récursif pour les dossiers
}
else
{
node
.
children
.
add
(
new
FtpNode
(
file
.
getName
(),
false
));
// Ajouter fichier
}
}
}
UriBuilder
builder
=
uriInfo
.
getAbsolutePathBuilder
();
builder
.
path
(
config
.
getAlias
());
return
Response
.
created
(
builder
.
build
()).
build
();
}
@DELETE
@Path
(
"/{alias}"
)
public
Response
removeFTPServer
(
@PathParam
(
"alias"
)
String
alias
)
{
System
.
out
.
println
(
"removeFTPServer()"
);
boolean
removed
=
FTPServerRepository
.
getInstance
().
removeServer
(
alias
);
return
removed
?
Response
.
noContent
().
build
()
:
Response
.
status
(
Response
.
Status
.
NOT_FOUND
).
build
();
}
@PUT
@Path
(
"/{alias}"
)
@Consumes
(
MediaType
.
APPLICATION_JSON
)
public
Response
updateFTPServer
(
@PathParam
(
"alias"
)
String
alias
,
FTPServerConfig
newConfig
)
{
System
.
out
.
println
(
"updateFTPServer()"
);
boolean
updated
=
FTPServerRepository
.
getInstance
().
updateServer
(
alias
,
newConfig
);
return
updated
?
Response
.
ok
(
newConfig
).
build
()
:
Response
.
status
(
Response
.
Status
.
NOT_FOUND
).
build
();
return
node
;
}
@PUT
...
...
@@ -142,18 +282,45 @@ public class FTPResource {
@PathParam
(
"path"
)
String
path
,
@HeaderParam
(
"X-FTP-User"
)
String
user
,
@HeaderParam
(
"X-FTP-Pass"
)
String
pass
,
@HeaderParam
(
"X-Zip-Extract"
)
Boolean
extractZip
,
InputStream
fileStream
)
{
System
.
out
.
println
(
"uploadFile()"
);
FTPServerConfig
config
=
FTPServerRepository
.
getInstance
().
getServer
(
alias
);
if
(
config
==
null
)
{
return
Response
.
status
(
Response
.
Status
.
NOT_FOUND
).
entity
(
"Serveur non trouvé"
).
build
();
}
FTPClient
ftp
=
new
FTPClient
();
try
{
ftp
.
connect
(
config
.
getHost
(),
config
.
getPort
());
ftp
.
login
(
user
,
pass
);
boolean
success
=
ftp
.
storeFile
(
path
,
fileStream
);
return
success
?
Response
.
ok
().
build
()
:
Response
.
status
(
Response
.
Status
.
INTERNAL_SERVER_ERROR
).
build
();
ftp
.
enterLocalPassiveMode
();
ftp
.
setFileType
(
FTP
.
BINARY_FILE_TYPE
);
if
(
extractZip
!=
null
&&
extractZip
)
{
if
(!
ftp
.
changeWorkingDirectory
(
path
))
{
return
Response
.
status
(
400
).
entity
(
"Le chemin n'est pas un dossier"
).
build
();
}
ZipInputStream
zis
=
new
ZipInputStream
(
fileStream
);
ZipEntry
entry
;
while
((
entry
=
zis
.
getNextEntry
())
!=
null
)
{
String
fullPath
=
path
+
"/"
+
entry
.
getName
();
if
(
entry
.
isDirectory
())
{
createDirectories
(
ftp
,
fullPath
);
}
else
{
String
parentDir
=
fullPath
.
substring
(
0
,
fullPath
.
lastIndexOf
(
'/'
));
createDirectories
(
ftp
,
parentDir
);
ftp
.
storeFile
(
fullPath
,
zis
);
}
zis
.
closeEntry
();
}
zis
.
close
();
return
Response
.
ok
().
build
();
}
else
{
boolean
success
=
ftp
.
storeFile
(
path
,
fileStream
);
return
success
?
Response
.
ok
().
build
()
:
Response
.
status
(
500
).
entity
(
"Erreur d'upload"
).
build
();
}
}
catch
(
IOException
e
)
{
return
Response
.
serverError
().
entity
(
e
.
getMessage
()).
build
();
return
Response
.
serverError
().
entity
(
"Erreur FTP: "
+
e
.
getMessage
()).
build
();
}
finally
{
try
{
if
(
ftp
.
isConnected
())
{
...
...
@@ -166,6 +333,21 @@ public class FTPResource {
}
}
private
void
createDirectories
(
FTPClient
ftp
,
String
path
)
throws
IOException
{
String
[]
dirs
=
path
.
split
(
"/"
);
StringBuilder
sb
=
new
StringBuilder
();
for
(
String
dir
:
dirs
)
{
if
(
dir
.
isEmpty
())
continue
;
sb
.
append
(
"/"
).
append
(
dir
);
String
currentDir
=
sb
.
toString
();
if
(!
ftp
.
changeWorkingDirectory
(
currentDir
))
{
ftp
.
makeDirectory
(
currentDir
);
ftp
.
changeWorkingDirectory
(
currentDir
);
}
}
}
@POST
@Path
(
"/{alias}/{path: .+}"
)
@Consumes
({
MediaType
.
APPLICATION_OCTET_STREAM
,
MediaType
.
TEXT_PLAIN
})
...
...
@@ -310,4 +492,5 @@ public class FTPResource {
private
String
getFileName
(
String
path
)
{
return
path
.
substring
(
path
.
lastIndexOf
(
'/'
)
+
1
);
}
// =============================
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment