diff --git a/jambotron-ui/src/app/components/file-browser-with-tree-component/file-browser-with-tree-component.html b/jambotron-ui/src/app/components/file-browser-with-tree-component/file-browser-with-tree-component.html
index c43553b..ce91847 100644
--- a/jambotron-ui/src/app/components/file-browser-with-tree-component/file-browser-with-tree-component.html
+++ b/jambotron-ui/src/app/components/file-browser-with-tree-component/file-browser-with-tree-component.html
@@ -9,6 +9,7 @@
diff --git a/jambotron-ui/src/app/components/file-browser-with-tree-component/file-browser-with-tree-component.ts b/jambotron-ui/src/app/components/file-browser-with-tree-component/file-browser-with-tree-component.ts
index 51da533..6ca6800 100644
--- a/jambotron-ui/src/app/components/file-browser-with-tree-component/file-browser-with-tree-component.ts
+++ b/jambotron-ui/src/app/components/file-browser-with-tree-component/file-browser-with-tree-component.ts
@@ -1,4 +1,4 @@
-import {Component, CUSTOM_ELEMENTS_SCHEMA, OnInit, ViewChild} from '@angular/core';
+import {Component, CUSTOM_ELEMENTS_SCHEMA, Input, OnInit, ViewChild} from '@angular/core';
import {DatePipe, NgForOf, NgIf} from '@angular/common';
import {
MatCell,
@@ -83,11 +83,18 @@ export class FileBrowserWithTreeComponent implements OnInit {
searchQuery = '';
filteredFiles: FileItem[] = [];
+ @Input() baseUrl: string = '';
+
constructor(
private fileService: FileBrowserTreeService,
private dialog: MatDialog,
private snackBar: MatSnackBar
- ) {}
+ ) {
+ if(this.baseUrl.length>0){
+ fileService.baseUrl = this.baseUrl;
+ }
+
+ }
ngOnInit(): void {
this.loadFiles(this.currentPath);
diff --git a/jambotron-ui/src/app/components/file-system-tree-component/file-system-tree-component.ts b/jambotron-ui/src/app/components/file-system-tree-component/file-system-tree-component.ts
index 550d7f7..9850b32 100644
--- a/jambotron-ui/src/app/components/file-system-tree-component/file-system-tree-component.ts
+++ b/jambotron-ui/src/app/components/file-system-tree-component/file-system-tree-component.ts
@@ -7,8 +7,8 @@ import {
inject,
signal,
Output,
- EventEmitter
- } from '@angular/core';
+ EventEmitter, Input, OnInit
+} from '@angular/core';
import {BehaviorSubject, merge, Observable} from 'rxjs';
import {map} from 'rxjs/operators';
import {MatProgressBarModule} from '@angular/material/progress-bar';
@@ -38,19 +38,24 @@ class DynamicFlatNode {
@Injectable({providedIn: 'root'})
export class DynamicDatabase {
-
rootNodes:FileItem[] = [];
constructor(private fileBrowserService: FileBrowserTreeService) {
- this.getFileItems('/').subscribe(
- value => {
- console.log('value', value);
- this.rootNodes = value;
- },
- error => {
- console.error('Error loading files:', error);
- }
- )
+ // this.getFileItems('/').subscribe(
+ // value => {
+ // console.log('value', value);
+ // this.rootNodes = value;
+ // },
+ // error => {
+ // console.error('Error loading files:', error);
+ // }
+ // )
+
+ //this.fileBrowserService.baseUrl
+ }
+
+ setBaseUrl(baseUrl: string) {
+ this.fileBrowserService.baseUrl = baseUrl;
}
getFileItems(path:string):Observable {
@@ -182,7 +187,7 @@ export class DynamicDataSource implements DataSource {
],
changeDetection: ChangeDetectionStrategy.OnPush,
})
-export class FileSystemTreeComponent {
+export class FileSystemTreeComponent implements OnInit{
database = inject(DynamicDatabase);
treeControl: FlatTreeControl;
dataSource: DynamicDataSource;
@@ -190,12 +195,23 @@ export class FileSystemTreeComponent {
@Output() folderSelected = new EventEmitter();
+ @Input() baseUrl: string = '';
+
constructor() {
+
this.treeControl = new FlatTreeControl(this.getLevel, this.isExpandable);
this.dataSource = new DynamicDataSource(this.treeControl, this.database);
+
+ }
+
+ ngOnInit(): void {
+ if(this.baseUrl.length>0){
+ this.database.setBaseUrl(this.baseUrl);
+ }
+
// Initialize root data
this.refresh();
}
diff --git a/jambotron-ui/src/app/modules/admin-module/admin.routing.ts b/jambotron-ui/src/app/modules/admin-module/admin.routing.ts
index 68bb0ac..22d8173 100644
--- a/jambotron-ui/src/app/modules/admin-module/admin.routing.ts
+++ b/jambotron-ui/src/app/modules/admin-module/admin.routing.ts
@@ -26,7 +26,7 @@ export const ADMIN_ROUTES: Routes = [
{
path: 'users',
loadComponent: () => import('../admin-module/users.component/users.component').then((c) => c.UsersComponent),
- data:{title: 'Users', icon:'', nav:true}
+ data:{title: 'Users', icon:'manage_accounts', nav:true}
},
{
path: 'hard-drive-browser',
diff --git a/jambotron-ui/src/app/modules/admin-module/hard-drive-browser.component/hard-drive-browser.component.html b/jambotron-ui/src/app/modules/admin-module/hard-drive-browser.component/hard-drive-browser.component.html
index cdc5540..9579420 100644
--- a/jambotron-ui/src/app/modules/admin-module/hard-drive-browser.component/hard-drive-browser.component.html
+++ b/jambotron-ui/src/app/modules/admin-module/hard-drive-browser.component/hard-drive-browser.component.html
@@ -1 +1,3 @@
-
+
diff --git a/jambotron-ui/src/app/modules/admin-module/hard-drive-browser.component/hard-drive-browser.component.ts b/jambotron-ui/src/app/modules/admin-module/hard-drive-browser.component/hard-drive-browser.component.ts
index 5cadb59..0decc04 100644
--- a/jambotron-ui/src/app/modules/admin-module/hard-drive-browser.component/hard-drive-browser.component.ts
+++ b/jambotron-ui/src/app/modules/admin-module/hard-drive-browser.component/hard-drive-browser.component.ts
@@ -2,6 +2,7 @@ import { Component } from '@angular/core';
import {
FileBrowserWithTreeComponent
} from '../../../components/file-browser-with-tree-component/file-browser-with-tree-component';
+import {GlobalConstants} from '../../../global-constants';
@Component({
selector: 'app-hard-drive-browser.component',
@@ -12,5 +13,6 @@ import {
styleUrl: './hard-drive-browser.component.scss'
})
export class HardDriveBrowserComponent {
+ baseUrl = `${GlobalConstants.API_URL}/admin/file-browser-tree`;
}
diff --git a/jambotron-ui/src/app/modules/user-module/files-browser.component/files-browser.component.html b/jambotron-ui/src/app/modules/user-module/files-browser.component/files-browser.component.html
new file mode 100644
index 0000000..9579420
--- /dev/null
+++ b/jambotron-ui/src/app/modules/user-module/files-browser.component/files-browser.component.html
@@ -0,0 +1,3 @@
+
diff --git a/jambotron-ui/src/app/modules/user-module/files-browser.component/files-browser.component.scss b/jambotron-ui/src/app/modules/user-module/files-browser.component/files-browser.component.scss
new file mode 100644
index 0000000..e69de29
diff --git a/jambotron-ui/src/app/modules/user-module/files-browser.component/files-browser.component.spec.ts b/jambotron-ui/src/app/modules/user-module/files-browser.component/files-browser.component.spec.ts
new file mode 100644
index 0000000..ca87df2
--- /dev/null
+++ b/jambotron-ui/src/app/modules/user-module/files-browser.component/files-browser.component.spec.ts
@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { FilesBrowserComponent } from './files-browser.component';
+
+describe('FilesBrowserComponent', () => {
+ let component: FilesBrowserComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [FilesBrowserComponent]
+ })
+ .compileComponents();
+
+ fixture = TestBed.createComponent(FilesBrowserComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/jambotron-ui/src/app/modules/user-module/files-browser.component/files-browser.component.ts b/jambotron-ui/src/app/modules/user-module/files-browser.component/files-browser.component.ts
new file mode 100644
index 0000000..5d1bcc6
--- /dev/null
+++ b/jambotron-ui/src/app/modules/user-module/files-browser.component/files-browser.component.ts
@@ -0,0 +1,21 @@
+import {Component, OnInit} from '@angular/core';
+import {
+ FileBrowserWithTreeComponent
+} from '../../../components/file-browser-with-tree-component/file-browser-with-tree-component';
+import {GlobalConstants} from '../../../global-constants';
+
+@Component({
+ selector: 'app-files-browser.component',
+ imports: [
+ FileBrowserWithTreeComponent
+ ],
+ templateUrl: './files-browser.component.html',
+ styleUrl: './files-browser.component.scss'
+})
+export class FilesBrowserComponent implements OnInit{
+ baseUrl: string ='';
+ ngOnInit(): void {
+ this.baseUrl= `${GlobalConstants.API_URL}/user/file-browser-tree`;
+ }
+
+}
diff --git a/jambotron-ui/src/app/modules/user-module/user.routing.ts b/jambotron-ui/src/app/modules/user-module/user.routing.ts
index 52fdf7f..7117fc4 100644
--- a/jambotron-ui/src/app/modules/user-module/user.routing.ts
+++ b/jambotron-ui/src/app/modules/user-module/user.routing.ts
@@ -31,6 +31,11 @@ export const USER_ROUTS: Routes = [
loadComponent: () => import('../user-module/tutorial-edit.component/tutorial-edit.component').then((c) => c.TutorialEditComponent),
data:{title: 'Edit Tutorial'}
},
+ {
+ path: 'files-browser',
+ loadComponent: ()=>import('../user-module/files-browser.component/files-browser.component').then((c)=>c.FilesBrowserComponent),
+ data:{title: 'Files Browser', icon:'folder_data', nav:true}
+ },
{
path: 'ai-models',
loadComponent: () => import('../user-module/ai-models.component/ai-models.component').then((c) => c.AiModelsComponent),
diff --git a/jambotron-ui/src/app/services/file-browser-tree.service.ts b/jambotron-ui/src/app/services/file-browser-tree.service.ts
index cb9763f..eba9298 100644
--- a/jambotron-ui/src/app/services/file-browser-tree.service.ts
+++ b/jambotron-ui/src/app/services/file-browser-tree.service.ts
@@ -16,23 +16,16 @@ export interface FileItem {
providedIn: 'root'
})
export class FileBrowserTreeService {
- private baseUrl = `${GlobalConstants.API_URL}/file-browser-tree/files`;
+ public baseUrl = `${GlobalConstants.API_URL}/user/file-browser-tree`;
constructor(private http: HttpClient) {}
getFiles(path: string): Observable {
const encodedPath = encodeURIComponent(path);
- return this.http.get(`${this.baseUrl}?path=${encodedPath}`);
+ return this.http.get(`${this.baseUrl}/files?path=${encodedPath}`);
}
- // New method to get only folders for tree view
- getFolders(path: string): Observable {
- const encodedPath = encodeURIComponent(path);
- return this.http.get(`${this.baseUrl}?path=${encodedPath}`)
- .pipe(
- map(files => files.filter(file => file.type === 'directory'))
- );
- }
+
// Alternative: dedicated backend endpoint for folders only
getFoldersOnly(path: string): Observable {
diff --git a/src/main/java/com/jambotronGroup/jambotron/controllers/FileBrowserTreeController.java b/src/main/java/com/jambotronGroup/jambotron/controllers/FileBrowserTreeController.java
index 898c040..3f79271 100644
--- a/src/main/java/com/jambotronGroup/jambotron/controllers/FileBrowserTreeController.java
+++ b/src/main/java/com/jambotronGroup/jambotron/controllers/FileBrowserTreeController.java
@@ -1,9 +1,12 @@
package com.jambotronGroup.jambotron.controllers;
import com.jambotronGroup.jambotron.fileBrowserTree.CreateFolderRequest;
+import com.jambotronGroup.jambotron.fileBrowserTree.FileBrowserTreeExtendedService;
import com.jambotronGroup.jambotron.fileBrowserTree.FileItemDto;
import com.jambotronGroup.jambotron.fileBrowserTree.FileBrowserTreeService;
import com.jambotronGroup.jambotron.fileUpload.ResponseMessage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
@@ -15,19 +18,24 @@ import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
+
@RestController
-@RequestMapping("/api/file-browser-tree/files")
+@RequestMapping("/api/user/file-browser-tree")
public class FileBrowserTreeController {
+ private final Logger _logger = LoggerFactory.getLogger(FileBrowserTreeController.class);
@Autowired
private FileBrowserTreeService fileBrowserTreeService;
+
@GetMapping
+ @RequestMapping("/files")
public ResponseEntity> getFiles(@RequestParam String path) {
try {
List files = fileBrowserTreeService.listFiles(path);
return ResponseEntity.ok(files);
} catch (Exception e) {
+ _logger.error("Error retrieving files from path: {}", path, e.getMessage());
return ResponseEntity.badRequest().build();
}
}
@@ -39,10 +47,12 @@ public class FileBrowserTreeController {
List folders = fileBrowserTreeService.listFolders(path);
return ResponseEntity.ok(folders);
} catch (Exception e) {
+ _logger.error("Error retrieving folders from path: {}", path, e.getMessage());
return ResponseEntity.badRequest().build();
}
}
+
// Search endpoint
@GetMapping("/search")
public ResponseEntity> searchFiles(
@@ -52,6 +62,7 @@ public class FileBrowserTreeController {
List files = fileBrowserTreeService.searchFiles(path, query);
return ResponseEntity.ok(files);
} catch (Exception e) {
+ _logger.error("Error searching files in path: {} with query: {}", path, query, e.getMessage());
return ResponseEntity.badRequest().build();
}
}
@@ -68,6 +79,7 @@ public class FileBrowserTreeController {
"attachment; filename=\"" + filename + "\"")
.body(resource);
} catch (Exception e) {
+ _logger.error("Error downloading file from path: {}", path, e.getMessage());
return ResponseEntity.notFound().build();
}
}
@@ -80,6 +92,7 @@ public class FileBrowserTreeController {
fileBrowserTreeService.storeFile(file, path);
return ResponseEntity.ok(new ResponseMessage("File uploaded successfully: " + file.getOriginalFilename()));
} catch (IOException e) {
+ _logger.error("Error uploading file: {}", file.getOriginalFilename(), e.getMessage());
return ResponseEntity.badRequest()
.body(new ResponseMessage("Failed to upload file: " + e.getMessage()));
}
diff --git a/src/main/java/com/jambotronGroup/jambotron/controllers/FileBrowserTreeExtendedController.java b/src/main/java/com/jambotronGroup/jambotron/controllers/FileBrowserTreeExtendedController.java
new file mode 100644
index 0000000..4083686
--- /dev/null
+++ b/src/main/java/com/jambotronGroup/jambotron/controllers/FileBrowserTreeExtendedController.java
@@ -0,0 +1,146 @@
+package com.jambotronGroup.jambotron.controllers;
+
+import com.jambotronGroup.jambotron.fileBrowserTree.CreateFolderRequest;
+import com.jambotronGroup.jambotron.fileBrowserTree.FileBrowserTreeExtendedService;
+import com.jambotronGroup.jambotron.fileBrowserTree.FileItemDto;
+import com.jambotronGroup.jambotron.fileUpload.ResponseMessage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.Resource;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.util.List;
+
+@RestController
+@RequestMapping("/api/admin/file-browser-tree")
+public class FileBrowserTreeExtendedController {
+
+ private final Logger _logger = LoggerFactory.getLogger(FileBrowserTreeExtendedService.class);
+
+ @Autowired
+ private FileBrowserTreeExtendedService fileBrowserTreeService;
+
+
+ @GetMapping
+ @RequestMapping("/files")
+ public ResponseEntity> getFiles(@RequestParam String path) {
+ try {
+ List files = fileBrowserTreeService.listFiles(path);
+ return ResponseEntity.ok(files);
+ } catch (Exception e) {
+ _logger.error("Error retrieving files from path: {}", path, e.getMessage());
+ return ResponseEntity.badRequest().build();
+ }
+ }
+
+ // New endpoint specifically for folders only (for tree view)
+ @GetMapping("/folders")
+ public ResponseEntity> getFolders(@RequestParam String path) {
+ try {
+ List folders = fileBrowserTreeService.listFolders(path);
+ return ResponseEntity.ok(folders);
+ } catch (Exception e) {
+ _logger.error("Error retrieving folders from path: {}", path, e.getMessage());
+ return ResponseEntity.badRequest().build();
+ }
+ }
+
+
+ // Search endpoint
+ @GetMapping("/search")
+ public ResponseEntity> searchFiles(
+ @RequestParam String path,
+ @RequestParam String query) {
+ try {
+ List files = fileBrowserTreeService.searchFiles(path, query);
+ return ResponseEntity.ok(files);
+ } catch (Exception e) {
+ _logger.error("Error searching files in path: {} with query: {}", path, query, e.getMessage());
+ return ResponseEntity.badRequest().build();
+ }
+ }
+
+ @GetMapping("/download")
+ public ResponseEntity downloadFile(@RequestParam String path) {
+ try {
+ Resource resource = fileBrowserTreeService.loadFileAsResource(path);
+ String filename = resource.getFilename();
+
+ return ResponseEntity.ok()
+ .contentType(MediaType.APPLICATION_OCTET_STREAM)
+ .header(HttpHeaders.CONTENT_DISPOSITION,
+ "attachment; filename=\"" + filename + "\"")
+ .body(resource);
+ } catch (Exception e) {
+ _logger.error("Error downloading file from path: {}", path, e.getMessage());
+ return ResponseEntity.notFound().build();
+ }
+ }
+
+ @PostMapping("/upload")
+ public ResponseEntity uploadFile(
+ @RequestParam("file") MultipartFile file,
+ @RequestParam("path") String path) {
+ try {
+ fileBrowserTreeService.storeFile(file, path);
+ return ResponseEntity.ok(new ResponseMessage("File uploaded successfully: " + file.getOriginalFilename()));
+ } catch (IOException e) {
+ return ResponseEntity.badRequest()
+ .body(new ResponseMessage("Failed to upload file: " + e.getMessage()));
+ }
+ }
+
+ @PostMapping("/folder")
+ public ResponseEntity createFolder(@RequestBody CreateFolderRequest request) {
+ try {
+ fileBrowserTreeService.createFolder(request.getPath(), request.getName());
+ return ResponseEntity.ok(new ResponseMessage("Folder created successfully: " + request.getName()));
+ } catch (IOException e) {
+ return ResponseEntity.badRequest()
+ .body(new ResponseMessage("Failed to create folder: " + e.getMessage()));
+ }
+ }
+
+ @DeleteMapping
+ public ResponseEntity deleteFile(@RequestParam String path) {
+ try {
+ fileBrowserTreeService.deleteFile(path);
+ return ResponseEntity.ok(new ResponseMessage("File deleted successfully: " + path));
+ } catch (IOException e) {
+ return ResponseEntity.badRequest()
+ .body(new ResponseMessage("Failed to delete file/folder: " + e.getMessage()));
+ }
+ }
+
+ // Move/rename endpoint
+ @PostMapping("/move")
+ public ResponseEntity moveFile(@RequestBody FileBrowserTreeController.MoveRequest request) {
+ try {
+ fileBrowserTreeService.moveFile(request.getSourcePath(), request.getTargetPath());
+ return ResponseEntity.ok(new ResponseMessage("File moved successfully from " + request.getSourcePath() + " to " + request.getTargetPath()));
+ } catch (IOException e) {
+ return ResponseEntity.badRequest()
+ .body(new ResponseMessage("Failed to move file: " + e.getMessage()));
+ }
+ }
+
+ // Copy endpoint
+ @PostMapping("/copy")
+ public ResponseEntity copyFile(@RequestBody FileBrowserTreeController.CopyRequest request) {
+ try {
+ fileBrowserTreeService.copyFile(request.getSourcePath(), request.getTargetPath());
+ return ResponseEntity.ok(new ResponseMessage("File copied successfully from " + request.getSourcePath() + " to " + request.getTargetPath()));
+ } catch (IOException e) {
+ return ResponseEntity.badRequest()
+ .body(new ResponseMessage("Failed to copy file: " + e.getMessage()));
+ }
+ }
+
+
+}
diff --git a/src/main/java/com/jambotronGroup/jambotron/controllers/FilesController.java b/src/main/java/com/jambotronGroup/jambotron/controllers/FilesController.java
index aec30d6..a81d7ca 100644
--- a/src/main/java/com/jambotronGroup/jambotron/controllers/FilesController.java
+++ b/src/main/java/com/jambotronGroup/jambotron/controllers/FilesController.java
@@ -78,9 +78,9 @@ public class FilesController {
response.getBody() // File content
);
- User user = authenticationFacade.getUser();
- storageService.save(user.getId().toString(), multipartFile);
+
+ storageService.save(multipartFile);
message = "Uploaded the file successfully: " + fileName;
@@ -104,7 +104,7 @@ public class FilesController {
try {
User user = authenticationFacade.getUser();
- String localFullFileName = storageService.save(user.getId().toString(), file);
+ String localFullFileName = storageService.save(file);
FileInfo fileInfo = new FileInfo(
file.getOriginalFilename(),
@@ -122,9 +122,8 @@ public class FilesController {
@GetMapping("/api/user/getImages")
public ResponseEntity> getImages() {
- User user = authenticationFacade.getUser();
- List fileInfos = storageService.loadUserImages(user.getId().toString()).map(path -> {
+ List fileInfos = storageService.loadUserImages().map(path -> {
String filename = path.getFileName().toString();
String url = FilesRoutingHelper.getUserImageUrl(filename);
@@ -158,7 +157,7 @@ public class FilesController {
@ResponseBody
public ResponseEntity getUserImage(@PathVariable String filename) {
User user = authenticationFacade.getUser();
- Resource file = storageService.loadUserImage(user.getId().toString(),filename);
+ Resource file = storageService.loadUserImage(filename);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getFilename() + "\"").body(file);
}
@@ -169,7 +168,7 @@ public class FilesController {
String message = "";
try {
String filename = storageService.getFileNameFromUrl(imageUrl);
- Base64ImageResponse base64Image = storageService.getUserImageAsBase64(user.getId().toString(),filename);
+ Base64ImageResponse base64Image = storageService.getUserImageAsBase64(filename);
return ResponseEntity.ok(base64Image);
@@ -177,6 +176,10 @@ public class FilesController {
logger.error("Error retrieving base64 image for user {}: {}", user.getId(), e.getMessage());
message = "Error retrieving base64 image for fileUrl" + imageUrl + ". \tError: " + e.getMessage();
return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body(new Base64ImageResponse(message));
+ } catch (IOException e) {
+ logger.error("IO Error retrieving base64 image for user {}: {}", user.getId(), e.getMessage());
+ message = "IO Error retrieving base64 image for fileUrl" + imageUrl + ". \tError: " + e.getMessage();
+ return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body(new Base64ImageResponse(message));
}
}
@@ -190,7 +193,7 @@ public class FilesController {
try {
- String fullFileName = storageService.saveUserBase64Image(user.getId().toString(),base64ImageRequest.getData(), base64ImageRequest.getMime());
+ String fullFileName = storageService.saveUserBase64Image(base64ImageRequest.getData(), base64ImageRequest.getMime());
String url = FilesRoutingHelper.getUserImageUrl(fullFileName);
diff --git a/src/main/java/com/jambotronGroup/jambotron/controllers/TutorialController.java b/src/main/java/com/jambotronGroup/jambotron/controllers/TutorialController.java
index bad1299..1209641 100644
--- a/src/main/java/com/jambotronGroup/jambotron/controllers/TutorialController.java
+++ b/src/main/java/com/jambotronGroup/jambotron/controllers/TutorialController.java
@@ -118,7 +118,6 @@ public class TutorialController {
String newFilename = filesStorageService.getFileNameFromUrl(tutorial.getTitleimage());
Path path= filesStorageService.moveFile(
- user.getId().toString(),
tutorial.getTitleimage(),
String.format("Tutorial_%s",newFilename )
);
@@ -188,7 +187,6 @@ public class TutorialController {
filesStorageService.deletePublicFile(servImageFileName);
Path path= filesStorageService.moveFile(
- user.getId().toString(),
tutorial.getTitleimage(),
String.format("Tutorial_%s",imageFileName )
);
diff --git a/src/main/java/com/jambotronGroup/jambotron/fileBrowserTree/FileBrowserTreeExtendedService.java b/src/main/java/com/jambotronGroup/jambotron/fileBrowserTree/FileBrowserTreeExtendedService.java
new file mode 100644
index 0000000..b71a981
--- /dev/null
+++ b/src/main/java/com/jambotronGroup/jambotron/fileBrowserTree/FileBrowserTreeExtendedService.java
@@ -0,0 +1,29 @@
+package com.jambotronGroup.jambotron.fileBrowserTree;
+
+import com.jambotronGroup.jambotron.globalConstants.GlobalConstants;
+import com.jambotronGroup.jambotron.model.ERole;
+import com.jambotronGroup.jambotron.security.AuthenticationFacade;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.nio.file.Path;
+
+@Service
+
+public class FileBrowserTreeExtendedService extends FileBrowserTreeService {
+
+ @Override
+ protected Path getRootPath() {
+
+ boolean isAdmin = super.authenticationFacade.getUser()
+ .getRoles().stream()
+ .anyMatch(role -> role.getName().equals(ERole.ROLE_ADMIN));
+
+ if( isAdmin ) {
+ return GlobalConstants.PATH_ROOT.toAbsolutePath();
+ } else {
+
+ return super.getRootPath();
+ }
+ }
+}
diff --git a/src/main/java/com/jambotronGroup/jambotron/fileBrowserTree/FileBrowserTreeService.java b/src/main/java/com/jambotronGroup/jambotron/fileBrowserTree/FileBrowserTreeService.java
index 9c46266..46f0a7f 100644
--- a/src/main/java/com/jambotronGroup/jambotron/fileBrowserTree/FileBrowserTreeService.java
+++ b/src/main/java/com/jambotronGroup/jambotron/fileBrowserTree/FileBrowserTreeService.java
@@ -1,5 +1,6 @@
package com.jambotronGroup.jambotron.fileBrowserTree;
+import com.jambotronGroup.jambotron.globalConstants.GlobalConstants;
import com.jambotronGroup.jambotron.model.ERole;
import com.jambotronGroup.jambotron.security.AuthenticationFacade;
import org.springframework.beans.factory.annotation.Autowired;
@@ -20,24 +21,20 @@ import java.util.stream.Stream;
public class FileBrowserTreeService {
@Autowired
- private AuthenticationFacade authenticationFacade;
+ protected AuthenticationFacade authenticationFacade;
- private final Path root = Paths.get("/jambotron_data");
- private Path getRootPath() {
- boolean isAdmin = authenticationFacade.getUser()
- .getRoles().stream()
- .anyMatch(role -> role.getName().equals(ERole.ROLE_ADMIN));
-
- if(isAdmin){
- // Admins can access the root directory
- return root.normalize().toAbsolutePath();
- }
- return root.resolve(authenticationFacade.getUser().getUsername()).normalize().toAbsolutePath();
+ //private final Path root = Paths.get("/jambotron_data");
+ //private final Path rootUsers = root.resolve("users");
+ protected Path getRootPath() {
+ GlobalConstants.PATH_USERS.toFile().mkdir();
+ Path userFolder = GlobalConstants.PATH_USERS.resolve(authenticationFacade.getUser().getUsername()).toAbsolutePath();
+ userFolder.toFile().mkdir();
+ return userFolder;
}
private Path resolvePath(String path) throws IOException {
Path root = getRootPath();
Path resolvedPath = root.resolve(path.startsWith("/") ? path.substring(1) : path)
- .normalize().toAbsolutePath();
+ .normalize();
// Security check: ensure the resolved path is within the root directory
if (!resolvedPath.startsWith(root)) {
@@ -47,6 +44,7 @@ public class FileBrowserTreeService {
return resolvedPath;
}
+
public List listFiles(String path) throws IOException {
Path targetPath = resolvePath(path);
diff --git a/src/main/java/com/jambotronGroup/jambotron/fileUpload/FilesStorageService.java b/src/main/java/com/jambotronGroup/jambotron/fileUpload/FilesStorageService.java
index 764d26f..573e079 100644
--- a/src/main/java/com/jambotronGroup/jambotron/fileUpload/FilesStorageService.java
+++ b/src/main/java/com/jambotronGroup/jambotron/fileUpload/FilesStorageService.java
@@ -5,6 +5,7 @@ import org.springframework.core.io.Resource;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
+import java.io.IOException;
import java.nio.file.Path;
import java.util.stream.Stream;
@@ -13,25 +14,24 @@ public interface FilesStorageService {
public String getFileNameFromUrl(String urlString);
- public String save(String userID,MultipartFile file);
+ public String save(MultipartFile file);
+// public void saveZhipuAiImage(MultipartFile file);
- public String saveUserBase64Image(String userID, String base64Image, String mimeType);
-
- public void save(MultipartFile file);
+ public String saveUserBase64Image(String base64Image, String mimeType);
public Resource load(String filename);
- public Resource loadUserImage(String userID, String filename);
+ public Resource loadUserImage(String filename);
- public Base64ImageResponse getUserImageAsBase64(String userID, String filename);
+ public Base64ImageResponse getUserImageAsBase64(String filename) throws IOException;
- public void deleteAll();
+ public void deleteAll() throws IOException;
public Stream loadAll();
- public Stream loadUserImages(String userID);
+ public Stream loadUserImages();
- public Path moveFile(String userID, String url, String newFilename) throws Exception;
+ public Path moveFile(String url, String newFilename) throws Exception;
public void deletePublicFile(String filename);
}
\ No newline at end of file
diff --git a/src/main/java/com/jambotronGroup/jambotron/fileUpload/FilesStorageServiceImpl.java b/src/main/java/com/jambotronGroup/jambotron/fileUpload/FilesStorageServiceImpl.java
index 3ee23c1..6329c99 100644
--- a/src/main/java/com/jambotronGroup/jambotron/fileUpload/FilesStorageServiceImpl.java
+++ b/src/main/java/com/jambotronGroup/jambotron/fileUpload/FilesStorageServiceImpl.java
@@ -2,9 +2,12 @@ package com.jambotronGroup.jambotron.fileUpload;
import com.jambotronGroup.jambotron.controllers.AuthController;
+import com.jambotronGroup.jambotron.globalConstants.GlobalConstants;
import com.jambotronGroup.jambotron.payload.request.UploadImageResponse;
+import com.jambotronGroup.jambotron.security.AuthenticationFacade;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Service;
@@ -26,6 +29,9 @@ public class FilesStorageServiceImpl implements FilesStorageService {
private static final Logger _logger = LoggerFactory.getLogger(AuthController.class);
+ @Autowired
+ private AuthenticationFacade _authenticationFacade;
+
private static final Set ALLOWED_MIME = Set.of(
"image/png", "image/jpeg", "image/webp", "image/gif"
);
@@ -38,22 +44,32 @@ public class FilesStorageServiceImpl implements FilesStorageService {
);
- // Update paths to use the Docker volume
- private final Path root = Paths.get("/jambotron_data/uploads/user-images/");
- private final Path rootPublic = Paths.get("/jambotron_data/uploads/public-images/");
- // private final Path rootInitData = Pa
+ private final Path _rootPublic = GlobalConstants.PATH_PUBLIC;
+
+
@Override
public void init() {
+
try {
- Files.createDirectories(root);
- Files.createDirectories(rootPublic);
+ Files.createDirectories(GlobalConstants.PATH_USERS);
+ Files.createDirectories(_rootPublic);
} catch (IOException e) {
throw new RuntimeException("Could not initialize folder for upload!");
}
}
+ private Path getUserUploadsImagesPath() throws IOException {
+ String username = _authenticationFacade.getUser().getUsername();
+ Path rootUserUploadsImages = GlobalConstants.PATH_USERS
+ .resolve(username)
+ .resolve("uploads")
+ .resolve("images");
+ Files.createDirectories(rootUserUploadsImages);
+ return rootUserUploadsImages;
+ }
+
@Override
public String getFileNameFromUrl(String urlString){
try {
@@ -69,10 +85,10 @@ public class FilesStorageServiceImpl implements FilesStorageService {
}
@Override
- public Base64ImageResponse getUserImageAsBase64(String userID,String filename){
+ public Base64ImageResponse getUserImageAsBase64(String filename) throws IOException {
- Path userPath = this.root.resolve(userID);
- Path file = userPath.resolve(filename);
+
+ Path file = getUserUploadsImagesPath().resolve(filename);
try {
@@ -95,32 +111,32 @@ public class FilesStorageServiceImpl implements FilesStorageService {
* Moves a file from a user's directory to the public directory with a new name.
* StandardCopyOption.REPLACE_EXISTING
*
- * @param userID The ID of the user owning the file.
+
* @param url The URL of the file to move.
* @param newFilename The new name for the file in the public directory.
* @return The path to the moved file in the public directory.
*/
@Override
- public Path moveFile(String userID, String url, String newFilename) {
+ public Path moveFile(String url, String newFilename) {
String filename = this.getFileNameFromUrl(url);
try {
- Path sourcePath = this.root.resolve(userID).resolve(filename);
- Path targetPath = this.rootPublic.resolve(newFilename);
+ Path sourcePath = getUserUploadsImagesPath().resolve(filename);
+ Path targetPath = _rootPublic.resolve(newFilename);
Files.copy(sourcePath, targetPath, java.nio.file.StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
throw new RuntimeException("Could not move the file: " + e.getMessage());
}
- return this.rootPublic.resolve(newFilename);
+ return _rootPublic.resolve(newFilename);
}
@Override
public void deletePublicFile(String filename) {
try {
- Path filePath = this.rootPublic.resolve(filename);
+ Path filePath = _rootPublic.resolve(filename);
Files.deleteIfExists(filePath);
} catch (IOException e) {
throw new RuntimeException("Could not delete the file: " + e.getMessage());
@@ -131,17 +147,16 @@ public class FilesStorageServiceImpl implements FilesStorageService {
* Saves a file to a user's directory.
* uploads/user-images/{userID}/{filename}
*
- * @param userID The ID of the user.
+
* @param file The file to save.
*/
@Override
- public String save(String userID,MultipartFile file) {
+ public String save(MultipartFile file) {
Path targetPath = null;
try {
- Path path = this.root.resolve(userID);
- path.toFile().mkdirs(); // Ensure user directory exists
- targetPath = path.resolve(file.getOriginalFilename());
+ String fixedFileName = getFixedFileName(file.getOriginalFilename());
+ targetPath = getUserUploadsImagesPath().resolve(fixedFileName);
Files.copy(file.getInputStream(), targetPath,
java.nio.file.StandardCopyOption.REPLACE_EXISTING);
@@ -157,24 +172,29 @@ public class FilesStorageServiceImpl implements FilesStorageService {
return targetPath.getFileName().toString();
}
- @Override
- public void save(MultipartFile file) {
- try {
- Files.copy(file.getInputStream(), this.root.resolve(file.getOriginalFilename()),
- java.nio.file.StandardCopyOption.REPLACE_EXISTING);
- } catch (Exception e) {
- if (e instanceof FileAlreadyExistsException) {
- throw new RuntimeException("A file of that name already exists.");
- }
+ private String getFixedFileName(String filename) {
- throw new RuntimeException(e.getMessage());
- }
+ return filename.indexOf('?') != -1 ? filename.substring(0, filename.indexOf('?')) : filename;
}
+// @Override
+// public void saveZhipuAiImage(MultipartFile file) {
+// try {
+// Files.copy(file.getInputStream(), getUserRootPath().resolve(file.getOriginalFilename()),
+// java.nio.file.StandardCopyOption.REPLACE_EXISTING);
+// } catch (Exception e) {
+// if (e instanceof FileAlreadyExistsException) {
+// throw new RuntimeException("A file of that name already exists.");
+// }
+//
+// throw new RuntimeException(e.getMessage());
+// }
+// }
+
@Override
public Resource load(String filename) {
try {
- Path file = rootPublic.resolve(filename);
+ Path file = _rootPublic.resolve(filename);
Resource resource = new UrlResource(file.toUri());
if (resource.exists() || resource.isReadable()) {
@@ -188,11 +208,10 @@ public class FilesStorageServiceImpl implements FilesStorageService {
}
@Override
- public Resource loadUserImage(String userID,String filename) {
+ public Resource loadUserImage(String filename) {
try {
- Path file = root.resolve(filename);
- Path userPath = this.root.resolve(userID);
- file = userPath.resolve(filename);
+ Path file = getUserUploadsImagesPath().resolve(filename);
+
Resource resource = new UrlResource(file.toUri());
if (resource.exists() || resource.isReadable()) {
@@ -202,36 +221,49 @@ public class FilesStorageServiceImpl implements FilesStorageService {
}
} catch (MalformedURLException e) {
throw new RuntimeException("Error: " + e.getMessage());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
}
}
@Override
- public void deleteAll() {
- FileSystemUtils.deleteRecursively(root.toFile());
+ public void deleteAll() throws IOException {
+ FileSystemUtils.deleteRecursively(getUserUploadsImagesPath().toFile());
}
@Override
public Stream loadAll() {
try {
- return Files.walk(this.root, 1).filter(path -> !path.equals(this.root)).map(this.root::relativize);
+ return Files.walk(getUserUploadsImagesPath(), 1).filter(path -> {
+ try {
+ return !path.equals(getUserUploadsImagesPath());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }).map(getUserUploadsImagesPath()::relativize);
} catch (IOException e) {
throw new RuntimeException("Could not load the files!");
}
}
@Override
- public Stream loadUserImages(String userID) {
- Path userPath = this.root.resolve(userID);
- userPath.toFile().mkdirs();
+ public Stream loadUserImages() {
+
try {
- return Files.walk(userPath, 1).filter(path -> !path.equals(userPath)).map(userPath::relativize);
+ return Files.walk(getUserUploadsImagesPath(), 1).filter(path -> {
+ try {
+ return !path.equals(getUserUploadsImagesPath());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }).map(getUserUploadsImagesPath()::relativize);
} catch (IOException e) {
throw new RuntimeException("Could not load the files!");
}
}
@Override
- public String saveUserBase64Image(String userID, String base64Image, String mimeType) {
+ public String saveUserBase64Image(String base64Image, String mimeType) {
if (!ALLOWED_MIME.contains(mimeType)) {
_logger.error("Unsupported MIME type: " + mimeType);
@@ -256,17 +288,14 @@ public class FilesStorageServiceImpl implements FilesStorageService {
String id = UUID.randomUUID().toString().replace("-", "");
- String safeBaseName = "user-image-" + userID;
- String storedName = safeBaseName + "-" + id + "." + ext;
+ String safeBaseName = "user-image-";
+ String storedName = safeBaseName + id + "." + ext;
try {
- Path userPath = this.root.resolve(userID);
- userPath.toFile().mkdirs(); // Ensure user directory exists
+ Path targetPath = getUserUploadsImagesPath().resolve(storedName);
- Path targetPath = userPath.resolve(storedName);
-
- Files.write(targetPath, bytes);
+ Files.write(targetPath, bytes);
return targetPath.getFileName().toString();
diff --git a/src/main/java/com/jambotronGroup/jambotron/globalConstants/GlobalConstants.java b/src/main/java/com/jambotronGroup/jambotron/globalConstants/GlobalConstants.java
new file mode 100644
index 0000000..6613808
--- /dev/null
+++ b/src/main/java/com/jambotronGroup/jambotron/globalConstants/GlobalConstants.java
@@ -0,0 +1,11 @@
+package com.jambotronGroup.jambotron.globalConstants;
+
+import java.nio.file.Path;
+
+public class GlobalConstants {
+ public static Path PATH_ROOT = Path.of("/jambotron_data/");
+ public static Path PATH_PUBLIC = PATH_ROOT.resolve("public");
+ public static Path PATH_USERS = PATH_ROOT.resolve("users");
+ public static Path PATH_INIT_DATA = PATH_ROOT.resolve("init_data");
+ public static Path PATH_JSON_DUMP = PATH_ROOT.resolve("json_dump");
+}
diff --git a/src/main/java/com/jambotronGroup/jambotron/security/WebSecurityConfig.java b/src/main/java/com/jambotronGroup/jambotron/security/WebSecurityConfig.java
index cb5adc0..5d14135 100644
--- a/src/main/java/com/jambotronGroup/jambotron/security/WebSecurityConfig.java
+++ b/src/main/java/com/jambotronGroup/jambotron/security/WebSecurityConfig.java
@@ -119,15 +119,17 @@ public class WebSecurityConfig implements WebMvcConfigurer {// extends WebSecuri
// Access permitted for specific roles
.requestMatchers("/api/user/**").hasRole("USER")
+ .requestMatchers("/api/user/file-browser-tree/**").hasRole("USER")
+
.requestMatchers("/api/moderator/**").hasRole("MODERATOR")
- //.requestMatchers("/api/admin/**").hasRole("ADMIN")
+
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.requestMatchers("/api/admin/json-dump/**").hasRole("ADMIN")
.requestMatchers("/api/admin/json-dump/import/**").hasRole("ADMIN")
+ .requestMatchers("/api/admin/file-browser-tree/**").hasRole("ADMIN")
+
- .requestMatchers("/api/file-browser/files/**").hasAnyRole("USER", "MODERATOR", "ADMIN")
- .requestMatchers("/api/file-browser-tree/files/**").hasAnyRole("USER", "MODERATOR", "ADMIN")
.anyRequest().authenticated()
);