Does springfox-swagger2 UI support choosing multiple files at once? - file-upload

I use Spring Boot and integrated swagger-ui (springfox-swagger2) and I want to be able to choose to upload multiple files at once. Unfortunately the Swagger UI doesn't appear to allow this, at least not give my controller method.
My controller method signature:
#ApiOperation(
value = "batch upload goods cover image",
notes = "batch upload goods cover image",
response = UploadCoverResultDTO.class,
responseContainer = "List"
)
public Result<?> uploadGoodsCover(#ApiParam(value = "Image array", allowMultiple = true,
required = true) #RequestPart("image") MultipartFile[] files) throws IOException {
Swagger UI generated:
But I was expecting a UI similar to this:
It's more convenient to choose all pictures in a folder in one go rather than choose one at a time e.g.:
<input type="file" name="img" multiple="multiple"/>
Does springfox-swagger2 support this? If so, what changes do I need to make?

Update: as pointed out by #Helen, this is now supported in Swagger 3.26.0 with OpenAPI 3 and should be in the next release of Springfox 3
Springfox 2: unfortunately the answer is no.
Springfox Swagger2 does not support this because it's not yet supported by Swagger: https://github.com/springfox/springfox/issues/1072
Relevant Swagger issues:
https://github.com/swagger-api/swagger-ui/issues/4600 (fixed in 3.26.0)
https://github.com/OAI/OpenAPI-Specification/issues/254

Related

Polarion API: How to update multiple work items in the same action

I created a script which updates work items in a polarion document. However, right now each workitem update is a single save. But my script updates all work items in the document, which results in a large number of save actions in the api and thus a large set of clutter in the history.
If you edit a polarion document yourself, it will update all workitems.
Is it possible to do this same thing with the polarion API?
I tried
Using the tracker service to update work items. This only allows a single work item to be updated.
Using the web development tools to try and get information from the API. This seems to use a UniversalService for which no documentation is available at the API site https://almdemo.polarion.com/polarion/sdk/index.html
Update 1:
I am using the python polarion package to update the workitems.Python polarion Based on the answer by #boaz I tried the following code:
project = client.getProject(project_name)
doc = project.getDocument(document_location)
workitems = doc.getWorkitems()
session_service = client.getService("Session")
tracker_service = client.getService("Tracker")
session_service.beginTransaction()
for workitem in workitems:
workitem.description = workitem._polarion.TextType(
content=str(datetime.datetime.now()), type='text/html', contentLossy=False)
update_list = {
"uri": workitem.uri,
"description": workitem.description
}
tracker_service.updateWorkItem(update_list)
session_service.endTransaction(False)
The login step that #boaz indicated is done in the backend (See: https://github.com/jesper-raemaekers/python-polarion/blob/3e61527cf0f1f3c8614a30289a0a3409d2d8712d/polarion/polarion.py#L103)
However, this gives the following Java exception:
java.lang.RuntimeException: java.lang.NullPointerException
Update 2
There seems to be an issue with the session. If I call the following code:
session_service.logIn(user, password)
print(session_service.hasSubject())
it prints False.
The same thing happens when using the transaction:
session_service.beginTransaction()
print(session_service.transactionExists())
also prints False
Try wrapping your changes in a SessionWebService transaction, see JavaDoc:
sessionService = factory.getSessionService();
sessionService.logIn(prop.getProperty("user"),
prop.getProperty("passwd"));
sessionService.beginTransaction();
// ...
// your changes
// ...
sessionService.endTransaction(false);
sessionService.endSession();
As shown in the example in Polarion/polarion/SDK/examples/com.polarion.example.importer.
This will commit all your changes in one single SVN commit.

Google.Cloud.Diagnostics.AspNetCore3 debug level not working

Consider a wizard generated ASP.NET Core project (NET 6). Add a Google.Cloud.Diagnostics.AspNetCore3 NuGet package and services.AddGoogleDiagnosticsForAspNetCore() to Startup.cs. Let GOOGLE_APPLICATION_CREDENTIALS environment variable point to a path to your service account JSON.
Somewhere in the app (e.g. a controller) add the following:
_logger.LogDebug("Nope");
_logger.LogInformation("Yeah");
Google Cloud Logs Explorer shows only the "Yeah" (no specific filters). My appsettings.json looks like:
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
As far as I understand the "Default": "Debug" should work everywhere where a more specific config is missing.
Why am I not seeing the "Nope" being logged? Anything obvious that I'm missing? It's worth mentioning that both Visual Studio Debug Output as well as the Console output show both Nope/Yeah as expected.
Short Answer: Google.Cloud.Diagnostics.AspNetCore3 does not use appsettings.json (at least for now) and one must explicitly set log levels.
Now to the long answer and working code after that.
To add Google Diagnostics to our project we have 3 overloads of ...AddGoogleDiagnosticsForAspNetCore(...) available, and also ...AddGoogle(...) just to use a service we need, such as logging service. (... at the beginning changes depending on dotnet version, examples at the end).
1- In a GCP environment, ...AddGoogleDiagnosticsForAspNetCore() signature is used to set defaults for the Diagnostics. Service details are fetched from GCP.
2- In a GCP environment, ...AddGoogleDiagnosticsForAspNetCore( AspNetCoreTraceOptions, LoggingServiceOptions, ErrorReportingServiceOptions ) signature we can set 3 types of options: AspNet Tracing, Logging Service and Error Reporting Service.
For this use case, if we want only logging services, we can either use positional arguments (null,new LoggingServiceOptions{...},null) (last null is not required) or named arguments (loggingOptions: new LoggingServiceOptions{...})
There are many to be set in LoggingServicesOptions{...} but just for log level purpose the following will suffice: new LoggingServiceOptions{ Options = LoggingOptions.Create(logLevel: LogLevel.Debug) }.
Now we have come to the important one. Although documentation covers enough of it implicitly, it is not made explicitly clear that this use case will directly set options, not services.
3- Although not explicitly clear, this use is for cases outside GCP or when GCP cannot be set properly(not sure how!?) AddGoogleDiagnosticsForAspNetCore( projectId, serviceName, serviceVersion, TraceOptions, LoggingOptions, ErrorReportingOptions ). This may seem similar to the 2nd signature at first, but it does not set options for services.
When one sees Project ID was not provided and could not be autodetected message for 1st or 2nd signature, they have to provide it as a parameter which immediately switches the function to use this 3rd signature.
In this case, if we want only logging services, it has to be used in the form of (projectId,null,null,null,LoggingOptions...,null) for positional arguments (last null is not required) or (projectId:"some ID",loggingOptions: LoggingOptions...) for named arguments
LoggingOptions... is simply be LoggingOptions.Create(logLevel: LogLevel.Debug) to set log level.
4- Apart from adding these details while adding Google Diagnostics to the services, we can instead add logging options when we set configurations: ...AddGoogle( LoggingServiceOptions{...} ). But in this use, we need to provide a project Id in it; new LoggingServiceOptions{ ProjectId = "some ID", Options = LoggingOptions.Create(logLevel: LogLevel.Debug) }
fill in the ...
dotnet 6 started using new top level statements. so we have following steps to follow.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGoogleDiagnosticsForAspNetCore(
projectId: "some ID",
loggingOptions: LoggingOptions.Create(logLevel: LogLevel.Debug)
);
// or
var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddGoogle(
new LoggingServiceOptions {
ProjectId = "some ID",
Options=LoggingOptions.Create(logLevel:LogLevel.Debug)
}
);
Since the OP mentions the use of Startup.cs, the project uses the old style so these are the required parts for that.
// inside ConfigureServices
services.AddGoogleDiagnosticsForAspNetCore(
projectId: "some ID",
loggingOptions: LoggingOptions.Create(logLevel: LogLevel.Debug)
);
// or
// before using "UseStartup"
.ConfigureLogging(
builder => builder.AddGoogle(
new LoggingServiceOptions {
ProjectId = "some ID",
Options=LoggingOptions.Create(logLevel:LogLevel.Debug)
}
)
)
Extra
We can read from the configuration file (top-level format)
var builder = WebApplication.CreateBuilder(args);
var config = builder.Configuration;
builder.Services.AddGoogleDiagnosticsForAspNetCore(
projectId:config["GCP:ID"],
loggingOptions: LoggingOptions.Create(
logLevel: Enum.Parse<LogLevel>(config["GCP:Logging:LogLevel:Default"]
)));
and add a GCP section in appsettings.json
"GCP":{
"ID":"some ID",
"Logging":{
"LogLevel":{
"Default":"Debug"
}
}
}
I've downloaded the mentioned package (it's open-source) and checked default logging-options creation:
As you may see the default logLevel is Information.
And as you go through the implementation there's no sign of reading the level from the config - it's simply passed from the options you may specify in the code:
Initial invocation:
Service provider registration:
Creation of logging provider and options:
Creation of options (1st picture)
And creation of logger (probably invoked somewhere internally by ASP.NET)
The simple answer is Google package doesn't read anything from the appsettings.json by default.
You can set the logging level by using the LoggingOptions:
(Other options omitted for brevity)
builder.Services.AddGoogleDiagnosticsForAspNetCore(loggingOptions: new Google.Cloud.Diagnostics.Common.LoggingServiceOptions
{
// ... Other required options, e.g. projectId
Options = Google.Cloud.Diagnostics.Common
.LoggingOptions.Create(logLevel: LogLevel.Debug
// ... Other necessary options
),
});

Save an image present in PDF on local File System

This is my first experience of using PDFBox jar files. Also, I have recently started working on TestComplete. In short, all these things are new for me and I have been stuck on one issue for last few hours. I will try to explain as much as I can. Would really appreciate any help!
Objective:
To save an image present in a PDF file on the file system
Issue:
When this line gets executed objImage.write2file_2(strSavePath);, I get the error Object doesn't support this property or method.
I am taking some help from here
Code:
function fn_PDFImage()
{
var objPdfFile, strPdfFilePath, strSavePath, objPages, objPage, objImages, objImage, imgbuffer;
strPdfFilePath = "C:\\Users\\aabb\\Desktop\\name.pdf";
strSavePath = "C:\\Users\\aabb\\Desktop\\abc";
objPdfFile = JavaClasses.org_apache_pdfbox_pdmodel.PDDocument.load_3(strPdfFilePath);
objPages = objPdfFile.getDocumentCatalog().getAllPages();
//getting a page with index=1
objPage = objPages.get(1)
objImages = objPage.getResources().getXObjects().values().toArray();
Log.Message(objImages.length); //This is returning 14. i.e, 14 images
//getting an image with index=1
objImage = objImages.items(1);
Log.Message(typeof objImage); //returns "Object" which means it is not null
//saving the image
objImage.write2file_2(strSavePath); //<---GETTING AN ERROR HERE
}
ERROR:
If you are bothered about the method namewrite2file_2, please read this excerpt from the link which I have shared:
In Java, the constructor of a class has the name of this class.
TestComplete changes the constructor names to newInstance(). If a
class has overloaded constructors, TestComplete names them like
newInstance, newInstace_2, newInstance_3 and so on.
Additional Info:
I have imported Jar file(pdfbox-app-1.8.13.jar) and their classes in testcomplete. I am not sure if I need to import some other jar file or its class here:
XObjects are not always image XObjects. And write2file is in the class PDXObjectImage so you need to check your object type first.
Re the second question asked in the comment: the form XObject isn't something you can save. XObject forms are content streams with resources etc, similar to pages. However what you can do is to explore these too whether the resources have images. See how this is done in the ExtractImages source code of PDFBox 1.8.
However there are other places where there can be images (e.g. patterns, soft masks, inline images); this is only available in PDFBox 2.*, see the ExtractImages source code there. (Note that the class names are different).

JIRA, get a parent issue via SOAP api

I need to obtain a parent issue of given issue via SOAP API, or even using database. It seems to be very basic objective, however I didn't find any useful information in internet. Besides, I didn't find any fields in jira's db tables (jiraissue) to set the parent issue of an issue.
Additional info: Jira 5.1, c# .Net
As far as I know there is no way to do this using the SOAP directly.
One possible solution would be using the Jira Scripting Suite. You can create a post-function that will run after the Open status that will copy the parent to a custom field using getParentObject. Then you could use the SOAP function getCustomFields to get the parent.
Another solution via REST API:
Issue issue = getRestClient().getIssueClient().getIssue(task.getKey(), new NullProgressMonitor());
Field issueParent = issue.getField("parent");
if (issueParent  !=null){
    JSONObject jsonParent = (JSONObject)issueParent.getValue();
    BasicIssue partsedIssue = null;
    try {
        partsedIssue = new BasicIssueJsonParser().parse(jsonParent);
    } catch (JSONException e1) {
        e1.printStackTrace();
    }
    System.out.println("parent key: "+partsedIssue.getKey());
}

use tika in nutch plugin

In nutch I'm implementing a plug-in that will get the content of webpages and process them in special way.
My main problem is I want to convert webpages to plainText to be able to processed,, I read that tika toolkit can do that
so, I found this code that use tika to parse urls, I write it under filter method
public ParseResult filter(Content content, ParseResult parseResult, HTMLMetaTags metaTags, DocumentFragment doc)
{
byte[] raw = content.getContent();
ContentHandler handler = new BodyContentHandler();
Metadata metadata = new Metadata();
Parser parser = new AutoDetectParser();
parser.parse(new ByteArrayInputStream(raw), handler, metadata, new ParseContext());
String plainText = handler.toString();
LOG.info("Mime: " + metadata.get(Metadata.CONTENT_TYPE));
LOG.info("content: " + handler.toString());
}
The result of metadata.get(Metadata.CONTENT_TYPE) is text/html
but handler.toString() is empty !
Update:
Also I try to use this line after the parser method
LOG.info ("Status : "+ new ParseStatus().toString());
and I get this result:
Status : notparsed(0,0)
Since version 1.1 Nutch includes a Tika plugin (see also NUTCH-766) that should cover your need. I don't know if there's more comprehensive documentation available. You might want to ask the Nutch users mailing list for more details (or someone here on SO can fill in).
As Jukka Zitting said, Tika is already leveraged in nutch. In the code that you pasted, there is no place that you had set the metadata and ParseStatus to any nutch specific data structure. So you dont see the ParseStatus accordingly.