I am trying to download the content of my s3 bucket, and when I hit the API endpoint the data shows in my Intellij console, but in my postman and browser console I simply get an empty object.
Is there a certain why I am supposed to receive this in an Axios request?
Axios -
downloadLocations() {
axios.get("http://localhost:8080/api/v1/targetLocation/downloadSearchData")
.then((res) => {
console.log(res.data)
// We will need to retrieve the data into a downloadable blob
// const content = new Blob([JSON.stringify(???)],{ type: 'text/plain;charset=utf-8' })
// const fileName = `test.txt`
// saveAs(content, fileName)
}, (error) => {
console.log(error);
});
}
Service -
public ByteArrayOutputStream downloadSearchData() throws IOException {
BasicAWSCredentials awsCredentials = new BasicAWSCredentials(awsAccessKey, awsSecretKey);
AmazonS3 s3client = AmazonS3ClientBuilder
.standard()
.withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
.withRegion(awsRegion)
.build();
var s3Object = s3client.getObject("downloadable-cases", "7863784198_2021-08-16T13_30_06.690Z.json");
var out = new ByteArrayOutputStream();
try (var in = s3Object.getObjectContent()) {
in.transferTo(out);
}
System.out.println(out);
return out;
}
Controller -
#GetMapping(value = "downloadSearchData")
public ByteArrayOutputStream downloadSearchData() throws IOException {
return targetLocationService.downloadSearchData();
}
Ok, I found the answer. I changed the Service and Controller return value to String and it now works perfectly
public String downloadSearchData() throws IOException {
BasicAWSCredentials awsCredentials = new BasicAWSCredentials(awsAccessKey, awsSecretKey);
AmazonS3 s3client = AmazonS3ClientBuilder
.standard()
.withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
.withRegion(Regions.GovCloud)
.build();
var s3Object = s3client.getObject("downloadable-cases", "7863784198_2021-08-16T13_30_06.690Z.json");
var out = new ByteArrayOutputStream();
try (var in = s3Object.getObjectContent()) {
in.transferTo(out);
}
return out.toString();
}
Related
I am very new to Springboot and do not fully understand how postmapping works. Currently, I have to implement Stripe payment system. From what I gathered, Stripe provides a custom payment flow but it is using Spark framework. I was able to create a Springboot Postmapping in place of the Spark Post. I have tried different methods I see online with no success. What would be the best method to do the following.
My PostMapping Code
#PostMapping("/create-payment-intent")
public String StripeTest(HttpServletRequest request, HttpServletResponse response) throws StripeException {
System.out.println("Stripe Controller Begins");
Gson gson = new Gson();
response.setContentType("application/json");
Stripe.apiKey = "sk_test_key";
try {
StringBuilder buffer = new StringBuilder();
BufferedReader reader = request.getReader();
String line;
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
String dataBody = buffer.toString();
CreatePayment postBody = gson.fromJson(dataBody,
CreatePayment.class);
PaymentIntentCreateParams createParams = new PaymentIntentCreateParams.Builder()
.setCurrency("USD")
.setAmount(new Long(calculateOrderAmount(postBody.getItems())))
.build();
// Create a PaymentIntent with the order amount and currency
PaymentIntent intent = PaymentIntent.create(createParams);
// Send publishable key and PaymentIntent details to client
return gson.toJson(new Server.CreatePaymentResponse(intent.getClientSecret()));
} catch (JsonSyntaxException e) {
e.printStackTrace();
return "";
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
I need to get the post to run then fetch the data using my javascript:
// Fetches a payment intent and captures the client secret
async function initialize() {
const response = await fetch("/create-payment-intent", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ items }),
});
const { clientSecret } = await response.json();
const appearance = {
theme: 'stripe',
};
elements = stripe.elements({ appearance, clientSecret });
const paymentElementOptions = {
layout: "tabs",
};
const paymentElement = elements.create("payment", paymentElementOptions);
paymentElement.mount("#payment-element");
}
Which will then be injected into the payment-id in the html below:
<form id="payment-form" action='/create-payment-intent' method='POST'>
<div id="payment-element">
<!--Stripe.js injects the Payment Element-->
</div>
<button id="submit">
<div class="spinner hidden" id="spinner"></div>
<span id="button-text">Pay now</span>
</button>
<div id="payment-message" class="hidden"></div>
</form>
I have tried $.Ajax from an example I read with no luck.
When I send a put request to a user in my spring boot backend, I got a 403 forbidden response. But when I send the same request through postman it gets updates. Can anyone help me to correct my code? I'll put all the relevant code segments below. (front - angular-cli 12, back - spring boot)
front end requesting method
updateUser(userId: string, profilePic: string, shortDes: string, username: string, email: string, phoneNumber: string): Observable<any> {
const body: FormData = new FormData();
body.append('id', userId);
body.append('username', username);
body.append('email', email);
body.append('shortDes', shortDes);
body.append('profilePic', profilePic);
body.append('phoneNum', phoneNumber);
console.log(userId,username,)
return this.http.put<HttpResponse<any>>(environment.baseUrl + `/api/v1/users/` + userId, body,{
observe: 'response'
});
}
backend receiving method
#PutMapping(
value = "/{id}",
produces = MediaType.APPLICATION_JSON_VALUE,
consumes = MediaType.MULTIPART_FORM_DATA_VALUE
)
#ResponseStatus(HttpStatus.OK)
#ResponseBody
public ResponseEntity<?> updateUser( #ModelAttribute UserBody body, #PathVariable("id") int id){
if (body.getId() != id) {
return new ResponseEntity<>("Mismatch userId !!", HttpStatus.BAD_REQUEST);
} else if (true) {
// TODO: 5/26/2022 handle the multi part file size from this stage before save it
}
try {
String filePath = null;
if (body.getProfilePic() != null) {
filePath = fileService.saveUserProfilePicture(body.getProfilePic());
UserDTO user = bo.getUser(id);
fileService.deleteFile(user.getProfilePicture());
}
UserDTO dto = new UserDTO();
dto.setId(body.getId());
dto.setUsername(body.getUsername());
dto.setEmail(body.getEmail());
dto.setShortDescription(body.getShortDes());
dto.setProfilePicture(filePath);
dto.setContactNum(body.getPhoneNum());
bo.updateUserNormalDetails(dto);
return new ResponseEntity<>(dto, HttpStatus.CREATED);
} catch (NoSuchElementException e) {
return new ResponseEntity<>("No user is found !!", HttpStatus.NOT_FOUND);
} catch (Exception e) {
return new ResponseEntity<>("Something went wrong !!", HttpStatus.INTERNAL_SERVER_ERROR);
}
}
postman request
The error I get from the spring-boot backend when I send a put request from the front-end
2022-07-04 10:44:40.619 WARN 3068 --- [nio-8080-exec-7] o.springframework.validation.DataBinder : Skipping URI variable 'id' because request contains bind value with same name.
HTTP request via browser
How do you programmatically set AWS S3 object meta data when uploading a file in Javascript?
I'm wanting to set the Content-Type and Content-Disposition headers for each file so I don't have to manually change the headers later.
When I try the below code, I get "Uncaught (in promise) TypeError: Cannot read property 'add' of undefined".
If I take out the middleware code, the file uploads successfully, but I have to manually set the metadata via S3 console.
Any assistance will be appreciated.
var upload = new AWS.S3.ManagedUpload({
params: {
Bucket: projectBucketName,
Key: jobKey,
Body: file
}
//tags: [{ Key: 'Content-Type', Value: 'application/pdf' }, { Key: 'Content-Disposition', Value: 'inline' }]
});
upload.middlewareStack.add(
(next, context) => async (args) => {
args.request.headers["Content-Type"] = "application/pdf";
const result = next(args);
// result.response contains data returned from next middleware.
return result;
},
{
step: "build",
name: "addContentTypeMetadataMiddleware",
tags: ["METADATA", "CONTENTTYPE"],
}
);
upload.middlewareStack.add(
(next, context) => async (args) => {
args.request.headers["Content-Disposition"] = "inline";
const result = next(args);
// result.response contains data returned from next middleware.
return result;
},
{
step: "build",
name: "addContentDispositionMetadataMiddleware",
tags: ["METADATA", "CONTENTDISPOSITION"],
}
);
promise = await upload.promise();
To set metadata on an onject, you can use the S3 API. Here is an example that is implemented in Java. You can port this to use the AWS SDK for JavaScript.
public static String putS3Object(S3Client s3,
String bucketName,
String objectKey,
String objectPath) {
try {
// Define the metadata
Map<String, String> metadata = new HashMap<>();
metadata.put("author", "Mary Doe");
metadata.put("version", "1.0.0.0");
PutObjectRequest putOb = PutObjectRequest.builder()
.bucket(bucketName)
.key(objectKey)
.metadata(metadata)
.build();
PutObjectResponse response = s3.putObject(putOb,
RequestBody.fromBytes(getObjectFile(objectPath)));
return response.eTag();
} catch (S3Exception e) {
System.err.println(e.getMessage());
System.exit(1);
}
return "";
}
// Return a byte array
private static byte[] getObjectFile(String filePath) {
FileInputStream fileInputStream = null;
byte[] bytesArray = null;
try {
File file = new File(filePath);
bytesArray = new byte[(int) file.length()];
fileInputStream = new FileInputStream(file);
fileInputStream.read(bytesArray);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return bytesArray;
}
I am using Javascript Fetch API to invoke Dot net web API.
Using Visual Studio code for HTML/Javascript & Visual Studio 2019 for Dot Net Web API.
I am trying to implement login functionality using Dot net C# Web API, that will return JWT token in the response and use the token later to invoke separate Web API/Service (e.g. EmployeeInfo ).
Login page :
It displays user id and password fields and the button "Login"
Once user clicks on login button, the function fnlogin is invoked
function fnlogin() {
const uname = document.getElementById('uname').value;
const pwd = document.getElementById('pwd').value;
const logindata = {
username: uname,
password: pwd
}
const loginurl = 'http://localhost:13402/api/Auth/Login';
authenticate(loginurl, logindata);
}
async function authenticate(loginurl, logindata) {
console.log(logindata)
const response = await fetch(loginurl , {
method: "POST",
mode: "cors",
body: JSON.stringify(logindata),
headers: { "Content-type" : "application/json, charset=UTF-8"}
});
const rdata = await response.json();
console.log(rdata);
if (!rdata.success) {
document.getElementById("loginMessage").innerHTML = rdata.message;
return;
}
const inMemoryToken = rdata.data
localStorage.setItem('user', JSON.stringify(rdata));
window.location.href = "http://localhost:5500/Employeeinfo1.html";
}
The Web API returns JWT token properly.
The code in controller is as follows :
[HttpPost("Login")]
public async Task<ActionResult<ServiceResponse<string>>> Login(UserLoginDto request)
{
var response = await _authRepo.Login(
request.Username, request.Password
);
if (!response.Success)
{
return BadRequest(response);
}
return Ok(response);
}
``
The code in AuthRepository class is as follows :
public class AuthRepository : IAuthRepository
{
private readonly AppDbContext _context;
private readonly IConfiguration _configuration;
public AuthRepository(AppDbContext context, IConfiguration configuration)
{
_configuration = configuration;
_context = context;
}
public async Task<ServiceResponse<string>> Login(string username, string password)
{
var response = new ServiceResponse<string>();
var user = await _context.Users.FirstOrDefaultAsync(x => x.Username.ToLower().Equals(username.ToLower()));
if (user == null)
{
response.Success = false;
response.Message = "User not found.";
}
else if (!VerifyPasswordHash(password, user.PasswordHash, user.PasswordSalt))
{
response.Success = false;
response.Message = "Wrong password.";
}
else
{
response.Data = CreateToken(user);
}
return response;
}
public async Task<ServiceResponse<User>> Register(User user, string password)
{
ServiceResponse<User> response = new ServiceResponse<User>();
if (await UserExists(user.Username))
{
response.Success = false;
response.Message = "User already exists.";
return response;
}
CreatePasswordHash(password, out byte[] passwordHash, out byte[] passwordSalt);
user.PasswordHash = passwordHash;
user.PasswordSalt = passwordSalt;
_context.Users.Add(user);
await _context.SaveChangesAsync();
response.Data = user;
return response;
}
public async Task<bool> UserExists(string username)
{
if (await _context.Users.AnyAsync(x => x.Username.ToLower().Equals(username.ToLower())))
{
return true;
}
return false;
}
private void CreatePasswordHash(string password, out byte[] passwordHash, out byte[] passwordSalt)
{
using (var hmac = new System.Security.Cryptography.HMACSHA512())
{
passwordSalt = hmac.Key;
passwordHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
}
}
private bool VerifyPasswordHash(string password, byte[] passwordHash, byte[] passwordSalt)
{
using (var hmac = new System.Security.Cryptography.HMACSHA512(passwordSalt))
{
var computedHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
for (int i = 0; i < computedHash.Length; i++)
{
if (computedHash[i] != passwordHash[i])
{
return false;
}
}
return true;
}
}
private string CreateToken(User user)
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Name, user.Username)
};
var key = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(_configuration.GetSection("AppSettings:Token").Value));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha512Signature);
var tokendDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(claims),
Expires = System.DateTime.Now.AddDays(1),
SigningCredentials = creds
};
var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateToken(tokendDescriptor);
return tokenHandler.WriteToken(token);
}
4. Once the JWT token is returned , it is stored in LocalStorage. I verified in Chrome Dev Tools
But after the next screen is displayed, when I check in Chrome dev tools, the object/token is no longer present in the Local Storage.
Is this because of window.location.href will remove all local data in localStorage in the browser ?
I want to be able to use the token to pass to remaining html screens and web api
You are storing an item in the local storage of http://127.0.0.1:5500 and trying to read it from http://localhost:5500.
From Window.localStorage in MDN Web Docs:
The localStorage read-only property of the window interface allows you to access a Storage object for the Document's origin;
And about Origin:
Web content's origin is defined by the scheme (protocol), host (domain), and port of the URL used to access it. Two objects have the same origin only when the scheme, host, and port all match.
As you see, for the browser the origins are different because the host does not match: 127.0.0.1 is not the same string as localhost.
Use either localhost or 127.0.0.1 everywhere, but do not use both.
I am doing a small project in ASP.NET Core (backend) and VueJs (frontend) the communication is by axios.
I want to send a PDF file to a local path on the server. And show it in a new window.
I've been looking for information for a couple of days and I only get more confused.
This is the closest I've ever been, and I honestly don't know what I'm doing :(
(I apologize for my English)
VueJS & Vuetify
this.$proxies.menusProxy
.getFileStream(
this.eitem.identificador,
{
params: {
file: "Clientes.pdf",
},
},
)
.then((x) => {
console.log("Done: ", x);
})
.catch((x) => {
console.log("Error: ", x);
});
})
.catch((x) => {});
ASP.NET
public async Task<HttpResponseMessage> GetFileStream(string file)
{
var uploads = Path.Combine("c:\\Shared\\06W03R0821105PLAE1\\"+file);
MemoryStream responseStream = new MemoryStream();
Stream fileStream = System.IO.File.Open(uploads, FileMode.Open);
fileStream.CopyTo(responseStream);
fileStream.Close();
responseStream.Position = 0;
HttpResponseMessage response = new HttpResponseMessage();
response.StatusCode = HttpStatusCode.OK;
response.Content = new StreamContent(responseStream);
string contentDisposition = string.Concat("attachment; filename=", file);
response.Content.Headers.ContentDisposition =
ContentDispositionHeaderValue.Parse(contentDisposition);
return response;
}
Console response:
Image Console
Thank you very much to all