How to correctly parse data from Firebase Realtime Database? - firebase

First encounter with RealtimeDatabse - My database structure looks like this:
I use this code to read the data:
Map<String, BookingItem> bookingMap={}; // Need to populate this
final db = FirebaseDatabase(databaseURL:"https:MYURL");
final fb = db.reference();
fb.child('1b***APkCeLs/Form Responses 1').once()
.then((DataSnapshot data) {
print(jsonEncode(data.value)); // Shows up fine
var encod = jsonEncode(data.value);
try { // Problem here
// Need some code help with getting the data into MAP format please
} on Exception catch(e) {
print ('Error: $e');
}
debugPrint(bookingList.toString());
}).catchError((onError){
if (kDebugMode) print (onError);
});
My booking item class is simple:
class BookingItem {
String email;
//String chooseYourBookingLocation;
BookingItem({required this.email});//, required this.chooseYourBookingLocation});
BookingItem.fromJson(Map<String, dynamic> json)
: //chooseYourBookingLocation = json['Choose your booking location'],
email = json['Email'];
}
I want - Fri Jul 09 2021 07:33:09 GMT+0100 (British Summer Time) as key and BookingItem object with sub-details as a value.
I want to just start by grabbing the email and then the rest in the next steps.
End goal is to have BookingItem Map with all the details so I can update field/fields later as well.
jsonEncode prints this on the screen
{"Fri Jul 09 2021 07:33:09 GMT+0100 (British Summer Time)":{"Additional Information":"","Email":"litl.com","First Name":"Laura","Choose your booking location":"Brentwood","Time":"13:00","Last Name":"Irving","Phone Number":"074","Number of Guests":5,"Timestamp":"2021-07-09T06:33:09.675Z","Date":"","Email Address":""},"Fri Jul 09 2021 10:51:06 GMT+0100 (British Summer Time)":{"Additional Information":"","Email":"sa***uk.com","First Name":"Sacha","Choose your booking location":"Brentwood","Time":"18:30","Last Name":"Leal","Phone Number":"07**4","Number of Guests":2,"Timestamp":"2021-07-09T09:51:06.939Z","Date":"","Email Address":""},"Fri Jul 09 2021 12:02:22 GMT+0100 (British Summer Time)":{"Additional Information":"","Email":"nic**om","First Name":"Nicola","Choose your booking location":"Hatfield","Time":"15:00","Last Name":"Coan","Phone Number":"07***4","Number of Guests":2,"Timestamp":"2021-07-09T11:02:22.663Z","Date":"","Email Address":""},"Fri Ju...
I just want to simply do the following to start with:

Related

chunked response empty (terminating) chunk missing

I have a controller action that returns a CSV document produced asynchronously by a data source. I subscribed to an observable data stream and I write to the http response with Response.WriteAsync(). It seems to work apart of the fact that the terminating (empty) chunk is missing at the end of the response (The missing data in hex is 30 0d 0a 0d 0a for the terminating 0\r\n\r\n).
I have few questions:
- is it okay to use WriteAsync in this scenario - call it multiple times as the data comes in - i certainly do not want to buffer the whole dataset and return it at once as it can grow huge
- whose responsibility it is to write the terminating chunk (should it write it explicitly in OnComplete handler with WriteAsync as well?)
example response from an action that returns a json object (note the terminator at the end of the response):
HTTP/1.1 200 OK
Date: Tue, 05 Feb 2019 09:25:23 GMT
Server: Kestrel
Transfer-Encoding: chunked
21
{"results":[{"statement_id":0}]}
0
Response from my action:
HTTP/1.1 200 OK
Date: Tue, 05 Feb 2019 09:27:42 GMT
Content-Type: text/csv
Server: Kestrel
Transfer-Encoding: chunked
47
ID,Timestamp,BadQualityCount,MAX_value,MEAN_value,MIN_value,TotalPoints
65
...
5d
SwitchStatus_On_a797c2c2-de78-4fe8-9e4b-5d64f51d1e00,2019-0204T11:52:17.3680000Z,0,0,0,0,1
Controller code:
using (var disposable = observableContent.Subscribe(
async current =>
await Response.WriteAsync(current),
() =>
{
//Response.WriteAsync(Environment.NewLine);
//Response.WriteAsync("0");
Response.Body.Flush();
completed = true;
}
))
SpinWait.SpinUntil(() => completed);
return Ok();
It turned out the terminator is written correctly if the action signature is changed from Task to Task.

Problem with routing css on my Node Express server

I am building a back-end for my web page, with file structure like this:
public
css
main.css
main_b.css
index.hbs
index_b.hbs
server
server.js
Styling sheets are referenced in index files by link attributes containing:
rel="stylesheet" type="text/css" href="main.css"
rel="stylesheet" type="text/css" href="main_b.css"
Here is my server.js :
const path = require('path');
const fs = require('fs');
const express = require('express');
const app = express();
const hbs = require('hbs');
hbs.registerPartials(path.join(__dirname, '../public/partials'));
app.set('view engine', 'hbs');
app.use(express.static(path.join(__dirname, '../public/css')));
// activity logger
app.use((req, res, next) => {
const now = new Date().toString();
const logEntry = `${now}: ${req.headers.host} ${req.method}${req.url}`;
fs.appendFile(path.join(__dirname, '../server/server.log'), logEntry.concat('\n'), (error) => {
if (error) {
console.log(error);
}
});
process.env.route = req.path;
next();
});
app.get('*', (req, res) => {
switch (process.env.route) {
case '/': // home page
res.render('../public/index.hbs');
break;
case '/b': // basic layout
res.render('../public/index_b.hbs');
break;
default: // unknown routes
res.render('../public/index.hbs');
}
});
app.listen(3000);
On requesting localhost:3000, log entry is ok:
Thu Jan 24 2019 07:57:08 GMT+0200 (Eastern European Standard Time): localhost:3000 GET/
On requesting localhost:3000/abc, log entry is also ok:
Thu Jan 24 2019 07:57:08 GMT+0200 (Eastern European Standard Time): localhost:3000 GET/abc
And the problem shows on testing requests with sub-routes like localhost:3000/abc/def, css doesn't render and the log entry is :
Thu Jan 24 2019 08:04:55 GMT+0200 (Eastern European Standard Time): localhost:3000 GET/abc/def
Thu Jan 24 2019 08:04:56 GMT+0200 (Eastern European Standard Time): localhost:3000 GET/abc/teamk-reset.css
Thu Jan 24 2019 08:04:56 GMT+0200 (Eastern European Standard Time): localhost:3000 GET/abc/main.css
I saw that part of the route is used to amend the css lookup path,
and tried to solve the problem by index and redirect properties of the options object in Express.static(), but no success.
Would be glad to receive some directions/ reference,
otherwise probably I should refactor my route querying approach.
I found the issue with my code,
Styling sheets should be referenced in index files by link attributes containing:
rel="stylesheet" type="text/css" href="/main.css"
rel="stylesheet" type="text/css" href="/main_b.css"
, their names prepended with '/' for correct lookup URL construction.

GWT with AsyncCallback and SuggestOracle

I use 'AsyncCallbacks' to the server (Tomcat) to query a database for 'resultsets', which should be shown as the result of the 'SuggestOracle'.
My problem is that, while typing in the input field, several 'AsyncCallbacks' are fired, but they are not fired in the order as they are entered.
For example:
If I enter the string "user1" there should be 5 callbacks be fired off. Now look at the server log:
Dez 30, 2017 9:27:59 AM com.test.server.dispatch.actionhandlers.SuggestUsersActionHandler execute
INFORMATION: Giving suggestinos for query u searching for contacts of user 136141
Dez 30, 2017 9:27:59 AM com.test.server.dao.UserDAO getSuggestions
INFORMATION: suggesting ... with query:u
Dez 30, 2017 9:28:00 AM com.test.server.dao.UserDAO getSuggestions
INFORMATION: query resulted in: 4 elements
Dez 30, 2017 9:28:00 AM com.test.server.dispatch.ActionExecutor execute
INFORMATION: com.test.entities.User(Id: 136141, Email: h#h.com) finished executing action com.test.services.dispatch.actions.SuggestUsersAction
Dez 30, 2017 9:28:01 AM com.test.server.dispatch.actionhandlers.SuggestUsersActionHandler execute
INFORMATION: Giving suggestinos for query user1 searching for contacts of user 136141
Dez 30, 2017 9:28:01 AM com.test.server.dao.UserDAO getSuggestions
INFORMATION: suggesting ... with query:user1
Dez 30, 2017 9:28:02 AM com.test.server.dao.UserDAO getSuggestions
INFORMATION: query resulted in: 1 elements
Dez 30, 2017 9:28:02 AM com.test.server.dispatch.ActionExecutor execute
INFORMATION: com.test.entities.User(Id: 136141, Email: h#h.com) finished executing action com.test.services.dispatch.actions.SuggestUsersAction
Dez 30, 2017 9:28:02 AM com.test.server.dispatch.actionhandlers.SuggestUsersActionHandler execute
INFORMATION: Giving suggestinos for query user searching for contacts of user 136141
Dez 30, 2017 9:28:02 AM com.test.server.dao.UserDAO getSuggestions
INFORMATION: suggesting ... with query:user
Dez 30, 2017 9:28:03 AM com.test.server.dao.UserDAO getSuggestions
INFORMATION: query resulted in: 4 elements
Dez 30, 2017 9:28:03 AM com.test.server.dispatch.ActionExecutor execute
INFORMATION: com.test.entities.User(Id: 136141, Email: h#h.com) finished executing action com.test.services.dispatch.actions.SuggestUsersAction
Dez 30, 2017 9:28:03 AM com.test.server.dispatch.actionhandlers.SuggestUsersActionHandler execute
INFORMATION: Giving suggestinos for query us searching for contacts of user 136141
Dez 30, 2017 9:28:03 AM com.test.server.dao.UserDAO getSuggestions
INFORMATION: suggesting ... with query:us
Dez 30, 2017 9:28:04 AM com.test.server.dao.UserDAO getSuggestions
INFORMATION: query resulted in: 4 elements
Dez 30, 2017 9:28:04 AM com.test.server.dispatch.ActionExecutor execute
INFORMATION: com.test.entities.User(Id: 136141, Email: h#h.com) finished executing action com.test.services.dispatch.actions.SuggestUsersAction
It first queries for "u" then for "user1" then for "user" then for "us" ..
so the requests are not sent in the right order.
Do you know any tip of how to send those async queries in the right order?
I fear that using 'AsyncCallbacks' in combination with 'SuggestOracles' are not a good idea.
You should never assume that asynchronous callbacks would be fired in any special order. There are many factors that can cause some calls to be delayed and thus the order can be random.
My favorite method is to just keep the last callback. Please, note, that while you are typing, let's say user1 you get 5 calls to the server, but you are only interested in the result for user1 results. Previous (like us, use etc.) can (or even should) be omitted.
So I've extended AsyncCallback to CancelableAsyncCallback:
public abstract class CancelableAsyncCallback<T> implements AsyncCallback<T> {
private boolean cancelled = false;
public void cancel() {
cancelled = true;
}
public boolean isCancelled() {
return cancelled;
}
}
I keep track of the last callback and cancel the unwanted previous results like this:
if(lastCallback != null)
lastCallback.cancel();
lastCallback = new CancelableAsyncCallback<Type>() {
#Override
public void onFailure(Throwable caught) {
if(!isCancelled()) {
// do the stuff
}
}
#Override
public void onSuccess(Type result) {
if(!isCancelled()) {
// do the stuff
}
}
};
Adams answer will probably work in a lot of situations. He is absolutely right that you can never assume AsyncCallbacks will be handled in any order that you expect.
I handle this in a slightly different way: in my response object, I also return the original query. I can then check to see if the response still applies to the state that the client application is now in.
This would be something like:
callback = new AsyncCallback<Type>() {
#Override
public void onFailure(Throwable caught) {
// handle error
}
#Override
public void onSuccess(Type result) {
String originalQuery = result.getOriginalQuery();
if (originalQuery.equals(oracleBox.getValue())) {
// handle return values
}
}
};

Symfony2 Authorize.net SIM error

I want to use Authorize.net SIM payment method in Symfony using payum.org.
There is no official gateway for it but there is one in omnipay: omnipay-authorizenet. There is also omnipay-bridge in payum so it is possible to use omnipay gateways in payum.
So I use this setup and after submitting the authorize.net form I get the error:
[date] request.CRITICAL: Uncaught PHP Exception Omnipay\Common\Exception\InvalidRequestException: "Incorrect hash" at .../authorize/vendor/omnipay/authorizenet/src/Message/SIMCompleteAuthorizeRequest.php line 42 {"exception":"[object] (Omnipay\\Common\\Exception\\InvalidRequestException(code: 0): Incorrect hash at .../authorize/vendor/omnipay/authorizenet/src/Message/SIMCompleteAuthorizeRequest.php:42)"} []
BUT this is NOT because of the generated hashes being incorrect - it is because capture url is called second time without the POST data.
On a clean installation of Symfony2 with 3 packages:
composer.json:
"payum/payum-bundle": "0.15.*",
"omnipay/authorizenet": "~2.0",
"payum/omnipay-bridge": "*#stable"
config.yml:
payum:
security:
token_storage:
AppBundle\Entity\PaymentToken: { doctrine: orm }
storages:
AppBundle\Entity\Payment: { doctrine: orm }
gateways:
authorizeGateway:
omnipay_offsite:
type: AuthorizeNet_SIM
options:
hashSecret: 'Simon'
ApiLoginId: 'xxx'
transactionkey: 'xxx'
testMode: false
developerMode: true
Controller:
/**
* #Route("/prepare", name="prepare")
*/
public function prepareAction()
{
$gatewayName = 'authorizeGateway';
$storage = $this->get('payum')->getStorage('AppBundle\Entity\Payment');
$payment = $storage->create();
$payment->setNumber(uniqid());
$payment->setCurrencyCode('USD');
$payment->setTotalAmount(1);
$payment->setDescription('A description');
$payment->setClientId('anId');
$payment->setClientEmail('foo#example.com');
$storage->update($payment);
$captureToken = $this->get('payum.security.token_factory')->createCaptureToken(
$gatewayName,
$payment,
'done' // the route to redirect after capture
);
return $this->redirect($captureToken->getTargetUrl());
}
/**
* #Route("/done", name="done")
*/
public function doneAction(Request $request)
{
...
}
Going to /prepare shows a redirecting to authorize.net page for a second and I'm redirected to external test.authorize.net/gateway/transact.dll (on https) page where I specify card number (test card number) and expiration date in the future.
Submitting this form gives:
An error occurred while trying to report this transaction to the merchant. An e-mail has been sent to the merchant informing them of the error. The following is the result of the attempt to charge your credit card.
This transaction has been approved.
It is advisable for you to contact the merchant to verify that you will receive the product or service.
I'm getting the email about Merchant Email Receipt and the one about the error:
Authorize.Net Developer Center Merchant,
Your script timed out while we were trying to post transaction results to it.
Transaction ID: XXX
Transaction Result: This transaction has been approved.
The transaction is processed correctly, the capture script is called, hashes match and then the capture is called again without post data - then hashes don't match and authorize displays error.
Requests that are made from symfony profiler:
Token IP Method URL Time Status
fe39ec 198.241.162.104 GET .../payment/capture/vVgoUCPtgCOglv6rLwhIbUp64RZ_oIql1_KDpWjdrdk Tue, 17 Nov 2015 09:47:36 +0100 500
bba47c 198.241.162.104 GET .../payment/capture/vVgoUCPtgCOglv6rLwhIbUp64RZ_oIql1_KDpWjdrdk Tue, 17 Nov 2015 09:47:36 +0100 200
c95b83 198.241.162.104 POST .../payment/capture/vVgoUCPtgCOglv6rLwhIbUp64RZ_oIql1_KDpWjdrdk Tue, 17 Nov 2015 09:47:36 +0100 302
a87347 myip GET .../payment/capture/vVgoUCPtgCOglv6rLwhIbUp64RZ_oIql1_KDpWjdrdk Tue, 17 Nov 2015 09:47:30 +0100 200
c95d57 myip GET .../prepare Tue, 17 Nov 2015 09:47:29 +0100 302
From what i see when we call /prepare we get redirected to capture right away this goes to authorize's form. Then after a few seconds (when credit card data is filled in and submitted) authorize (different ip) makes post request to capture. This is 302 redirect (and probably should be a SIM response with javascript code to go back to our page?). Capture is called secod time with GET and calculated hashes don't match - this is 500 response - authorize stays on their url and shows the error message. Done script is never called.
What can be the issue? It's difficult to debug this further because there is payum, omnipay-bridge, omnipay, authorize combined.
Im testing this on the environment accessible from the internet with account on http://developer.authorize.net/ with test mode off.
UPDATE:
If I add notify token to the controller, like this:
/**
* #Route("/prepare", name="prepare")
*/
public function prepareAction()
{
$gatewayName = 'authorizeGateway';
$storage = $this->get('payum')->getStorage('AppBundle\Entity\Payment');
$payment = $storage->create();
$payment->setNumber(uniqid());
$payment->setCurrencyCode('USD');
$payment->setTotalAmount(1); // 1.23 EUR
$payment->setDescription('A description');
$payment->setClientId('anId');
$payment->setClientEmail('foo#example.com');
$storage->update($payment);
$captureToken = $this->get('payum.security.token_factory')->createCaptureToken(
$gatewayName,
$payment,
'done' // the route to redirect after capture
);
$tokenFactory = $this->get('payum.security.token_factory');
$notifyToken = $tokenFactory->createNotifyToken($gatewayName, $payment);
$payment->setDetails(['notifyUrl' => $notifyToken->getTargetUrl()]);
$storage->update($payment);
return $this->redirect($captureToken->getTargetUrl());
}
I get error "Request Notify{model: ArrayObject} is not supported.":
[2015-11-17 17:46:50] request.INFO: Matched route "payum_notify_do". {"route_parameters":{"_controller":"Payum\\Bundle\\PayumBundle\\Controller\\NotifyController::doAction","payum_token":"Lv5ovrC-8vikIB9ItDVLcNfuRzjjaD_pPiE3-6VIV8Y","_route":"payum_notify_do"},"request_uri":".../payment/notify/Lv5ovrC-8vikIB9ItDVLcNfuRzjjaD_pPiE3-6VIV8Y"} []
[2015-11-17 17:46:50] security.INFO: Populated the TokenStorage with an anonymous Token. [] []
[2015-11-17 17:46:50] request.CRITICAL: Uncaught PHP Exception Payum\Core\Exception\RequestNotSupportedException: "Request Notify{model: ArrayObject} is not supported." at .../authorize/vendor/payum/core/Payum/Core/Exception/RequestNotSupportedException.php line 29 {"exception":"[object] (Payum\\Core\\Exception\\RequestNotSupportedException(code: 0): Request Notify{model: ArrayObject} is not supported. at .../authorize/vendor/payum/core/Payum/Core/Exception/RequestNotSupportedException.php:29)"} []
Omnipay bridge 0.15.x does not set a notifyUrl, and the omnipay gateway uses return url as notify one. When notification comes (before you are redirected) the capture token is invalidated and no longer available.
There are two solutions:
Upgrade to 1.0 where notifyUrl is generated. Btw you can use omnipay gateway factory instead of omnipay_offsite.
or you have to generate notify url yourself, and set it to notifyUrl
$tokenFactory = $this->get('payum.security.token_factory');
$notifyToken = $tokenFactory->createNotifyToken($gatewayName, $payment);
$payment->setDetails(['notifyUrl' => $notifyToken->getTargetUrl()]);
$storage->update($payment);

Stubbing tomorrow's date in rspec

I have a method in which am sending tomorrow's date(1.date.from_now). I'm testing the same method in my specs. Can anyone tell me how to stub that date.
if I pass 1.date.from now. am getting following error.
<S3Client (class)> received :upload_csv_by_path with unexpected arguments
expected: ("/home/projects/sh/tmp/test_exporter.csv", nil, {:expires=>Sat, 07 Feb 2015 11:36:39 UTC +00:00})
got: ("/home/projects/sh/tmp/test_exporter.csv", nil, {:expires=>Sat, 07 Feb 2015 11:36:39 UTC +00:00})
below is my method
S3Client.upload_csv_by_path(file_name, nil, expires: 1.day.from_now)
Here is my spec,
S3Client.should_receive(:upload_csv_by_path).with("#{Rails.root}/tmp/scalar_test_exporter.csv", nil, expires: 1.day.from_now)
Can anyone tell me how can i solve this issue
The issue is that the times might look exactly the same, but the timestamps aren't, the time which is spent between running the two statements ( even if it's in micro seconds ) makes the time different, to solve it you should use the same time variable in both statements, for example:
time = Time.now
S3Client.should_receive(:upload_csv_by_path).with("#{Rails.root}/tmp/scalar_test_exporter.csv", nil, expires: time)
S3Client.upload_csv_by_path(file_name, nil, expires: time)
This way you could make sure that the time is the same in both statements, or you could use a gem like timecop to help you with this like #gotva suggested, timecop is very useful because it gives you the ability to freeze time, move forward and backwards in time, it's nice, for the same example you'd write this
Time.freeze
S3Client.should_receive(:upload_csv_by_path).with("#{Rails.root}/tmp/scalar_test_exporter.csv", nil, expires: 1.day.from_now)
S3Client.upload_csv_by_path(file_name, nil, expires: 1.day.from_now)
Time.return
Solved by using Time.now + 1.day in my method.
and stubbed the Time.now and while passing parameter added 1day as below.
current_time = Time.now
Time.stub(:now) { current_time }
S3Client.should_receive(:upload_csv_by_path).with("#{Rails.root}/tmp/scalar_test_exporter.csv", nil, expires: current_time + 1.day)

Resources