I am attempting to implement the Revit to Excel exporter discussed here. The button is working and passing urn and token to
ForgeXLS.downloadXLSX(urn, token, callback /*Optional*/);
I receive an error" "GET " 403 (forbidden)"
I am extending the Extensions Skeleton tutorial found here.
Is it possible that there is an issue with the scopes... if so can you guide me as to how to adjust the scope of the access token I am pulling?
Code for ForgeXLSX.downloadXLSX is:
downloadXLSX: function (urn, token, status) {
var fileName = decodeURIComponent(atob(urn).replace(/^.*[\\\/]/, '')) + '.xlsx';
if (fileName.indexOf('.rvt') == -1) {
if (status) status(true, 'Not a Revit file, aborting.');
return;
}
if (status) {
status(false, 'Preparing ' + fileName);
status(false, 'Reading project information....');
}
this.prepareTables(urn, token, function (tables) {
if (status) status(false, 'Building XLSX file...');
var wb = new Workbook();
jQuery.each(tables, function (name, table) {
if (name.indexOf('<')==-1) { // skip tables starting with <
var ws = ForgeXLS.sheetFromTable(table);
wb.SheetNames.push(name);
wb.Sheets[name] = ws;
}
});
var wbout = XLSX.write(wb, {bookType: 'xlsx', bookSST: true, type: 'binary'});
saveAs(new Blob([s2ab(wbout)], {type: "application/octet-stream"}), fileName);
if (status) status(true, 'Downloading...');
})
},
Scope wise, you will need both data:read bucket:read to have sufficient access to model metadata:
Token with insufficient scope ends up with a 403:
Make sure your server sets scope up properly in the request body to fetch access tokens.
And your best bet to observe the URN and Token variables in the process of calling the Forge endpoints is here at ForgeXLS.forgeGetRequest:
After digging around a bit (and some help from a friend) figured out that it was the scopes after all. Adding 'data:read' scope to the public scope in the config.js file provided the needed access and the exporter now works.
scopes: {
// Required scopes for the server-side application
internal: ['bucket:create', 'bucket:read', 'data:read', 'data:create', 'data:write'],
// Required scope for the client-side viewer
public: ['viewables:read', 'data:read']
}
Related
Is it possible or there is any way to load Model through URN instead of URL.
we can load the model through URL :
this.viewer.loadModel(url, options) -> Here i know the url of the SVF
Is there any possibility to load the model using the URN, But in my case I know only URN of the svf.
In regular way,
We are loading the document using the URN of the uploaded file, on Document load success then we are loading the viewables.
var documentId = 'urn:dXJuOmFkc2sub2JqZ3Q6cGxuLW1vZGVN0L0NhZGFjR3JvdXBIUSUyMDIwMTkucnZ0';
Autodesk.Viewing.Initializer(options, function onInitialized(){
viewerApp = new Autodesk.Viewing.ViewingApplication('MyViewerDiv');
viewerApp.registerViewer(viewerApp.k3D, Autodesk.Viewing.Private.GuiViewer3D);
viewerApp.loadDocument(documentId, onDocumentLoadSuccess, onDocumentLoadFailure);
});
function onDocumentLoadSuccess(doc) {
var viewables = viewerApp.bubble.search({type:'geometry', role:'3d',name:'blahblah'});
if (viewables.length === 0) {
console.error('Document contains no viewables.');
return;
}
// Choose any of the avialble viewables
console.log(viewables[0].data);
console.log(doc.getViewablePath(viewables[0].data));
viewerApp.selectItem(viewables[0].data, onItemLoadSuccess, onItemLoadFail);
}
From above code, based on the URN of the uploaded OBJ, it is getting the manifest and loading the viewable, But In our scenario, we are doing that part at server side and getting the URN of the SVF.
But in our scenario, We have the URN of the SVF file. Is there any way to load the Model Using SVF URN.
I saw one possiblity is that appending
"https://developer.api.autodesk.com/derivativeservice/v2/derivatives/"
to my urn and calling the
viewer.loadModel(url)
Is loading the Model, But it is again a maintenance work, When there is a change in that URL from forge side we need to update it again.
Is there anyway from javascript to get the path of the model based on the URN?
To load by URN of the SVF simply pass in its, with the rest of your Viewer's environment kept the same as you would for URN of the document:
// get the URN of the SVF from the manifest, e.g. `urn%3Aadsk.viewing%3Afs.file%3AdXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6c2JzYjIzMzMzL3NiYmJiYmIuZHdn%2Foutput%2F3a65ae5a-804e-b91b-11d1-5bc44f41866f_f2d%2F3d.svf`
Autodesk.Viewing.Initializer({
'env' : 'AutodeskProduction', getAccessToken: onGetAccessToken
}, function onInitialized(){
//...
viewer.start();
viewer.loadModel('https://developer.api.autodesk.com/derivativeservice/v2/derivatives/urn%3Aadsk.viewing%3Afs.file%3AdXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6c2JzYjIzMzMzL3NiYmJiYmIuZHdn%2Foutput%2F3a65ae5a-804e-b91b-11d1-5bc44f41866f_f2d%2F3d.svf')
});
BTW the viewerApplication API has been deprecated as of v7 so I'd recommend to follow this migration guide here to upgrade to v7 in order to get all those new features and fixes ...
I upgraded the forge viewer version of my solution to 6.* to utilize the latest released feature "Document browser extension" as it mentions here
This extension doesn't appear for me, please help.
I got it to work after some experimenting.
Here is my workflow in case you still need it.
First, initialize the viewer:
// initialize the viewer
Autodesk.Viewing.Initializer(adOptions, () => {
// when initialized, call loading function
this.loadDocument(encodedUrn);
});
Then, load your document in the function called above:
// load the document from the urn
Autodesk.Viewing.Document.load(
encodedUrn,
this.onDocumentLoadSuccess,
this.onDocumentLoadFailure,
);
In the success callback you can now do the following:
onDocumentLoadSuccess(doc) {
// get the geometries of the document
const geometries = doc.getRoot().search({ type: 'geometry' });
// Choose any of the available geometries
const initGeom = geometries[0];
// and prepare config for the viewer application
const config = {
extensions: ['Autodesk.DocumentBrowser'],
};
// create the viewer application and bind the reference of the viewerContainer to 'this.viewer'
this.viewer = new Autodesk.Viewing.Private.GuiViewer3D(
this.viewerContainer,
config,
);
// start the viewer
this.viewer.start();
// load a node in the fetched document
this.viewer.loadDocumentNode(doc.getRoot().lmvDocument, initGeom);
}
I hope this will make it work for you as well. What helped me was the reference to the loadDocumentNode function in this blog post.
I have a public (anyone with the link can view) file on my Google Drive and I want to use the content of it in my Android app.
From what I could gather so far, I need the fileID, the OAuth token and the client ID - these I already got. But I can't figure out what is the exact methodology of authorising the app or fetching the file.
EDIT:
Simply reading it using file.readAsLines didn't work:
final file = new File(dogListTxt);
Future<List<String>> dogLinks = file.readAsLines();
return dogLinks;
The dogLinks variable isn't filled with any data, but I get no error messages.
The other method I tried was following this example but this is a web based application with explicit authorization request (and for some reason I was never able to import the dart:html library).
The best solution would be if it could be done seamlessly, as I would store the content in a List at the application launch, and re-read on manual refresh button press.
I found several old solutions here, but the methods described in those doesn't seem to work anymore (from 4-5 years ago).
Is there a good step-by-step tutorial about integrating the Drive API in a flutter application written in dart?
I had quite a bit of trouble with this, it seems much harder than it should be. Also this is for TXT files only. You need to use files.export() for other files.
First you need to get a list fo files.
ga.FileList textFileList = await drive.files.list(q: "'root' in parents");
Then you need to get those files based on ID (This is for TXT Files)
ga.Media response = await drive.files.get(filedId, downloadOptions: ga.DownloadOptions.FullMedia);
Next is the messy part, you need to convert your Media object stream into a File and then read the text from it. ( #Google, please make this easier.)
List<int> dataStore = [];
response.stream.listen((data) {
print("DataReceived: ${data.length}");
dataStore.insertAll(dataStore.length, data);
}, onDone: () async {
Directory tempDir = await getTemporaryDirectory(); //Get temp folder using Path Provider
String tempPath = tempDir.path; //Get path to that location
File file = File('$tempPath/test'); //Create a dummy file
await file.writeAsBytes(dataStore); //Write to that file from the datastore you created from the Media stream
String content = file.readAsStringSync(); // Read String from the file
print(content); //Finally you have your text
print("Task Done");
}, onError: (error) {
print("Some Error");
});
There currently is no good step-by-step tutorial, but using https://developers.google.com/drive/api/v3/manage-downloads as a reference guide for what methods to use in Dart/Flutter via https://pub.dev/packages/googleapis: to download or read the contents of a Google Drive file, you should be using googleapis/Drive v3, or specifically, the methods from the FilesResourceApi class.
drive.files.export(), if this is a Google document
/// Exports a Google Doc to the requested MIME type and returns the exported content. Please note that the exported content is limited to 10MB.
drive.files.get(), if this something else, a non-Gdoc file
/// Gets a file's metadata or content by ID.
Simplified example:
var drive = new DriveApi(http_client);
drive.files.get(fileId).then((file) {
// returns file
});
However, what I discovered was that this Dart-GoogleAPIs library seemed to be missing a method equivalent to executeMediaAndDownloadTo(outputStream). In the original Google Drive API v3, this method adds the alt=media URL parameter to the underlying HTTP request. Otherwise, you'll get the error, which is what I saw:
403, message: Export requires alt=media to download the exported
content.
And I wasn't able to find another way to insert that URL parameter into the current request (maybe someone else knows?). So as an alternative, you'll have to resort to implementing your own Dart API to do the same thing, as hinted by what this OP did over here https://github.com/dart-lang/googleapis/issues/78: CustomDriveApi
So you'll either:
do it through Dart with your own HttpClient implementation and try to closely follow the REST flow from Dart-GoogleAPIs, but remembering to include the alt=media
or implement and integrate your own native-Android/iOS code and use the original SDK's convenient executeMediaAndDownloadTo(outputStream)
(note, I didn't test googleapis/Drive v2, but a quick examination of the same methods looks like they are missing the same thing)
I wrote this function to get file content of a file using its file id. This is the simplest method I found to do it.
Future<String> _getFileContent(String fileId) async {
var response = await driveApi.files.get(fileId, downloadOptions: DownloadOptions.fullMedia);
if (response is! Media) throw Exception("invalid response");
return await utf8.decodeStream(response.stream);
}
Example usage:
// save file to app data folder with 150 "hello world"s
var content = utf8.encode("hello world" * 150);
driveApi.files
.create(File(name: fileName, parents: [appDataFolder]),
uploadMedia: Media(Stream.value(content), content.length))
.then((value) {
Log().i("finished uploading file ${value.id}");
var id = value.id;
if (id != null) {
// after successful upload, read the recently uploaded file content
_getFileContent(id).then((value) => Log().i("got content is $value"));
}
});
I'm struggling for a couple of days. Question is simple, is there a way that can I create a server on Raspberry PI that will return current status of GPIO ports in JSON format?
Example:
Http://192.168.1.109:3000/led
{
"Name": "green led",
"Status": "on"
}
I found Adafruit gpio-stream library useful but don't know how to send data to JSON format.
Thank you
There are a variety of libraries for gpio interaction for node.js. One issue is that you might need to run it as root to have access to gpio, unless you can adjust the read access for those devices. This is supposed to be fixed in the latest version of rasbian though.
I recently built a node.js application that was triggered from a motion sensor, in order to activate the screen (and deactivate it after a period of time). I tried various gpio libraries but the one that I ended up using was "onoff" https://www.npmjs.com/package/onoff mainly because it seemed to use an appropriate way to identify changes on the GPIO pins (using interrupts).
Now, you say that you want to send data, but you don't specify how that is supposed to happen. If we use the example that you want to send data using a POST request via HTTP, and send the JSON as body, that would mean that you would initialize the GPIO pins that you have connected, and then attach event handlers for them (to listen for changes).
Upon a change, you would invoke the http request and serialize the JSON from a javascript object (there are libraries that would take care of this as well). You would need to keep a name reference yourself since you only address the GPIO pins by number.
Example:
var GPIO = require('onoff').Gpio;
var request = require('request');
var x = new GPIO(4, 'in', 'both');
function exit() {
x.unexport();
}
x.watch(function (err, value) {
if (err) {
console.error(err);
return;
}
request({
uri: 'http://example.org/',
method: 'POST',
json: true,
body: { x: value } // This is the actual JSON data that you are sending
}, function () {
// this is the callback from when the request is finished
});
});
process.on('SIGINT', exit);
I'm using the npm modules onoff and request. request is used for simplifying the JSON serialization over a http request.
As you can see, I only set up one GPIO here. If you need to track multiple, you must make sure to initialize them all, distinguish them with some sort of name and also remember to unexport them in the exit callback. Not sure what happens if you don't do it, but you might lock it for other processes.
Thank You, this was very helpful. I did not express myself well, sorry for that. I don't want to send data (for now) i just want to enter web address like 192.168.1.109/led and receive json response. This is what I manage to do for now. I don't know if this is the right way. PLS can you review this or suggest better method..
var http = require('http');
var url = require('url');
var Gpio = require('onoff').Gpio;
var led = new Gpio(23, 'out');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
var command = url.parse(req.url).pathname.slice(1);
switch(command) {
case "on":
//led.writeSync(1);
var x = led.readSync();
res.write(JSON.stringify({ msgId: x }));
//res.end("It's ON");
res.end();
break;
case "off":
led.writeSync(0);
res.end("It's OFF");
break;
default:
res.end('Hello? yes, this is pi!');
}
}).listen(8080);
Google Universal Analytics has a hit type of exception
ga('send', 'exception', {
'exDescription': 'DatabaseError'
});
I was expecting to be able to just go to the Google Analytics console and find an exeption report at the same level as 'events' however it's nowhere to be seen.
The Android and iOS APIs say Crash and exception data is available primarily in the Crash and Exceptions report but I can't find any report by that name.
Figured it out. I'm not sure why they don't make this a built in report but maybe someday.
I made a custom widget in a dashboard with Exception Description for dimension and 'Crashes' for the metric:
Which gives me a report like this:
You can also go to Customization tab and create a custom report to give you a table of errors, and then add it to your dashboard.
Used with this global exception handler
if (typeof window.onerror == "object")
{
window.onerror = function (err, url, line)
{
if (ga)
{
ga('send', 'exception', {
'exDescription': line + " " + err
});
}
};
}
You can put this handler anywhere in the initialization of your Javascript - which will depend upon how you have all your JS files configured. Alternatively you can just put it inside a <script> tag near the top of your html body tag.
I took Simon_Weaver's guide to making a custom report a few steps further and built out a fairly complete Google Analytics custom exceptions report. I figured it might be worth sharing, so I uploaded it to the GA "Solutions Gallery".
My template: Google Analytics Exceptions Report
Here's a picture of the end result:
I just wanted to expand a bit on #Simon_Weaver 's excellent answer to provide error reports with a few additional details:
Make sure ga() is defined before trying to call it (as an Error could be triggered before the Analytics library is loaded).
Log Exception line numbers and column index in the Analytics Reports (although minified JavaScript code used in production might be difficult to read).
Execute any previously-defined window.onerror callback.
/**
* Send JavaScript error information to Google Analytics.
*
* #param {Window} window A reference to the "window".
* #return {void}
* #author Philippe Sawicki <https://github.com/philsawicki>
*/
(function (window) {
// Retain a reference to the previous global error handler, in case it has been set:
var originalWindowErrorCallback = window.onerror;
/**
* Log any script error to Google Analytics.
*
* Third-party scripts without CORS will only provide "Script Error." as an error message.
*
* #param {String} errorMessage Error message.
* #param {String} url URL where error was raised.
* #param {Number} lineNumber Line number where error was raised.
* #param {Number|undefined} columnNumber Column number for the line where the error occurred.
* #param {Object|undefined} errorObject Error Object.
* #return {Boolean} When the function returns true, this prevents the
* firing of the default event handler.
*/
window.onerror = function customErrorHandler (errorMessage, url, lineNumber, columnNumber, errorObject) {
// Send error details to Google Analytics, if the library is already available:
if (typeof ga === 'function') {
// In case the "errorObject" is available, use its data, else fallback
// on the default "errorMessage" provided:
var exceptionDescription = errorMessage;
if (typeof errorObject !== 'undefined' && typeof errorObject.message !== 'undefined') {
exceptionDescription = errorObject.message;
}
// Format the message to log to Analytics (might also use "errorObject.stack" if defined):
exceptionDescription += ' # ' + url + ':' + lineNumber + ':' + columnNumber;
ga('send', 'exception', {
'exDescription': exceptionDescription,
'exFatal': false, // Some Error types might be considered as fatal.
'appName': 'Application_Name',
'appVersion': '1.0'
});
}
// If the previous "window.onerror" callback can be called, pass it the data:
if (typeof originalWindowErrorCallback === 'function') {
return originalWindowErrorCallback(errorMessage, url, lineNumber, columnNumber, errorObject);
}
// Otherwise, Let the default handler run:
return false;
};
})(window);
// Generate an error, for demonstration purposes:
//throw new Error('Crash!');
Edit: As #Simon_Weaver duly noted, Google Analytics now has documentation about Exception Tracking (which I should have linked to in my original answer -- sorry, rookie mistake!):
https://developers.google.com/analytics/devguides/collection/analyticsjs/exceptions
https://developers.google.com/analytics/devguides/collection/analyticsjs/field-reference#exception
This is what I came up with so you don't need to include the code everywhere. Just add new ErrorHandler(); to each .js file. This was done for a Chrome Extension, but should work anywhere, I think. I implement the actual ga() stuff in a separate file (hence the app.GA), but you could bake it in here too.
/*
* Copyright (c) 2015-2017, Michael A. Updike All rights reserved.
* Licensed under the BSD-3-Clause
* https://opensource.org/licenses/BSD-3-Clause
* https://github.com/opus1269/photo-screen-saver/blob/master/LICENSE.md
*/
// noinspection ThisExpressionReferencesGlobalObjectJS
(function(window, factory) {
window.ExceptionHandler = factory(window);
}(this, function(window) {
'use strict';
return ExceptionHandler;
/**
* Log Exceptions with analytics. Include: new ExceptionHandler();<br />
* at top of every js file
* #constructor
* #alias ExceptionHandler
*/
function ExceptionHandler() {
if (typeof window.onerror === 'object') {
// global error handler
window.onerror = function(message, url, line, col, errObject) {
if (app && app.GA) {
let msg = message;
let stack = null;
if (errObject && errObject.message && errObject.stack) {
msg = errObject.message;
stack = errObject.stack;
}
app.GA.exception(msg, stack);
}
};
}
}
}));
You can now find a "Crashes and Exceptions" view under Behavior (if property is created as a "mobile app" in Google Analytics).