How to make ember work with Django REST gis - ember-data

I am currently trying to setup ember to interact with Django's REST Framework using the ember-django-adapter.
This works flawless. But since I started using djangorestframework-gis, ember is not able to process the responses anymore.
I have not found anyone building geoJSON with ember except for: https://gist.github.com/cspanring/5114078 But that does not seem to be the right approach because I do not want to change the data model?
This is the api-response:
{
"type": "FeatureCollection",
"features": [
{
"id": 1,
"type": "Feature",
"geometry": {
"coordinates": [
9.84375,
53.665466308594
],
"type": "Point"
},
"properties": {
"date_created": "2014-10-05T20:08:43.565Z",
"body": "Hi",
"author": 1,
"expired": false,
"anonymous": false,
"input_device": 1,
"image": "",
"lat": 0.0,
"lng": 0.0
}
}
]
}
While ember expects something like:
[{"id":1,
"date_created":"2014-10-05T20:08:43.565Z",
"body":"Hi",
"author":1,
"expired":false,
"anonymous":false,
"input_device":1,
"image":"",
"lat":0,
"lng":0
}
]
My take on this was to write my own Serializer:
import Ember from "ember";
import DS from "ember-data";
export default DS.DjangoRESTSerializer.extend({
extractArray: function(store, type, payload) {
console.log(payload);
//console.log(JSON.stringify(payload));
var features = payload["features"];
var nPayload = [];
for (var i = features.length - 1; i >= 0; i--) {
var message = features[i];
var nmessage = {"id": message.id};
for(var entry in message.properties){
var props = message.properties;
if (message.properties.hasOwnProperty(entry)) {
var obj = {}
nmessage[entry]=props[entry];
}
}
nPayload.push(nmessage);
};
console.log(nPayload); //prints in the format above
this._super(store, type, nPayload);
},
})
But I receive the following error:
The response from a findAll must be an Array, not undefined
What am I missing here? Or is this the wrong approach? Has anyone ever tried to get this to work?
An alternative would be to handle this on the serverside and simply output a regular restframework response and set lat and long in the backend.

This is not a valid answer for the question above. I wanted to share my solution anyways,
just in case anyone ever gets into the same situation:
I now do not return a valid geoJSON, but custom lat, lng values. The following is backend code for django-rest-framework:
Model:
#models/message.py
class Message(models.Model):
def lat(self):
return self.location.coords[1]
def lng(self):
return self.location.coords[0]
And in the serializer:
#message/serializer.py
class MessageSerializer(serializers.ModelSerializer):
lat = serializers.Field(source="lat")
lng = serializers.Field(source="lng")
Ember can easily handle the format.

Related

Mimic the ( Show All ) link in datatables.net

I have a situation where I want to get the full (data) from the backend as a CSV file. I have already prepared the backend for that, but normally the front-end state => (filters) is not in contact with the backend unless I send a request, so I managed to solve the problem by mimicking the process of showing all data but by a custom button and a GET request ( not an ajax request ). knowing that I am using serverSide: true in datatables.
I prepared the backend to receive a request like ( Show All ) but I want that link to be sent by custom button ( Export All ) not by the show process itself as by the picture down because showing all data is not practical at all.
This is the code for the custom button
{
text: "Export All",
action: function (e, dt, node, config) {
// get the backend file here
},
},
So, How could I send a request like the same request sent by ( Show All ) by a custom button, I prepared the server to respond by the CSV file. but I need a way to get the same link to send a get request ( not by ajax ) by the same link that Show All sends?
If you are using serverSide: true that should mean you have too much data to use the default (serverSide: false) - because the browser/DataTables cannot handle the volume. For this reason I would say you should also not try to use the browser to generate a full export - it's going to be too much data (otherwise, why did you choose to use serverSide: true?).
Instead, use a server-side export utility - not DataTables.
But if you still want to pursuse this approach, you can build a custom button which downloads the entire data set to the DataTables (in your browser) and then exports that complete data to Excel.
Full Disclosure:
The following approach is inspired by the following DataTables forum post:
Customizing the data from export buttons
The following approach requires you to have a separate REST endpoint which delivers the entire data set as a JSON response (by contrast, the standard response should only be one page of data for the actual table data display and pagination.)
How you set up this endpoint is up to you (in Laravel, in your case).
Step 1: Create a custom button:
I tested with Excel, but you can do CSV, if you prefer.
buttons: [
{
extend: 'excelHtml5', // or 'csvHtml5'
text: 'All Data to Excel', // or CSV if you prefer
exportOptions: {
customizeData: function (d) {
var exportBody = getDataToExport();
d.body.length = 0;
d.body.push.apply(d.body, exportBody);
}
}
}
],
Step 2: The export function, used by the above button:
function GetDataToExport() {
var jsonResult = $.ajax({
url: '[your_GET_EVERYTHING_url_goes_here]',
success: function (result) {},
async: false
});
var exportBody = jsonResult.responseJSON.data;
return exportBody.map(function (el) {
return Object.keys(el).map(function (key) {
return el[key]
});
});
}
In the above code, my assumption is that the JSON response has the standard DataTables object structure - so, something like:
{
"data": [
{
"id": "1",
"name": "Tiger Nixon",
"position": "System Architect",
"salary": "$320,800",
"start_date": "2011/04/25",
"office": "Edinburgh",
"extn": "5421"
},
{
"id": "2",
"name": "Garrett Winters",
"position": "Accountant",
"salary": "$170,750",
"start_date": "2011/07/25",
"office": "Tokyo",
"extn": "8422"
},
{
"id": "3",
"name": "Ashton Cox",
"position": "Junior Technical Author",
"salary": "$86,000",
"start_date": "2009/01/12",
"office": "San Francisco",
"extn": "1562"
}
]
}
So, it's an object, containing a data array.
The DataTables customizeData function is what controls writing this complete JSON to the Excel file.
Overall, your DataTables code will look something like this:
$(document).ready(function() {
$('#example').DataTable( {
serverSide: true,
dom: 'Brftip',
buttons: [
{
extend: 'excelHtml5',
text: 'All Data to Excel',
exportOptions: {
customizeData: function (d) {
var exportBody = GetDataToExport();
d.body.length = 0;
d.body.push.apply(d.body, exportBody);
}
}
}
],
ajax: {
url: "[your_SINGLE_PAGE_url_goes_here]"
},
"columns": [
{ "title": "ID", "data": "id" },
{ "title": "Name", "data": "name" },
{ "title": "Position", "data": "position" },
{ "title": "Salary", "data": "salary" },
{ "title": "Start Date", "data": "start_date" },
{ "title": "Office", "data": "office" },
{ "title": "Extn.", "data": "extn" }
]
} );
} );
function GetDataToExport() {
var jsonResult = $.ajax({
url: '[your_GET_EVERYTHING_url_goes_here]',
success: function (result) {},
async: false
});
var exportBody = jsonResult.responseJSON.data;
return exportBody.map(function (el) {
return Object.keys(el).map(function (key) {
return el[key]
});
});
}
Just to repeat my initial warning: This is probably a bad idea, if you really needed to use serverSide: true because of the volume of data you have.
Use a server-side export tool instead - I'm sure Laravel/PHP has good support for generating Excel files.

SQL Server stored procedure in .NET Core 6 Web API to produce JSON data used in Angular app

I have a SQL Server stored procedure that has an ID parameter and returns a string in JSON format that is needed in the Angular app.
Here is a sample of the JSON needed:
[
{
"type": "date",
"name": "asofdate",
"ui":
{
"label": "As Of Date",
"placeholder": "Enter a date"
},
"validators": { "required": "true" }
},
{
"type": "select",
"name": "scope",
"ui": { "label": "Scope", "placeholder": "Select a scope" },
"validators": { "required": "true" },
"source": [
{ "value": 1, "text": "ABC" },
{ "value": 2, "text": "CDE" },
{ "value": 3, "text": "FGI" }
]
}
]
Here is a what the result of running the stored procedure looks like:
When I run the Web API passing the ID parameter to the stored procedure, I would like to capture the response as a JSON object to be used in the Angular app.
But the Web API is returning this:
[
{
"jsonResponse": "[
{
\"type\":\"date\",
\"name\":\"asofdate\",
\"ui\":{\"label\":\"As Of Date\",\"placeholder\":\"Enter a date\"},
\"validators\":{\"required\":\"true\"}
}
,
{
\"type\":\"select\",
\"name\":\"scope\",
\"ui\":{\"label\":\"Scope\",\"placeholder\":\"Select a scope\"},
\"validators\":{\"required\":\"true\"},
\"source\":[{\"value\":1,\"text\":\"ABC\"},{\"value\":2,\"text\":\"DEF\"},{\"value\":3,\"text\":\"GHI\"}]}
}
]
Is there a way to get the JSON response from the Web API without all the "\" and without:
{
"jsonResponse": "
so that it matches the sample above?
Here is the code from the Web API:
[HttpGet("{ReportID}")]
public async Task<ActionResult<IEnumerable<usp_ReportParameterResult>>> GetReportParameters(int ReportID)
{
if (_context.usp_ReportParameterAsync == null)
{
return NotFound();
}
var op = new OutputParameter<int>();
var JSONresponse = await _context.usp_ReportParameterAsync(ReportID, op);
if (JSONresponse == null)
{
return NotFound();
}
return JSONresponse;
}
The stored procedure uses JSON_QUERY and JSON PATH to create the needed nested arrays.
So, in the angular code I have the following hard-coded:
TESTDATA:any[] = [
{
type:'text',
name:'firstName',
validators:{
required:true
},
ui:{label:'First Name',placeholder:'Enter Your First Name'}
}
,
{
"type":"date",
"name":"asofdate",
"ui":{"label":"****As Of Date","placeholder":"Enter a date","class":["date-picker-wrapper"]},
"validators":{"required":"true"}
}
]
What I need is instead of this data being hrad-coded it is being dynamically generated from a Web API.
The hard-coded data looks like the following from browser debug:
[![enter image description here][2]][2]
From the web api data looks like the following:
It is not an array like the TESTDATA. Is the a way to get response from web api into an array format as required?
Actually, easiest solution was to remove the backlashes in the Angular app by simply doing the following:
for (let item of this.formattedJSON) {
item.ui = JSON.parse(item.ui);
item.validators = JSON.parse(item.validators);
}

How can I pass the Session ID in API Request via Apps Script?

I am trying to access the API of our CRM Documentation through Google Sheets / Apps Script.
When accessing the API through Postman I have no issues and get the desired results using the following setup:
POST: https://api.sharpspring.com/pubapi/v1.2/?accountID={{accountID}}&secretKey={{secretKey}}
BODY:
{
"id":"12345678912345678999",
"method": "getOpportunities",
"params": {
"where": {},
"limit":"500",
"offset": "0"
}
}
Now, when I try to replicate the same in Apps Script I get the following result:
{ result: null,
error: { code: 102, message: 'Header missing request ID', data: [] },
id: null }
The function that I am running is as below:
function myFunction() {
var URL = "https://api.sharpspring.com/pubapi/v1.2/?accountID={{accountID}}&secretKey={{secretKey}}"
var body = {
"method": "POST",
"body": raw,
"headers": {"Content-Type": "application/json"},
"redirect": "follow"
}
var raw = {
"method": "getOpportunities",
"id": "12345678912345678999",
"params": {
"where": {},
"limit":"500",
"offset": "0"
}
}
var results = UrlFetchApp.fetch(URL, body).getContentText();
var data = JSON.parse(results);
console.log(data);
}
In both I am passing a random session ID "12345678912345678999". I tried finding a session ID in the cookie but that didn't work and I assume that I am on the wrong path there. Passing the id in the header directly didn't work either.
Any ideas? Thanks a lot in advance!

Modify data using AJV for Json Schema

I'm using AJV (Another Json schema validator) on NodeJs.
I've the following schema
var schema = {
"$id": "testSchema.json",
"type": "object",
"$schema": "http://json-schema.org/draft-06/schema#",
"additionalProperties": false,
"properties": {
"userId": {
"type": "integer"
},
"userName": {
"type": "string"
},
"uniqueID": {
"type": "integer"
}
}
}
I need to overwrite unqiueID property by a value that I could somehow pass to Json schema or AJV.
I think the above can be done using AJV addKeyword method, tried using it but failed because I don't know how to manipulate (and return) data value from AJV custom keywords.
Is possible to modify data with AJV ? or are there any other possible ways to do it??
Thank you!
You can create a custom keyword with function that will do whatever your want to data.
var Ajv = require('ajv');
var ajv = new Ajv({allErrors: true});
ajv.addKeyword('my_id_rewrite', {
type: 'object',
compile: function (sch, parentSchema) {
return function (data) {
console.log(data)
data['my_id']=parentSchema.my_id_rewrite;
return true;
}
}
});
var schema = { "my_id_rewrite": 2 };
var validate = ajv.compile(schema);
o = {"my_id":1}
console.log(validate(o)); // true
console.log(o); // Object {my_id: 2}
https://runkit.com/embed/cxg0vwqazre3

How do you get all the email body parts? And how do you know how many parts exist?

I'm trying to read emails responded by the Gmail API.
I have trouble accessing all the "parts". And don't have great ways to traverse through the response. I'm also lost as to how many parts can exist so that I can make sure I read the different email responses properly. I've shortened the response below...
{ "payload": { "mimeType": "multipart/mixed", "filename": "",
], "body": { "size": 0 }, "parts": [ {
"body": {
"size": 0
},
"parts": [
{
"partId": "0.0",
"mimeType": "text/plain",
"filename": "",
"headers": [
{
"name": "Content-Type",
"value": "text/plain; charset=\"us-ascii\""
},
{
"name": "Content-Transfer-Encoding",
"value": "quoted-printable"
}
],
"body": {
"size": 2317,
"data": "RGVhciBNSVQgQ2x1YiBWb2x1bnRlZXJzIGluIEFzaWEsDQoNCkJ5IG5vdyBlYWNoIG9mIHlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBpbnZpdGF0aW9ucyB0byB0aGUgcmVjZXB0aW9ucyBpbiBib3RoIFNpbmdhcG9yZSBhbmQgSG9uZyBLb25nIHdpdGggUHJlc2lkZW50IFJlaWYgb24gTm92ZW1iZXIgNyBhbmQgTm92ZW1iZXIg"
}
},
{
"partId": "0.1",
"mimeType": "text/html",
"filename": "",
"headers": [
{
"name": "Content-Type",
"value": "text/html; charset=\"us-ascii\""
},
{
"name": "Content-Transfer-Encoding",
"value": "quoted-printable"
}
],
"body": {
"size": 9116,
"data": "PGh0bWwgeG1sbnM6dj0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp2bWwiIHhtbG5zOm89InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206b2ZmaWNlOm9mZmljZSIgeG1sbnM6dz0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTpvZmZpY2U6d29yZCIgeG1sbnM6bT0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS9vZmZpY2UvMjA"
}
}
] }, {
"partId": "1",
"mimeType": "text/plain",
"filename": "",
"body": {
"size": 411,
"data": "X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NClRoYW5rIHlvdSBmb3IgYWxsb3dpbmcgdXMgdG8gcmVhY2ggeW91IGJ5IGVtYWlsLCB0aGUgbW9zdCBpbW1lZGlhdGUgbWVhbnMgZm9yIHNoYXJpbmcgaW5mb3JtYXRpb24gd2l0aCBNSVQgYWx1bW5pLiANCklmIHlvdSB3b3VsZCBsaWtlIHRvIHVuc3Vic2NyaWJlIGZyb20gdGhpcyBtYWlsaW5nIGxpc3Qgc2VuZCBhIGJsYW5rIGVtYWlsIHRvIGxpc3RfdW5zdWJzY3JpYmVAYWx1bS5taXQuZWR1IGFuZCBwdXQgdGhlIGxpc3QgbmFtZSBpbiB0aGUgc3ViamVjdCBsaW5lLg0KRm9yIGV4YW1wbGU6DQpUbzogbGlzdF91bnN1YnNjcmliZUBhbHVtLm1pdC5lZHUNCkNjOg0KU3ViamVjdDogYXNpYW9mZg0K"
} } ] } }
Is there something I'm missing?
A MIME message is not just an array it's a full blown tree structure. So you'll have to traverse it to correctly handle it. Luckily JSON parsers are plentiful and the problem can easily be handled with recursion. In many languages there exist very useful email parsing libraries that can make accessing traditional parts (e.g. the text/plain or text/html displayable part, or attachments) not too laborious.
You'll have to set up walker functions to traverse through the json and pick out the bits you are after. Here is a part of what I wrote. This may help you jumpstart your code. NOTE: this is used inside of wordpress...hence the special jQuery call. Not needed if you do not need to use jquery inside wordpress.
function makeApiCall() {
gapi.client.load('gmail', 'v1', function() {
//console.log('inside call: '+myquery);
var request = gapi.client.gmail.users.messages.list({
'userId': 'me',
'q': myquery
});
request.execute(function(resp) {
jQuery(document).ready(function($) {
//console.log(resp);
//$('.ASAP-emailhouse').height(300);
$.each(resp.messages, function(index, value){
messageId = value.id;
var messagerequest = gapi.client.gmail.users.messages.get({
'userId': 'me',
'id': messageId
});//end var message request
messagerequest.execute(function(messageresp) {
//console.log(messageresp);
$.each(messageresp, responsewalker);
function responsewalker(key, response){
messagedeets={};
$.each(messageresp.payload.headers, headerwalker);
function headerwalker(headerkey, header){
if(header.name =='Date'){
d = new Date(header.value);
var curr_date = d.getDate();
var curr_month = d.getMonth() + 1; //Months are zero based
var curr_year = d.getFullYear();
var formatteddate = curr_month+'/'+curr_date+'/'+curr_year;
messagedeets['date']=formatteddate;
//$('.ASAP-emailhouse').append('<p>'+header.value+'</p>');
}
if(header.name =='Subject'){
//console.log(header.value);
messagedeets.subject=header.value;
}
}
messagedeets.body = {};
$.each(messageresp.payload.parts, walker);
function walker(partskey, value) {
//console.log(value.body);
if (value.body.data !== "undefined") {
//console.log(value.body);
var messagebody = atob(value.body.data);
messagedeets.body.partskey = messagebody;
}
console.log(messagedeets);
$('.ASAP-emailhouse').append('<div class="messagedeets"><p class="message-date">'+messagedeets.date+': <span class="message-subject">'+messagedeets.subject+'</span></p><p>'+messagedeets.body.partskey+'</p></div>');
}//end responsewalker
//$('.ASAP-emailhouse').append('</li>');
}
//$('.ASAP-emailhouse').append('</ul>');
});//end message request
});//end each message id
});//end jquery wrapper for wordpress
});//end request execute list messages
});//end gapi client load gmail
}
The MIME parts you are looking for are in an array. JSON does not tell you up front how many items are in an array. Even MIME itself does not provide a way of knowing how many parts are present without looking at the entire message. You will just have to traverse the entire array to know how many parts are in it, and process each part as you encounter it.
To know how much parts exists, you can just use the Length property.
Example :
json.payload.parts.length
For your example, this property is 2 because there are 2 parts.