Volley post params with multi level array is not working - arrays

I am using volley JSONObject Request. I am trying to send multi level array in POST params, but it is not working.
Here is my array structure.
[
"param1" => "single value",
"param2" => [123,321],
"param3" => 112
]
I am not sure how to send these values.

Related

Concat multilevel API calls in Angular using rxjs

I am new to rxjs I am calling three api calls using the hacker new api. I want to concat response of the last api call to the second api call.
I want to achieve something like this.
[
{
"by": "john"
"title": "Sample title"
"time":1657786985
"karma": 123456 // this is from the third api call that i want to merge
},
{
"by": "jane"
"title": "Sample title 2"
"time":1657786333
"karma": 123456 // this is from the third api call that i want to merge
}
]
So far this is my code
this.service.fetchStories().pipe( // get list of id array
switchMap(idArray => forkJoin(
idArray.map(id => this.service.fetchStoryItems(id).pipe( // first api call
concatMap(itm => this.service.fetchUserById(itm.by)) // second api call i want to merge { karma } to the first api call
)))
),
take(1)
).subscribe(data => console.log(data));
But the result is I am getting only the response of the last api call. Can somebody help me. I am trying to learn rxjs.
All you need to do is to pipe the third call again and merge the results.
this.service.fetchStories().pipe( // get list of id array
switchMap(idArray => forkJoin(
idArray.map(id => this.service.fetchStoryItems(id).pipe( // first api call
concatMap(itm => this.service.fetchUserById(itm.by).pipe(map(({karma}) => ({ ...itm, karma }))))
)))
),
take(1)
).subscribe(data => console.log(data));

PHP Laravel Sage One API says invoice lines are required when they are there and not empty

I am currently integrating an application with the Sage One API and am having a problem. The API says that invoice lines may not be empty, but the data is there. What am I doing wrong?
Here is my method of getting the line items:
$lineItems = [];
foreach ($invoiceItems as $invoiceItem){
$lineItems[] =
[
"SelectionId" => "35175771",
"TaxTypeId" => "6194291",
"Description" => $invoiceItem->name,
"Quantity" => $invoiceItem->duration,
"UnitPriceExclusive" => $invoiceItem->total_excl_vat
];
}
foreach ($invoiceOtherItems as $invoiceOtherItem){
$lineItems[] =
[
"SelectionId" => "35175771",
"TaxTypeId" => "6194291",
"Description" => $invoiceOtherItem->otherItem->name,
"Quantity" => $invoiceOtherItem->quantity,
"UnitPriceExclusive" => $invoiceOtherItem->total_excl_vat
];
}
//dd($lineItems)
And here is the part in the post data to the API where I post the invoice items (removed majority items for the sake of brevity here):
$invoice = [
"Date" => Carbon::now()->toDateString(),
"Lines" => $lineItems,
"DueDate" => "2021-08-29"
];
Performing a dump and die where I commented the dd returns all the arrays, yet the API is telling me lines are required. Am I doing anything wrong? The code seems correct to me and I can't find anything to help on this matter.
For anyone that might run across this problem here is the solution:
In your response, define your headers like this:
'headers' => ['Content-Type' => 'application/json', 'Accept' => 'application/json']
And do not use form_params, but use this instead:
'body' => json_encode($invoice)

How I can read and storage a JSON object from Dynamodb into React?

I am getting a JSON object from a Lambda function. When I get a specific value from the JSON object and storage it into an array it works fine. I don't know how to storage the whole JSON object on any structure in React. The idea is to storage the JSON object to make some calculations later with the values.
I am using "json.map" get the values
Here is where I call the API gateway and fecth the json object:
componentDidMount() {
fetch('https://llzgbat7hi.execute-api.us-east-2.amazonaws.com/api/getrange?domain=demo.com&cont=5')
.then(res => res.json())
.then(json => {
const RecordRowCount = json.map(item => item.RecordRowCount)
this.setState({ tasks: RecordRowCount })
});
}
The code above show how I get the value RecordRowCount and storage it into an array but I need to fecth the whole JSON object
This is the actual JSON structure returned from DB:
[
{
"Id": "123455",
"Customer": 100,
"Domain": "demo.com",
"OrgName": "demo.com",
"ReportMetadataEmail": "demo#me.com",
"ReportMetadataExtraContactInfo": "postmaster#demo.com"
},
{
"Id": "123456",
"Customer": 101,
"Domain": "demo1.com",
"OrgName": "demo1.com",
"ReportMetadataEmail": "demo1#me.com",
"ReportMetadataExtraContactInfo": "postmaster#demo1.com"
}
]
I want to map that JSON object into any React structure (Ex Array)
Thanks a lot #AppleJam, #Taki and #tcoulson
You were right. I just assigned json to tasks and it worked, now my tasks array hold all the json object.
Thanks

How to get authenticated to join private channel using Laravel Echo and Socket.io

I am using Laravel 5.8.10, React 16.8, Laravel Echo Server 1.5.2, Redis 3.2.9, and Socket.io 2.2.0.
I am NOT using Pusher and don't want to use Pusher.
I am trying to create a basic chat system for site users. They log in normally using session authentication with email and password - all of that works fine.
There are 2 types of users: Brands and Influencers. Each has its own custom guard (web-brands & web-influencers). All session guards work normally.
I'm building the chat page using React. I can successfully join a public channel and receive messages on that public channel. However, the problem is when I try to make the channel private.
When I try to join a private channel, Laravel Echo Server sends an authentication request to: http://localhost:8000/broadcasting/auth.
But that returns the following 401 error:
{"message":"Unauthenticated."}
Client can not be authenticated, got HTTP status 401
Right now, I am trying to authenticate requests to /broadcasting/auth using a simple 'api_token' that is stored in the users tables (brands and influencers are the 2 users tables). This is a unique 60-character string.
I am trying this 'api_token' strategy because it sounds easier than setting up Laravel Passport, but perhaps I am wrong about that.
This is the constructor method from my React page:
import React, { Component } from 'react';
import Echo from "laravel-echo";
import Socketio from "socket.io-client";
constructor(props) {
super(props);
this.state = {
currentConversationId: conversations[0].id,
data: '',
};
this.selectConversation = this.selectConversation.bind(this);
let echo = new Echo({
broadcaster: 'socket.io',
host: 'http://localhost:6001',
client: Socketio,
auth: {
headers: {
// I currently have CSRF requirements disabled for /broadcasting/auth,
// but this should work fine once it is enabled anyway
'X-CSRF-Token': document.head.querySelector('meta[name="csrf-token"]'),
// I have the api_token hard-coded as I am trying to get it to work,
// but I have also used the javascript variable 'token' below
'api_token':'uUOyxRgCkVLKvp7ICZ0gXaELBPPbWEL0tUqz2Dv4TsFFc7JO4gv5kUi3WL3Q',
'Authorization':'Bearer: ' +'uUOyxRgCkVLKvp7ICZ0gXaELBPPbWEL0tUqz2Dv4TsFFc7JO4gv5kUi3WL3Q',
//'api_token':token,
//'Authorization':'Bearer: ' + token,
}
}
});
// Note that the ID of 1 is hardcoded for now until I get it to work
echo.private('brand.1')
.listen('SimpleMessageEvent', event => {
console.log('got something...');
console.log(event);
this.state.data = event;
});
}
Here you can see the in $php artisan route:list, the route is using auth:api middleware:
| GET|POST|HEAD | broadcasting/auth | Illuminate\Broadcasting\BroadcastController#authenticate | auth:api
Here is my BroadcastServiceProvider.php:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Broadcast;
class BroadcastServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
Broadcast::routes(['middleware' => ['auth:api']]);
require base_path('routes/channels.php');
}
}
Here is my auth.php:
<?php
return [
'defaults' => [
'guard' => 'web-brands',
'passwords' => 'brands',
],
'guards' => [
'web-brands' => [
'driver' => 'session',
'provider' => 'brands',
],
'web-influencers' => [
'driver' => 'session',
'provider' => 'influencers',
],
'api' => [
'driver' => 'token',
'provider' => 'brands2',
],
],
'providers' => [
'brands' => [
'driver' => 'eloquent',
'model' => App\Brand::class,
],
'influencers' => [
'driver' => 'eloquent',
'model' => App\Influencer::class,
],
'brands2' => [
'driver' => 'database',
'table' => 'brands',
],
],
'passwords' => [
'brands' => [
'provider' => 'brands',
'table' => 'password_resets',
'expire' => 60,
],
'influencers' => [
'provider' => 'influencers',
'table' => 'password_resets',
'expire' => 60,
],
],
];
Here is my channels.php:
Broadcast::channel('brand.{id}',true);
Note that I have the brand.{id} set it to return true by default. I have also tried this for channels.php:
Broadcast::channel('brand.{id}', function ($brand,$id) {
return $brand->id === Brand::find($id)->id;
});
I have already tried testing the simple api_token method by using a dummy route:
Route::get('test-test-test',function(){return 'asdf';})->middleware('auth:api');
This test works:
http://localhost:8000/test-test-test results in redirect
http://localhost:8000/test-test-test?api_token=123 results in redirect
http://localhost:8000/test-test-test?api_token=[the actual correct 60-character token] results in 'asdf'
Here is some info from my .env:
BROADCAST_DRIVER=redis
QUEUE_DRIVER=redis
CACHE_DRIVER=file
QUEUE_CONNECTION=database
SESSION_DRIVER=file
SESSION_LIFETIME=120
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
Here is my laravel-echo-server.json:
{
"authHost": "http://localhost:8000",
"authEndpoint": "/broadcasting/auth",
"clients": [],
"database": "redis",
"databaseConfig": {
"redis": {},
"sqlite": {
"databasePath": "/database/laravel-echo-server.sqlite"
}
},
"devMode": true,
"host": null,
"port": "6001",
"protocol": "http",
"socketio": {},
"sslCertPath": "",
"sslKeyPath": "",
"sslCertChainPath": "",
"sslPassphrase": "",
"subscribers": {
"http": true,
"redis": true
},
"apiOriginAllow": {
"allowCors": false,
"allowOrigin": "",
"allowMethods": "",
"allowHeaders": ""
}
}
Perhaps I am not sending the api_token correctly in the header of the laravel echo request?
UPDATE/EDIT:
Now I have tried removing the auth:api middleware for the /broadcasting/auth route. I'm not sure if that was the correct thing to do.
That now produces a 403 error:
Client can not be authenticated, got HTTP status 403
UPDATE 2 - IMPORTANT
So I know this is not recommended, but I started changing some things inside of the laravel source files... I got it to work finally and now that I have figured it out, I would like to override the source files that I changed instead of actually changing them. I did save the originals so I can easily revert back.
One big challenge was that while changing the source files, I was not able to use the where() method, only the find() method to lookup users.
The key function that needed changing was retrieveUser() (which is located inside of Illuminate/Broadcasting/Broadcasters/Broadcaster.php.
The problem was that it kept trying to run:
return $request->user();
...but that user() function never worked, which is why it always returned a 403 forbidden error. I think it is because the actual Laravel Echo request was sent from React (in javascript frontend), so there was no user object attached to the request. In other words, it was like a guest making the request. That explains why the public channels worked, but the private ones didn't.
I never did figure out how to get the user information to be sent with the request through React, but I did figure out a workaround.
Basically what I had to do:
In my controller, encrypt the ID of the user and pass it to javascript as a variable.
Pass the encrypted ID variable through the Echo request as part of the header.
Modify the retrieveUser() function to use find(Crypt::decrypt($id)) to lookup the user instead of ->user() (or where() which was strangely not allowed).
From what I can tell, this seems like a decent strategy from a security perspective, but perhaps readers could point out if that is actually correct.
To hack your way into a private channel, you would have to know the ID of the channel you want to listen to, then pass it as an encrypted variable in the header of the request.
Maybe a potential hacker could say that he/she wants to listen to private channel 'brand.1' and all they would have to do is encrypt the number 1 and pass it through the header. I guess I don't know how that works enough to know whether that is possible.
Anyway my goals now are:
converting this into an override setup instead of explicitly changing the Laravel source code.
figuring out if passing the encrypted ID through the request header is secure enough for production.
It does seem like the encrypted ID in the header (which does change every time you run the request) is more secure than simply passing through an 'api_token' which would be a value stored in the users table and is what most people seem to do.

How to get the json data by yii2

Two question:
1.I use the post method of yii2 to get the json data, sent by front end with ngResource in Angularjs. And I configure the yii2 as follow:
'parsers' => [
'application/json' => 'yii\web\JsonParser',
'text/json' => 'yii\web\JsonParser',
]
But it doesn't work when I use $post = Yii::$app->request->post() to get the data. Additionally, the data is not serialized.
2.I configure the yii2
'response' => [
'formatters' => [
\yii\web\Response::FORMAT_JSON => [
'class' => 'yii\web\JsonResponseFormatter',
'prettyPrint' => YII_DEBUG,
]
]
],
When I find that it is different from
Yii::$app->response->format = Response::FORMAT_JSON;
before return some value. The former doesn't transform the data to json format. I don't know why?
1.I force the contentTye to application/x-www-form-urlencoded;charset=utf-8, it is so silly.
2.Formatters is different from format.

Resources