fix
This commit is contained in:
+1
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
<app-file-system-tree-component
|
<app-file-system-tree-component
|
||||||
(folderSelected)="onFolderSelected($event)"
|
(folderSelected)="onFolderSelected($event)"
|
||||||
|
[baseUrl]="baseUrl"
|
||||||
>
|
>
|
||||||
</app-file-system-tree-component>
|
</app-file-system-tree-component>
|
||||||
</mat-sidenav>
|
</mat-sidenav>
|
||||||
|
|||||||
+9
-2
@@ -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 {DatePipe, NgForOf, NgIf} from '@angular/common';
|
||||||
import {
|
import {
|
||||||
MatCell,
|
MatCell,
|
||||||
@@ -83,11 +83,18 @@ export class FileBrowserWithTreeComponent implements OnInit {
|
|||||||
searchQuery = '';
|
searchQuery = '';
|
||||||
filteredFiles: FileItem[] = [];
|
filteredFiles: FileItem[] = [];
|
||||||
|
|
||||||
|
@Input() baseUrl: string = '';
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private fileService: FileBrowserTreeService,
|
private fileService: FileBrowserTreeService,
|
||||||
private dialog: MatDialog,
|
private dialog: MatDialog,
|
||||||
private snackBar: MatSnackBar
|
private snackBar: MatSnackBar
|
||||||
) {}
|
) {
|
||||||
|
if(this.baseUrl.length>0){
|
||||||
|
fileService.baseUrl = this.baseUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.loadFiles(this.currentPath);
|
this.loadFiles(this.currentPath);
|
||||||
|
|||||||
+28
-12
@@ -7,8 +7,8 @@ import {
|
|||||||
inject,
|
inject,
|
||||||
signal,
|
signal,
|
||||||
Output,
|
Output,
|
||||||
EventEmitter
|
EventEmitter, Input, OnInit
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import {BehaviorSubject, merge, Observable} from 'rxjs';
|
import {BehaviorSubject, merge, Observable} from 'rxjs';
|
||||||
import {map} from 'rxjs/operators';
|
import {map} from 'rxjs/operators';
|
||||||
import {MatProgressBarModule} from '@angular/material/progress-bar';
|
import {MatProgressBarModule} from '@angular/material/progress-bar';
|
||||||
@@ -38,19 +38,24 @@ class DynamicFlatNode {
|
|||||||
@Injectable({providedIn: 'root'})
|
@Injectable({providedIn: 'root'})
|
||||||
export class DynamicDatabase {
|
export class DynamicDatabase {
|
||||||
|
|
||||||
|
|
||||||
rootNodes:FileItem[] = [];
|
rootNodes:FileItem[] = [];
|
||||||
|
|
||||||
constructor(private fileBrowserService: FileBrowserTreeService) {
|
constructor(private fileBrowserService: FileBrowserTreeService) {
|
||||||
this.getFileItems('/').subscribe(
|
// this.getFileItems('/').subscribe(
|
||||||
value => {
|
// value => {
|
||||||
console.log('value', value);
|
// console.log('value', value);
|
||||||
this.rootNodes = value;
|
// this.rootNodes = value;
|
||||||
},
|
// },
|
||||||
error => {
|
// error => {
|
||||||
console.error('Error loading files:', error);
|
// console.error('Error loading files:', error);
|
||||||
|
// }
|
||||||
|
// )
|
||||||
|
|
||||||
|
//this.fileBrowserService.baseUrl
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
setBaseUrl(baseUrl: string) {
|
||||||
|
this.fileBrowserService.baseUrl = baseUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
getFileItems(path:string):Observable<FileItem[]> {
|
getFileItems(path:string):Observable<FileItem[]> {
|
||||||
@@ -182,7 +187,7 @@ export class DynamicDataSource implements DataSource<DynamicFlatNode> {
|
|||||||
],
|
],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class FileSystemTreeComponent {
|
export class FileSystemTreeComponent implements OnInit{
|
||||||
database = inject(DynamicDatabase);
|
database = inject(DynamicDatabase);
|
||||||
treeControl: FlatTreeControl<DynamicFlatNode>;
|
treeControl: FlatTreeControl<DynamicFlatNode>;
|
||||||
dataSource: DynamicDataSource;
|
dataSource: DynamicDataSource;
|
||||||
@@ -190,12 +195,23 @@ export class FileSystemTreeComponent {
|
|||||||
|
|
||||||
@Output() folderSelected = new EventEmitter<string>();
|
@Output() folderSelected = new EventEmitter<string>();
|
||||||
|
|
||||||
|
@Input() baseUrl: string = '';
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
this.treeControl = new FlatTreeControl<DynamicFlatNode>(this.getLevel, this.isExpandable);
|
this.treeControl = new FlatTreeControl<DynamicFlatNode>(this.getLevel, this.isExpandable);
|
||||||
this.dataSource = new DynamicDataSource(this.treeControl, this.database);
|
this.dataSource = new DynamicDataSource(this.treeControl, this.database);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
if(this.baseUrl.length>0){
|
||||||
|
this.database.setBaseUrl(this.baseUrl);
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize root data
|
// Initialize root data
|
||||||
this.refresh();
|
this.refresh();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export const ADMIN_ROUTES: Routes = [
|
|||||||
{
|
{
|
||||||
path: 'users',
|
path: 'users',
|
||||||
loadComponent: () => import('../admin-module/users.component/users.component').then((c) => c.UsersComponent),
|
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',
|
path: 'hard-drive-browser',
|
||||||
|
|||||||
+3
-1
@@ -1 +1,3 @@
|
|||||||
<app-file-browser-with-tree-component></app-file-browser-with-tree-component>
|
<app-file-browser-with-tree-component
|
||||||
|
[baseUrl]="baseUrl"
|
||||||
|
></app-file-browser-with-tree-component>
|
||||||
|
|||||||
+2
@@ -2,6 +2,7 @@ import { Component } from '@angular/core';
|
|||||||
import {
|
import {
|
||||||
FileBrowserWithTreeComponent
|
FileBrowserWithTreeComponent
|
||||||
} from '../../../components/file-browser-with-tree-component/file-browser-with-tree-component';
|
} from '../../../components/file-browser-with-tree-component/file-browser-with-tree-component';
|
||||||
|
import {GlobalConstants} from '../../../global-constants';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-hard-drive-browser.component',
|
selector: 'app-hard-drive-browser.component',
|
||||||
@@ -12,5 +13,6 @@ import {
|
|||||||
styleUrl: './hard-drive-browser.component.scss'
|
styleUrl: './hard-drive-browser.component.scss'
|
||||||
})
|
})
|
||||||
export class HardDriveBrowserComponent {
|
export class HardDriveBrowserComponent {
|
||||||
|
baseUrl = `${GlobalConstants.API_URL}/admin/file-browser-tree`;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
<app-file-browser-with-tree-component
|
||||||
|
[baseUrl]="baseUrl"
|
||||||
|
></app-file-browser-with-tree-component>
|
||||||
+23
@@ -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<FilesBrowserComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [FilesBrowserComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(FilesBrowserComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
+21
@@ -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`;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -31,6 +31,11 @@ export const USER_ROUTS: Routes = [
|
|||||||
loadComponent: () => import('../user-module/tutorial-edit.component/tutorial-edit.component').then((c) => c.TutorialEditComponent),
|
loadComponent: () => import('../user-module/tutorial-edit.component/tutorial-edit.component').then((c) => c.TutorialEditComponent),
|
||||||
data:{title: 'Edit Tutorial'}
|
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',
|
path: 'ai-models',
|
||||||
loadComponent: () => import('../user-module/ai-models.component/ai-models.component').then((c) => c.AiModelsComponent),
|
loadComponent: () => import('../user-module/ai-models.component/ai-models.component').then((c) => c.AiModelsComponent),
|
||||||
|
|||||||
@@ -16,23 +16,16 @@ export interface FileItem {
|
|||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class FileBrowserTreeService {
|
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) {}
|
constructor(private http: HttpClient) {}
|
||||||
|
|
||||||
getFiles(path: string): Observable<FileItem[]> {
|
getFiles(path: string): Observable<FileItem[]> {
|
||||||
const encodedPath = encodeURIComponent(path);
|
const encodedPath = encodeURIComponent(path);
|
||||||
return this.http.get<FileItem[]>(`${this.baseUrl}?path=${encodedPath}`);
|
return this.http.get<FileItem[]>(`${this.baseUrl}/files?path=${encodedPath}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// New method to get only folders for tree view
|
|
||||||
getFolders(path: string): Observable<FileItem[]> {
|
|
||||||
const encodedPath = encodeURIComponent(path);
|
|
||||||
return this.http.get<FileItem[]>(`${this.baseUrl}?path=${encodedPath}`)
|
|
||||||
.pipe(
|
|
||||||
map(files => files.filter(file => file.type === 'directory'))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Alternative: dedicated backend endpoint for folders only
|
// Alternative: dedicated backend endpoint for folders only
|
||||||
getFoldersOnly(path: string): Observable<FileItem[]> {
|
getFoldersOnly(path: string): Observable<FileItem[]> {
|
||||||
|
|||||||
+14
-1
@@ -1,9 +1,12 @@
|
|||||||
package com.jambotronGroup.jambotron.controllers;
|
package com.jambotronGroup.jambotron.controllers;
|
||||||
|
|
||||||
import com.jambotronGroup.jambotron.fileBrowserTree.CreateFolderRequest;
|
import com.jambotronGroup.jambotron.fileBrowserTree.CreateFolderRequest;
|
||||||
|
import com.jambotronGroup.jambotron.fileBrowserTree.FileBrowserTreeExtendedService;
|
||||||
import com.jambotronGroup.jambotron.fileBrowserTree.FileItemDto;
|
import com.jambotronGroup.jambotron.fileBrowserTree.FileItemDto;
|
||||||
import com.jambotronGroup.jambotron.fileBrowserTree.FileBrowserTreeService;
|
import com.jambotronGroup.jambotron.fileBrowserTree.FileBrowserTreeService;
|
||||||
import com.jambotronGroup.jambotron.fileUpload.ResponseMessage;
|
import com.jambotronGroup.jambotron.fileUpload.ResponseMessage;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
@@ -15,19 +18,24 @@ import org.springframework.web.multipart.MultipartFile;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/file-browser-tree/files")
|
@RequestMapping("/api/user/file-browser-tree")
|
||||||
public class FileBrowserTreeController {
|
public class FileBrowserTreeController {
|
||||||
|
|
||||||
|
private final Logger _logger = LoggerFactory.getLogger(FileBrowserTreeController.class);
|
||||||
@Autowired
|
@Autowired
|
||||||
private FileBrowserTreeService fileBrowserTreeService;
|
private FileBrowserTreeService fileBrowserTreeService;
|
||||||
|
|
||||||
|
|
||||||
@GetMapping
|
@GetMapping
|
||||||
|
@RequestMapping("/files")
|
||||||
public ResponseEntity<List<FileItemDto>> getFiles(@RequestParam String path) {
|
public ResponseEntity<List<FileItemDto>> getFiles(@RequestParam String path) {
|
||||||
try {
|
try {
|
||||||
List<FileItemDto> files = fileBrowserTreeService.listFiles(path);
|
List<FileItemDto> files = fileBrowserTreeService.listFiles(path);
|
||||||
return ResponseEntity.ok(files);
|
return ResponseEntity.ok(files);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
_logger.error("Error retrieving files from path: {}", path, e.getMessage());
|
||||||
return ResponseEntity.badRequest().build();
|
return ResponseEntity.badRequest().build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -39,10 +47,12 @@ public class FileBrowserTreeController {
|
|||||||
List<FileItemDto> folders = fileBrowserTreeService.listFolders(path);
|
List<FileItemDto> folders = fileBrowserTreeService.listFolders(path);
|
||||||
return ResponseEntity.ok(folders);
|
return ResponseEntity.ok(folders);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
_logger.error("Error retrieving folders from path: {}", path, e.getMessage());
|
||||||
return ResponseEntity.badRequest().build();
|
return ResponseEntity.badRequest().build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Search endpoint
|
// Search endpoint
|
||||||
@GetMapping("/search")
|
@GetMapping("/search")
|
||||||
public ResponseEntity<List<FileItemDto>> searchFiles(
|
public ResponseEntity<List<FileItemDto>> searchFiles(
|
||||||
@@ -52,6 +62,7 @@ public class FileBrowserTreeController {
|
|||||||
List<FileItemDto> files = fileBrowserTreeService.searchFiles(path, query);
|
List<FileItemDto> files = fileBrowserTreeService.searchFiles(path, query);
|
||||||
return ResponseEntity.ok(files);
|
return ResponseEntity.ok(files);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
_logger.error("Error searching files in path: {} with query: {}", path, query, e.getMessage());
|
||||||
return ResponseEntity.badRequest().build();
|
return ResponseEntity.badRequest().build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -68,6 +79,7 @@ public class FileBrowserTreeController {
|
|||||||
"attachment; filename=\"" + filename + "\"")
|
"attachment; filename=\"" + filename + "\"")
|
||||||
.body(resource);
|
.body(resource);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
_logger.error("Error downloading file from path: {}", path, e.getMessage());
|
||||||
return ResponseEntity.notFound().build();
|
return ResponseEntity.notFound().build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -80,6 +92,7 @@ public class FileBrowserTreeController {
|
|||||||
fileBrowserTreeService.storeFile(file, path);
|
fileBrowserTreeService.storeFile(file, path);
|
||||||
return ResponseEntity.ok(new ResponseMessage("File uploaded successfully: " + file.getOriginalFilename()));
|
return ResponseEntity.ok(new ResponseMessage("File uploaded successfully: " + file.getOriginalFilename()));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
_logger.error("Error uploading file: {}", file.getOriginalFilename(), e.getMessage());
|
||||||
return ResponseEntity.badRequest()
|
return ResponseEntity.badRequest()
|
||||||
.body(new ResponseMessage("Failed to upload file: " + e.getMessage()));
|
.body(new ResponseMessage("Failed to upload file: " + e.getMessage()));
|
||||||
}
|
}
|
||||||
|
|||||||
+146
@@ -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<List<FileItemDto>> getFiles(@RequestParam String path) {
|
||||||
|
try {
|
||||||
|
List<FileItemDto> 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<List<FileItemDto>> getFolders(@RequestParam String path) {
|
||||||
|
try {
|
||||||
|
List<FileItemDto> 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<List<FileItemDto>> searchFiles(
|
||||||
|
@RequestParam String path,
|
||||||
|
@RequestParam String query) {
|
||||||
|
try {
|
||||||
|
List<FileItemDto> 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<Resource> 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<ResponseMessage> 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<ResponseMessage> 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<ResponseMessage> 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<ResponseMessage> 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<ResponseMessage> 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()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -78,9 +78,9 @@ public class FilesController {
|
|||||||
response.getBody() // File content
|
response.getBody() // File content
|
||||||
);
|
);
|
||||||
|
|
||||||
User user = authenticationFacade.getUser();
|
|
||||||
|
|
||||||
storageService.save(user.getId().toString(), multipartFile);
|
|
||||||
|
storageService.save(multipartFile);
|
||||||
|
|
||||||
message = "Uploaded the file successfully: " + fileName;
|
message = "Uploaded the file successfully: " + fileName;
|
||||||
|
|
||||||
@@ -104,7 +104,7 @@ public class FilesController {
|
|||||||
try {
|
try {
|
||||||
User user = authenticationFacade.getUser();
|
User user = authenticationFacade.getUser();
|
||||||
|
|
||||||
String localFullFileName = storageService.save(user.getId().toString(), file);
|
String localFullFileName = storageService.save(file);
|
||||||
|
|
||||||
FileInfo fileInfo = new FileInfo(
|
FileInfo fileInfo = new FileInfo(
|
||||||
file.getOriginalFilename(),
|
file.getOriginalFilename(),
|
||||||
@@ -122,9 +122,8 @@ public class FilesController {
|
|||||||
@GetMapping("/api/user/getImages")
|
@GetMapping("/api/user/getImages")
|
||||||
public ResponseEntity<List<FileInfo>> getImages() {
|
public ResponseEntity<List<FileInfo>> getImages() {
|
||||||
|
|
||||||
User user = authenticationFacade.getUser();
|
|
||||||
|
|
||||||
List<FileInfo> fileInfos = storageService.loadUserImages(user.getId().toString()).map(path -> {
|
List<FileInfo> fileInfos = storageService.loadUserImages().map(path -> {
|
||||||
String filename = path.getFileName().toString();
|
String filename = path.getFileName().toString();
|
||||||
|
|
||||||
String url = FilesRoutingHelper.getUserImageUrl(filename);
|
String url = FilesRoutingHelper.getUserImageUrl(filename);
|
||||||
@@ -158,7 +157,7 @@ public class FilesController {
|
|||||||
@ResponseBody
|
@ResponseBody
|
||||||
public ResponseEntity<Resource> getUserImage(@PathVariable String filename) {
|
public ResponseEntity<Resource> getUserImage(@PathVariable String filename) {
|
||||||
User user = authenticationFacade.getUser();
|
User user = authenticationFacade.getUser();
|
||||||
Resource file = storageService.loadUserImage(user.getId().toString(),filename);
|
Resource file = storageService.loadUserImage(filename);
|
||||||
return ResponseEntity.ok()
|
return ResponseEntity.ok()
|
||||||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getFilename() + "\"").body(file);
|
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getFilename() + "\"").body(file);
|
||||||
}
|
}
|
||||||
@@ -169,7 +168,7 @@ public class FilesController {
|
|||||||
String message = "";
|
String message = "";
|
||||||
try {
|
try {
|
||||||
String filename = storageService.getFileNameFromUrl(imageUrl);
|
String filename = storageService.getFileNameFromUrl(imageUrl);
|
||||||
Base64ImageResponse base64Image = storageService.getUserImageAsBase64(user.getId().toString(),filename);
|
Base64ImageResponse base64Image = storageService.getUserImageAsBase64(filename);
|
||||||
|
|
||||||
return ResponseEntity.ok(base64Image);
|
return ResponseEntity.ok(base64Image);
|
||||||
|
|
||||||
@@ -177,6 +176,10 @@ public class FilesController {
|
|||||||
logger.error("Error retrieving base64 image for user {}: {}", user.getId(), e.getMessage());
|
logger.error("Error retrieving base64 image for user {}: {}", user.getId(), e.getMessage());
|
||||||
message = "Error retrieving base64 image for fileUrl" + imageUrl + ". \tError: " + e.getMessage();
|
message = "Error retrieving base64 image for fileUrl" + imageUrl + ". \tError: " + e.getMessage();
|
||||||
return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body(new Base64ImageResponse(message));
|
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 {
|
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);
|
String url = FilesRoutingHelper.getUserImageUrl(fullFileName);
|
||||||
|
|
||||||
|
|||||||
@@ -118,7 +118,6 @@ public class TutorialController {
|
|||||||
|
|
||||||
String newFilename = filesStorageService.getFileNameFromUrl(tutorial.getTitleimage());
|
String newFilename = filesStorageService.getFileNameFromUrl(tutorial.getTitleimage());
|
||||||
Path path= filesStorageService.moveFile(
|
Path path= filesStorageService.moveFile(
|
||||||
user.getId().toString(),
|
|
||||||
tutorial.getTitleimage(),
|
tutorial.getTitleimage(),
|
||||||
String.format("Tutorial_%s",newFilename )
|
String.format("Tutorial_%s",newFilename )
|
||||||
);
|
);
|
||||||
@@ -188,7 +187,6 @@ public class TutorialController {
|
|||||||
filesStorageService.deletePublicFile(servImageFileName);
|
filesStorageService.deletePublicFile(servImageFileName);
|
||||||
|
|
||||||
Path path= filesStorageService.moveFile(
|
Path path= filesStorageService.moveFile(
|
||||||
user.getId().toString(),
|
|
||||||
tutorial.getTitleimage(),
|
tutorial.getTitleimage(),
|
||||||
String.format("Tutorial_%s",imageFileName )
|
String.format("Tutorial_%s",imageFileName )
|
||||||
);
|
);
|
||||||
|
|||||||
+29
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+11
-13
@@ -1,5 +1,6 @@
|
|||||||
package com.jambotronGroup.jambotron.fileBrowserTree;
|
package com.jambotronGroup.jambotron.fileBrowserTree;
|
||||||
|
|
||||||
|
import com.jambotronGroup.jambotron.globalConstants.GlobalConstants;
|
||||||
import com.jambotronGroup.jambotron.model.ERole;
|
import com.jambotronGroup.jambotron.model.ERole;
|
||||||
import com.jambotronGroup.jambotron.security.AuthenticationFacade;
|
import com.jambotronGroup.jambotron.security.AuthenticationFacade;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -20,24 +21,20 @@ import java.util.stream.Stream;
|
|||||||
public class FileBrowserTreeService {
|
public class FileBrowserTreeService {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private AuthenticationFacade authenticationFacade;
|
protected AuthenticationFacade authenticationFacade;
|
||||||
|
|
||||||
private final Path root = Paths.get("/jambotron_data");
|
//private final Path root = Paths.get("/jambotron_data");
|
||||||
private Path getRootPath() {
|
//private final Path rootUsers = root.resolve("users");
|
||||||
boolean isAdmin = authenticationFacade.getUser()
|
protected Path getRootPath() {
|
||||||
.getRoles().stream()
|
GlobalConstants.PATH_USERS.toFile().mkdir();
|
||||||
.anyMatch(role -> role.getName().equals(ERole.ROLE_ADMIN));
|
Path userFolder = GlobalConstants.PATH_USERS.resolve(authenticationFacade.getUser().getUsername()).toAbsolutePath();
|
||||||
|
userFolder.toFile().mkdir();
|
||||||
if(isAdmin){
|
return userFolder;
|
||||||
// Admins can access the root directory
|
|
||||||
return root.normalize().toAbsolutePath();
|
|
||||||
}
|
|
||||||
return root.resolve(authenticationFacade.getUser().getUsername()).normalize().toAbsolutePath();
|
|
||||||
}
|
}
|
||||||
private Path resolvePath(String path) throws IOException {
|
private Path resolvePath(String path) throws IOException {
|
||||||
Path root = getRootPath();
|
Path root = getRootPath();
|
||||||
Path resolvedPath = root.resolve(path.startsWith("/") ? path.substring(1) : path)
|
Path resolvedPath = root.resolve(path.startsWith("/") ? path.substring(1) : path)
|
||||||
.normalize().toAbsolutePath();
|
.normalize();
|
||||||
|
|
||||||
// Security check: ensure the resolved path is within the root directory
|
// Security check: ensure the resolved path is within the root directory
|
||||||
if (!resolvedPath.startsWith(root)) {
|
if (!resolvedPath.startsWith(root)) {
|
||||||
@@ -47,6 +44,7 @@ public class FileBrowserTreeService {
|
|||||||
return resolvedPath;
|
return resolvedPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public List<FileItemDto> listFiles(String path) throws IOException {
|
public List<FileItemDto> listFiles(String path) throws IOException {
|
||||||
Path targetPath = resolvePath(path);
|
Path targetPath = resolvePath(path);
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import org.springframework.core.io.Resource;
|
|||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@@ -13,25 +14,24 @@ public interface FilesStorageService {
|
|||||||
|
|
||||||
public String getFileNameFromUrl(String urlString);
|
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 String saveUserBase64Image(String base64Image, String mimeType);
|
||||||
|
|
||||||
public void save(MultipartFile file);
|
|
||||||
|
|
||||||
public Resource load(String filename);
|
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<Path> loadAll();
|
public Stream<Path> loadAll();
|
||||||
|
|
||||||
public Stream<Path> loadUserImages(String userID);
|
public Stream<Path> 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);
|
public void deletePublicFile(String filename);
|
||||||
}
|
}
|
||||||
+85
-56
@@ -2,9 +2,12 @@ package com.jambotronGroup.jambotron.fileUpload;
|
|||||||
|
|
||||||
|
|
||||||
import com.jambotronGroup.jambotron.controllers.AuthController;
|
import com.jambotronGroup.jambotron.controllers.AuthController;
|
||||||
|
import com.jambotronGroup.jambotron.globalConstants.GlobalConstants;
|
||||||
import com.jambotronGroup.jambotron.payload.request.UploadImageResponse;
|
import com.jambotronGroup.jambotron.payload.request.UploadImageResponse;
|
||||||
|
import com.jambotronGroup.jambotron.security.AuthenticationFacade;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.core.io.UrlResource;
|
import org.springframework.core.io.UrlResource;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@@ -26,6 +29,9 @@ public class FilesStorageServiceImpl implements FilesStorageService {
|
|||||||
|
|
||||||
private static final Logger _logger = LoggerFactory.getLogger(AuthController.class);
|
private static final Logger _logger = LoggerFactory.getLogger(AuthController.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AuthenticationFacade _authenticationFacade;
|
||||||
|
|
||||||
private static final Set<String> ALLOWED_MIME = Set.of(
|
private static final Set<String> ALLOWED_MIME = Set.of(
|
||||||
"image/png", "image/jpeg", "image/webp", "image/gif"
|
"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
|
@Override
|
||||||
public void init() {
|
public void init() {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Files.createDirectories(root);
|
Files.createDirectories(GlobalConstants.PATH_USERS);
|
||||||
Files.createDirectories(rootPublic);
|
Files.createDirectories(_rootPublic);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException("Could not initialize folder for upload!");
|
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
|
@Override
|
||||||
public String getFileNameFromUrl(String urlString){
|
public String getFileNameFromUrl(String urlString){
|
||||||
try {
|
try {
|
||||||
@@ -69,10 +85,10 @@ public class FilesStorageServiceImpl implements FilesStorageService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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 {
|
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.
|
* Moves a file from a user's directory to the public directory with a new name.
|
||||||
* StandardCopyOption.REPLACE_EXISTING
|
* StandardCopyOption.REPLACE_EXISTING
|
||||||
*
|
*
|
||||||
* @param userID The ID of the user owning the file.
|
|
||||||
* @param url The URL of the file to move.
|
* @param url The URL of the file to move.
|
||||||
* @param newFilename The new name for the file in the public directory.
|
* @param newFilename The new name for the file in the public directory.
|
||||||
* @return The path to the moved file in the public directory.
|
* @return The path to the moved file in the public directory.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Path moveFile(String userID, String url, String newFilename) {
|
public Path moveFile(String url, String newFilename) {
|
||||||
|
|
||||||
String filename = this.getFileNameFromUrl(url);
|
String filename = this.getFileNameFromUrl(url);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Path sourcePath = this.root.resolve(userID).resolve(filename);
|
Path sourcePath = getUserUploadsImagesPath().resolve(filename);
|
||||||
Path targetPath = this.rootPublic.resolve(newFilename);
|
Path targetPath = _rootPublic.resolve(newFilename);
|
||||||
Files.copy(sourcePath, targetPath, java.nio.file.StandardCopyOption.REPLACE_EXISTING);
|
Files.copy(sourcePath, targetPath, java.nio.file.StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException("Could not move the file: " + e.getMessage());
|
throw new RuntimeException("Could not move the file: " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.rootPublic.resolve(newFilename);
|
return _rootPublic.resolve(newFilename);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deletePublicFile(String filename) {
|
public void deletePublicFile(String filename) {
|
||||||
try {
|
try {
|
||||||
Path filePath = this.rootPublic.resolve(filename);
|
Path filePath = _rootPublic.resolve(filename);
|
||||||
Files.deleteIfExists(filePath);
|
Files.deleteIfExists(filePath);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException("Could not delete the file: " + e.getMessage());
|
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.
|
* Saves a file to a user's directory.
|
||||||
* uploads/user-images/{userID}/{filename}
|
* uploads/user-images/{userID}/{filename}
|
||||||
*
|
*
|
||||||
* @param userID The ID of the user.
|
|
||||||
* @param file The file to save.
|
* @param file The file to save.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String save(String userID,MultipartFile file) {
|
public String save(MultipartFile file) {
|
||||||
Path targetPath = null;
|
Path targetPath = null;
|
||||||
try {
|
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,
|
Files.copy(file.getInputStream(), targetPath,
|
||||||
java.nio.file.StandardCopyOption.REPLACE_EXISTING);
|
java.nio.file.StandardCopyOption.REPLACE_EXISTING);
|
||||||
@@ -157,24 +172,29 @@ public class FilesStorageServiceImpl implements FilesStorageService {
|
|||||||
return targetPath.getFileName().toString();
|
return targetPath.getFileName().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private String getFixedFileName(String filename) {
|
||||||
public void save(MultipartFile file) {
|
|
||||||
try {
|
return filename.indexOf('?') != -1 ? filename.substring(0, filename.indexOf('?')) : filename;
|
||||||
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.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new RuntimeException(e.getMessage());
|
// @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
|
@Override
|
||||||
public Resource load(String filename) {
|
public Resource load(String filename) {
|
||||||
try {
|
try {
|
||||||
Path file = rootPublic.resolve(filename);
|
Path file = _rootPublic.resolve(filename);
|
||||||
Resource resource = new UrlResource(file.toUri());
|
Resource resource = new UrlResource(file.toUri());
|
||||||
|
|
||||||
if (resource.exists() || resource.isReadable()) {
|
if (resource.exists() || resource.isReadable()) {
|
||||||
@@ -188,11 +208,10 @@ public class FilesStorageServiceImpl implements FilesStorageService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Resource loadUserImage(String userID,String filename) {
|
public Resource loadUserImage(String filename) {
|
||||||
try {
|
try {
|
||||||
Path file = root.resolve(filename);
|
Path file = getUserUploadsImagesPath().resolve(filename);
|
||||||
Path userPath = this.root.resolve(userID);
|
|
||||||
file = userPath.resolve(filename);
|
|
||||||
Resource resource = new UrlResource(file.toUri());
|
Resource resource = new UrlResource(file.toUri());
|
||||||
|
|
||||||
if (resource.exists() || resource.isReadable()) {
|
if (resource.exists() || resource.isReadable()) {
|
||||||
@@ -202,36 +221,49 @@ public class FilesStorageServiceImpl implements FilesStorageService {
|
|||||||
}
|
}
|
||||||
} catch (MalformedURLException e) {
|
} catch (MalformedURLException e) {
|
||||||
throw new RuntimeException("Error: " + e.getMessage());
|
throw new RuntimeException("Error: " + e.getMessage());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deleteAll() {
|
public void deleteAll() throws IOException {
|
||||||
FileSystemUtils.deleteRecursively(root.toFile());
|
FileSystemUtils.deleteRecursively(getUserUploadsImagesPath().toFile());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<Path> loadAll() {
|
public Stream<Path> loadAll() {
|
||||||
try {
|
try {
|
||||||
return Files.walk(this.root, 1).filter(path -> !path.equals(this.root)).map(this.root::relativize);
|
return Files.walk(getUserUploadsImagesPath(), 1).filter(path -> {
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException("Could not load the files!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Stream<Path> loadUserImages(String userID) {
|
|
||||||
Path userPath = this.root.resolve(userID);
|
|
||||||
userPath.toFile().mkdirs();
|
|
||||||
try {
|
try {
|
||||||
return Files.walk(userPath, 1).filter(path -> !path.equals(userPath)).map(userPath::relativize);
|
return !path.equals(getUserUploadsImagesPath());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}).map(getUserUploadsImagesPath()::relativize);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException("Could not load the files!");
|
throw new RuntimeException("Could not load the files!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String saveUserBase64Image(String userID, String base64Image, String mimeType) {
|
public Stream<Path> loadUserImages() {
|
||||||
|
|
||||||
|
try {
|
||||||
|
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 base64Image, String mimeType) {
|
||||||
|
|
||||||
if (!ALLOWED_MIME.contains(mimeType)) {
|
if (!ALLOWED_MIME.contains(mimeType)) {
|
||||||
_logger.error("Unsupported MIME type: " + mimeType);
|
_logger.error("Unsupported MIME type: " + mimeType);
|
||||||
@@ -256,15 +288,12 @@ public class FilesStorageServiceImpl implements FilesStorageService {
|
|||||||
|
|
||||||
String id = UUID.randomUUID().toString().replace("-", "");
|
String id = UUID.randomUUID().toString().replace("-", "");
|
||||||
|
|
||||||
String safeBaseName = "user-image-" + userID;
|
String safeBaseName = "user-image-";
|
||||||
String storedName = safeBaseName + "-" + id + "." + ext;
|
String storedName = safeBaseName + id + "." + ext;
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Path userPath = this.root.resolve(userID);
|
Path targetPath = getUserUploadsImagesPath().resolve(storedName);
|
||||||
userPath.toFile().mkdirs(); // Ensure user directory exists
|
|
||||||
|
|
||||||
Path targetPath = userPath.resolve(storedName);
|
|
||||||
|
|
||||||
Files.write(targetPath, bytes);
|
Files.write(targetPath, bytes);
|
||||||
|
|
||||||
|
|||||||
@@ -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");
|
||||||
|
}
|
||||||
@@ -119,15 +119,17 @@ public class WebSecurityConfig implements WebMvcConfigurer {// extends WebSecuri
|
|||||||
|
|
||||||
// Access permitted for specific roles
|
// Access permitted for specific roles
|
||||||
.requestMatchers("/api/user/**").hasRole("USER")
|
.requestMatchers("/api/user/**").hasRole("USER")
|
||||||
|
.requestMatchers("/api/user/file-browser-tree/**").hasRole("USER")
|
||||||
|
|
||||||
.requestMatchers("/api/moderator/**").hasRole("MODERATOR")
|
.requestMatchers("/api/moderator/**").hasRole("MODERATOR")
|
||||||
|
|
||||||
//.requestMatchers("/api/admin/**").hasRole("ADMIN")
|
|
||||||
.requestMatchers("/api/admin/**").hasRole("ADMIN")
|
.requestMatchers("/api/admin/**").hasRole("ADMIN")
|
||||||
.requestMatchers("/api/admin/json-dump/**").hasRole("ADMIN")
|
.requestMatchers("/api/admin/json-dump/**").hasRole("ADMIN")
|
||||||
.requestMatchers("/api/admin/json-dump/import/**").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()
|
.anyRequest().authenticated()
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user