Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

External tools #11

Open
wants to merge 30 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
5b3f9d5
Add ExternalTool, MarketplaceItem, and MarketplaceItemImage models wi…
jp-tosca Feb 7, 2025
957f7ae
Add @Lob annotation to image field in MarketplaceItemImage model
jp-tosca Feb 8, 2025
4197258
Add repository and service classes for ExternalTool and MarketplaceIt…
jp-tosca Feb 11, 2025
7e5108f
Add ExternalToolManifest repository and update ExternalTool service f…
jp-tosca Feb 11, 2025
2ea83a9
Update ExternalToolService to extract content type from JSON manifest
jp-tosca Feb 12, 2025
0d56e1e
Add repository and service classes for resource storage, including da…
jp-tosca Feb 13, 2025
555a30d
Refactor ExternalToolService and ResourceStorageService to integrate …
jp-tosca Feb 13, 2025
7ab76ff
Refactor resource storage handling to support MultipartFile and updat…
jp-tosca Feb 13, 2025
a8d37a7
Implement StoredResourceController and enhance ResourceStorageService…
jp-tosca Feb 13, 2025
7ac4db9
Add support for uploading item images in AddToolRequest and update Ex…
jp-tosca Feb 13, 2025
c8fc697
Add MarketplaceItemImage repository and update ExternalToolService to…
jp-tosca Feb 14, 2025
fa95d8b
Refactor ExternalToolController and OpenAPI annotations to enhance ad…
jp-tosca Feb 14, 2025
436e36e
Update ExternalToolSamples to refine sample data and enhance clarity …
jp-tosca Feb 14, 2025
0a64824
Refactor AuthAPIDocs to simplify schema references for SignupRequest …
jp-tosca Feb 14, 2025
5359cc3
Add retrieval functionality for external tools and enhance API docume…
jp-tosca Feb 14, 2025
aa6efe2
Add functionality to manage external tool versions and update API doc…
jp-tosca Feb 15, 2025
0fd36f2
Add functionality to manage external tool versions, including new req…
jp-tosca Feb 18, 2025
3e03936
Add image management functionality for external tools, including uplo…
jp-tosca Feb 18, 2025
a1437b7
Fix null return in ExternalToolController to ensure proper response h…
jp-tosca Feb 18, 2025
f44775c
Refactor external tool models and services to enhance image managemen…
jp-tosca Feb 18, 2025
c8f1b1a
Refactor ExternalToolDTO and ExternalToolController for improved imag…
jp-tosca Feb 18, 2025
5d25e7d
Add caching support with Ehcache configuration and enhance external t…
jp-tosca Feb 19, 2025
7c9879d
Enhance ExternalToolController and payload classes for improved tool …
jp-tosca Feb 19, 2025
3e74a8e
Add image handling support and refactor models for serialization in e…
jp-tosca Feb 20, 2025
1ac43fc
Add toString methods for ExternalToolManifestDTO and ExternalToolVers…
jp-tosca Feb 20, 2025
370d9ad
Remove altText field from MarketplaceItemImage and update correspondi…
jp-tosca Feb 20, 2025
812fa92
Remove altText assignment from newImage in ExternalToolService
jp-tosca Feb 20, 2025
e354820
Rename resourceId to storedResourceId in StoredResourceController and…
jp-tosca Feb 26, 2025
765550e
Update password size validation and enhance external tool update func…
jp-tosca Feb 26, 2025
c71cd2c
Refactor AddToolRequest to remove commented-out ArraySchema for image…
jp-tosca Feb 26, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,6 @@ build/
### VS Code ###
.vscode/


/storage/*
docker-dev-volumes
18 changes: 18 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,24 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Spring Cache -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!-- ehcache -->
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<classifier>jakarta</classifier>
<exclusions>
<exclusion>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
</exclusion>
</exclusions>
</dependency>



<!-- Spring OPenAPI-->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.dataverse.marketplace.config.cache;

import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableCaching
public class CacheConfig {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.dataverse.marketplace.config.cache;

import org.ehcache.event.CacheEvent;
import org.ehcache.event.CacheEventListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CacheEventLogger implements CacheEventListener<Object, Object> {

Logger logger = LoggerFactory.getLogger(CacheEventLogger.class);

@Override
public void onEvent(
CacheEvent<? extends Object, ? extends Object> cacheEvent) {
logger.info(cacheEvent.getType().toString(),
cacheEvent.getKey(), cacheEvent.getOldValue(), cacheEvent.getNewValue());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,16 @@ public ResponseEntity<?> authenticateUser(@Valid @RequestBody LoginRequest login
loginRequest.getPassword()));

SecurityContextHolder.getContext().setAuthentication(authentication);

String jwt = jwtUtils.generateJwtToken(authentication);

UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
List<String> roles = userDetails.getAuthorities().stream().map(item -> item.getAuthority())
.collect(Collectors.toList());

List<String> roles = userDetails
.getAuthorities()
.stream()
.map(item -> item.getAuthority())
.collect(Collectors.toList());

return ResponseEntity
.ok(new JwtResponse(jwt,
return ResponseEntity.ok(new JwtResponse(jwt,
userDetails.getId(),
userDetails.getUsername(),
userDetails.getEmail(),
Expand Down Expand Up @@ -108,7 +109,7 @@ public ResponseEntity<?> registerUser(@Valid @RequestBody SignupRequest signUpRe

@PreAuthorize(ApplicationRoles.ADMIN_ROLE)
@PostMapping("/roles")
@AuthAPIDocs.RoleCreationRequest
@AuthAPIDocs.RoleCreationRequestDoc
public ResponseEntity<?> createRole(@Valid @RequestBody RoleCreationRequest roleCreationRequest) {

if(roleRepository.existsByName(roleCreationRequest.getRoleName().toUpperCase())) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
package org.dataverse.marketplace.controller.api;

import jakarta.validation.Valid;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.dataverse.marketplace.model.*;
import org.dataverse.marketplace.openapi.annotations.ExternalToolsAPIDocs;
import org.dataverse.marketplace.payload.*;
import org.dataverse.marketplace.security.ApplicationRoles;
import org.dataverse.marketplace.service.ExternalToolService;
import org.dataverse.marketplace.service.ResourceStorageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;


@RestController
@RequestMapping("/api/tools")
public class ExternalToolController {

@Autowired
private ExternalToolService externalToolService;

@Autowired
private ResourceStorageService resourceStorageService;

/**
* Method to retrieve all external tools
*/
@GetMapping()
@ExternalToolsAPIDocs.ExternalToolsListDoc
public ResponseEntity<?> getAllTools() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This API endpoint doesn't seem to work for me. Getting just one tool works, but not all. I just get an empty array.

pdurbin@beamish dataverse-marketplace % curl -s http://localhost:8080/api/tools/1 | jq .
{
  "id": 1,
  "name": "AskTheData",
  "description": "Ask the Data is an ...",
  "versions": [
    {
      "id": 1,
      "version": "1.0",
      "releaseNote": "This release includes a new feature ...",
      "dataverseMinVersion": "6.0",
      "manifests": [
        {
          "manifestId": 2,
          "storedResourceId": 5
        }
      ]
    }
  ],
  "imagesResourceId": [
    3
  ]
}
pdurbin@beamish dataverse-marketplace % curl -s http://localhost:8080/api/tools | jq .  
[]
pdurbin@beamish dataverse-marketplace % 

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is weird, I been using that endpoint for the main page and it works fine, I will do a fresh test soon and post back.


return ResponseEntity.ok(externalToolService.getAllTools());
}

/**
* Method to add a new external tool
*/
@PreAuthorize(ApplicationRoles.ADMIN_ROLE)
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@ExternalToolsAPIDocs.AddExternalToolsRequestDoc
public ResponseEntity<?> addNewTool(@Valid AddToolRequest addToolRequest) {

try {
return ResponseEntity.ok(externalToolService.addTool(addToolRequest));
} catch (IOException e) {
ServerMessageResponse messageResponse
= new ServerMessageResponse(HttpStatus.INTERNAL_SERVER_ERROR,
"Error adding tool",
e.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(messageResponse);
}
}

/**
* Method to retrieve all external tools
*/
@GetMapping("/{toolId}")
@ExternalToolsAPIDocs.GetExternalToolByIdDoc
public ResponseEntity<?> getToolById(@PathVariable("toolId") Integer toolId) {

ExternalTool tool = externalToolService.getToolById(toolId);
return ResponseEntity.ok(new ExternalToolDTO(tool));
}

@PreAuthorize(ApplicationRoles.ADMIN_ROLE)
@PutMapping("/{toolId}")
@ExternalToolsAPIDocs.UpdateExternalToolDoc
public ResponseEntity<?> updateTool(@PathVariable("toolId") Integer toolId, @Valid UpdateToolRequest updateToolRequest) {

ExternalTool tool = externalToolService.getToolById(toolId);

if(tool == null){
ServerMessageResponse messageResponse = new ServerMessageResponse(HttpStatus.NOT_FOUND,
"Resource not found",
String.format("The requested external tool with ID %d was not found.", toolId));
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(messageResponse);
}

try {
ServerMessageResponse messageResponse = new ServerMessageResponse(HttpStatus.OK,
"Tool updated",
String.format("The tool with ID %d was updated.", toolId));
externalToolService.updateTool(tool, updateToolRequest);
return ResponseEntity.ok(messageResponse);
} catch (Exception e) {
ServerMessageResponse messageResponse
= new ServerMessageResponse(HttpStatus.INTERNAL_SERVER_ERROR,
"Error updating tool",
e.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(messageResponse);
}
}


/**
* Method to retrieve the images of an external tool.
*/
@GetMapping("/{toolId}/images")
@ExternalToolsAPIDocs.GetToolImagesDoc
public ResponseEntity<?> getToolImages(@PathVariable("toolId") Integer toolId) {

ExternalTool tool = externalToolService.getToolById(toolId);

if(tool == null){
ServerMessageResponse messageResponse = new ServerMessageResponse(HttpStatus.NOT_FOUND,
"Resource not found",
String.format("The requested external tool with ID %d was not found.", toolId));
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(messageResponse);
}

List<MarketplaceItemImageDTO> imagesResourceId = new ArrayList<>();
for (MarketplaceItemImage image : tool.getImages()) {
imagesResourceId.add(new MarketplaceItemImageDTO(image));
}

return ResponseEntity.ok(imagesResourceId);
}

/**
* Method to add images to an external tool.
*/
@PreAuthorize(ApplicationRoles.ADMIN_ROLE)
@PostMapping(path = "/{toolId}/images", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@ExternalToolsAPIDocs.AddToolImagesDoc
public ResponseEntity<?> addToolImages(
@PathVariable("toolId") Integer toolId,
@RequestBody List<MultipartFile> images) throws IOException {

ExternalTool tool = externalToolService.getToolById(toolId);

if(tool == null){
ServerMessageResponse messageResponse = new ServerMessageResponse(HttpStatus.NOT_FOUND,
"Resource not found",
String.format("The requested external tool with ID %d was not found.", toolId));
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(messageResponse);
}

externalToolService.addItemImages(tool, images);

ServerMessageResponse messageResponse = new ServerMessageResponse(HttpStatus.OK,
"Images added",
String.format("The images were added to the tool with ID %d.", toolId));

return ResponseEntity.ok(messageResponse);
}

/**
* Method to delete an image from an external tool.
*/
@PreAuthorize(ApplicationRoles.ADMIN_ROLE)
@DeleteMapping("/{toolId}/images/{imageId}")
@ExternalToolsAPIDocs.DeleteToolImageDoc
public ResponseEntity<?> deleteToolImage(
@PathVariable("toolId") Integer toolId,
@PathVariable("imageId") Integer imageId) {

MarketplaceItemImage image = externalToolService.getItemImage(imageId, toolId);

if(image == null){
ServerMessageResponse messageResponse = new ServerMessageResponse(HttpStatus.NOT_FOUND,
"Resource not found",
String.format("The requested image with ID %d was not found.", imageId));
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(messageResponse);
}

try {

resourceStorageService.deleteResourceContent(image.getImageStoredResourceId());
externalToolService.deleteToolImage(image);
return ResponseEntity.ok(new ServerMessageResponse(HttpStatus.OK,
"Image deleted",
String.format("The image with ID %d was deleted.", imageId)));

} catch (IOException e) {

ServerMessageResponse messageResponse = new ServerMessageResponse(HttpStatus.INTERNAL_SERVER_ERROR,
"Error deleting image",
e.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(messageResponse);
}
}






}
Loading
Loading