I have an file upload plugin (jQuery Fine Upload). With this plugin i upload images via AJAX, and from the response (JSON) generate preview images. This works fine in the major browsers, except all versions of Internet Explorer, because this sh... wants to open the JSON respone with .js extension. The event is fired when the file input will change. See the code below:
initFileuploader: function() {
$('#imageUploadWrapper').fineUploader({
request: {
uuidName: 'uploadId',
inputName: 'upload',
endpoint: '/admin/model/media/image/upload',
params: {
format: 'json'
}
},
// debug: true, // ##### !!!!! #####
autoUpload: true,
responseJSON: true,
deleteFile: {
enabled: true,
forceConfirm: true
}
}).on('complete', function(event, id, name, response) {
var elem = $('.qq-upload-list li')[id];
$(elem).prepend('<div class="previewContainer"></div>').addClass('cf');
$(elem)
.children('.previewContainer')
.append($('<img src="/admin/model/media/image/view/tmp/'+response.result[0].name+'" class="previewItem"/>'));
});
}
And this is the JSON response:
{
"success": true,
"version": "1.0",
"code": 200,
"result": [{
"name": "08390ab5-0c1d-4801-bef9-7bfd5d446776.jpg",
"type": "image\/pjpeg",
"error": 0,
"size": 845941
}],
"error": ""
}
As specified in the documentation, your response's Content-Type header MUST have a value of "text/plain". If your response's Content-Type is "application/json", as I presume yours is, you will run into the problem you are observing.
Related
The same server I use for my app can also serve up other pages. I would like to use link unfurling to add a card when any links to those pages are added to a message. My link unfurling works so long as the domain is something other than the app's server domain. When it is the same I can see in the debug output on my server that MS Teams tries to open the link.
After more testing I found that my handler does get called but the card is not inserted. If I start a new message and paste the URL in again the card does appear even though no call was made to my service.
My manifest looks like this:
{
"$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.5/MicrosoftTeams.schema.json",
"manifestVersion": "1.5",
"version": "1.25",
"id": "xxxxxxx-xxxxxxx-xxxxxxx-xxxxxxx-xxxxxxx",
"packageName": "xxxxxxx",
"developer": {
"name": "xx",
"websiteUrl": "https://www.xx.com",
"privacyUrl": "https://xxxx.com/en/privacy-policy/",
"termsOfUseUrl": "https://xxxx.com/en/terms-and-conditions/"
},
"name": {
"short": "xxxxxxx",
"full": "xxxxxxx"
},
"description": {
"short": "xxxxxxx",
"full": "xxxxxxx"
},
"icons": {
"outline": "xxxxxxx-outline.png",
"color": "xxxxxxx-color.png"
},
"accentColor": "#FFFFFF",
"composeExtensions": [
{
"botId": "xxxxxxx-xxxxxxx-xxxxxxx-xxxxxxx-xxxxxxx",
"canUpdateConfiguration": false,
"commands": [
],
"messageHandlers": [
{
"type": "link",
"value": {
"domains": [
"*.xxxxxxx.net",
"*.ngrok.io"
]
}
}
]
}
],
"validDomains": [
"*.xxxxxxx.net",
"*.ngrok.io"
]
}
This is my handler:
const { TeamsActivityHandler, CardFactory } = require('botbuilder');
class TeamsMessagingExtensionsActionBot extends TeamsActivityHandler {
handleTeamsAppBasedLinkQuery(context, query) {
console.log(`\nhandleTeamsAppBasedLinkQuery: ` + query.url);
var parts = query.url.split("/");
var sizeStr = parts[6].replace("-", " ");;
var dir = parts[7];
var file = parts[8];
var card = {
contentType: 'application/vnd.microsoft.card.hero',
content: {
title: 'File: ' + file,
subtitle:'Dir: ' + dir,
text: 'Size: '+ sizeStr
}
};
console.log(card);
const result = {
attachmentLayout: 'list',
type: 'result',
attachments: [card]
};
const response = {
composeExtension: result
};
return response;
}
}
module.exports.TeamsMessagingExtensionsActionBot = TeamsMessagingExtensionsActionBot;
I am using ngok while testing, is there any chance that it is caching things? I have seen some other strange behavior where Teams was unfurling links using a card that was already inserted and never calling my service, I know because the service was not even running.
I have found that if I run Teams in a browser the inspector shows the following errors:
Content Security Policy: Ignoring "'unsafe-inline'" within script-src or style-src: nonce-source or hash-source specified
GEThttps://eu-api.asm.skype.com/v1/objects/0-neu-d9-f79c02c35893b017803e3a0781c147c0/views/imgpsh_fullsize
[HTTP/1.1 200 OK 0ms]
Content Security Policy: Ignoring "'unsafe-inline'" within script-src or style-src: nonce-source or hash-source specified 2
Content Security Policy: Ignoring "'unsafe-inline'" within script-src or style-src: nonce-source or hash-source specified
[Bot invoke failed]: <BotError>Bot returned unsuccessful status code NotFound 3.2-app.min-0f0e437.js:4:1729883
postInvokeMessageWithUserInfo https://statics.teams.cdn.office.net/hashedjs/3.2-app.min-0f0e437.js:4
jQuery 4
f
g
$eval
$digest
$digest https://statics.teams.cdn.office.net/hashedjs/3.2-app.min-0f0e437.js:4
jQuery 4
$apply
m
x
onload
{…}
errorCode: 1008
errorMessage: "<BotError>Bot returned unsuccessful status code NotFound"
errorSubCode: undefined
headers: {…}
"cache-control": "no-store, must-revalidate, no-cache"
"content-length": "87"
"content-type": "application/json; charset=utf-8"
contextid: "tcid=965107910583198700,server=DB3PEPF000012A0,cv=ViFTxnq4MUSzogp8N8o9zg.1.0"
pragma: "no-cache"
"set-registrationtoken": "**redacted**"
request: XMLHttpRequest { readyState: 4, timeout: 0, withCredentials: false, … }
statusCode: 502
<prototype>: Object { … }
undefined 0-angular-jquery.min-eee9041.js:114:37
2020-06-16T21:13:53.449Z InputExtensionService: Input extension invoke command failed 0-angular-jquery.min-eee9041.js:114:37
e jQuery
logMessage https://statics.teams.cdn.office.net/hashedjs/3.2-app.min-0f0e437.js:4
error https://statics.teams.cdn.office.net/hashedjs/3.2-app.min-0f0e437.js:4
runCommand https://statics.teams.cdn.office.net/hashedjs/3.2-app.min-0f0e437.js:3
jQuery 4
f
g
$eval
$digest
$digest https://statics.teams.cdn.office.net/hashedjs/3.2-app.min-0f0e437.js:4
jQuery 4
$apply
m
x
onload
2020-06-16T21:14:43.904Z StorageUsage: Error ocrrured collecting storage usage numbers for the user. Error:navigator.webkitTemporaryStorage.queryUsageAndQuota 0-angular-jquery.min-eee9041.js:114:37
e jQuery
logMessage https://statics.teams.cdn.office.net/hashedjs/3.2-app.min-0f0e437.js:4
error https://statics.teams.cdn.office.net/hashedjs/3.2-app.min-0f0e437.js:4
startStorageUsageCollector https://statics.teams.cdn.office.net/hashedjs/3.2-app.min-0f0e437.js:4
_resolveFailures https://statics.teams.cdn.office.net/hashedjs/3.1-app.min-84b23e5.js:942
r https://statics.teams.cdn.office.net/hashedjs/3.1-app.min-84b23e5.js:942
_resolveFailures https://statics.teams.cdn.office.net/hashedjs/3.1-app.min-84b23e5.js:942
_resolveFailures https://statics.teams.cdn.office.net/hashedjs/3.1-app.min-84b23e5.js:942
_addCallbackSet https://statics.teams.cdn.office.net/hashedjs/3.1-app.min-84b23e5.js:942
then https://statics.teams.cdn.office.net/hashedjs/3.1-app.min-84b23e5.js:942
startStorageUsageCollector https://statics.teams.cdn.office.net/hashedjs/3.2-app.min-0f0e437.js:4
jQuery 3
n
e
c
The cause of all of this was that my free subscription had quietly expired and I had not noticed it. :(
Has anyone been able to use SendGrid templates with Parse Cloud Code?
This works, but only sends text, any ideas on how to use a template_id?
I tried with the filter but was not successful.
Parse.Cloud.define("sendEmail", function(request, response) {
// Import SendGrid module and call with your SendGrid API Key
var sg = require('sendgrid')('your SendGrid API key here');
// Create the SendGrid Request
var reqSG = sg.emptyRequest({
method: 'POST',
path: '/v3/mail/send',
body: {
personalizations: [
{
to: [
{
// This field is the "to" in the email
email: request.params.toEmail,
},
],
// This field is the "subject" in the email
subject: request.params.subject,
},
],
// This field contains the "from" information
from: {
email: 'info#youremail.com',
name: 'Your Name',
},
// This contains info about the "reply-to"
// Note that the "reply-to" may be different than the "from"
reply_to: {
email: 'info#youremail.com',
name: 'Your Name',
},
content: [
{
type: 'text/plain',
value: request.params.body,
},
],
},
});
sg.API(reqSG, function(SGerror, SGresponse) {
// Testing if some error occurred
if (SGerror) {
// Ops, something went wrong
console.error('Error response received');
console.error('StatusCode=' + SGresponse.statusCode);
console.error(JSON.stringify(SGresponse.body));
response.error('Error = ' + JSON.stringify(SGresponse.body));
}
else {
// Everything went fine
console.log('Email sent!');
response.success('Email sent!');
}
});
});
This is from the documentation on Back4App https://docs.back4app.com/docs/integrations/using-sendgrid-to-send-email/
If anyone is looking for the answer it turned out to be simple,
add the template_id as a personalization and change the message type the text/html,
template_id:"your template_id",
content: [
{
type: 'text/html',
// This field is the body of the email
value: "",
},
],
I am trying to make a basic GET call to an API using JSON API specifications with deeply nested relationship data. I'm experiencing an issue with axios or vue manipulating my data...
Paying attention to pickup and delivery relationships, the raw data looks like the following:
{
"data": {
"type": "parent",
"id": "34",
"attributes": {
// ...
},
"relationships": {
"r1": {
"data": [
{
"type": "nextparent",
"id": "62",
"attributes": {
// ..
},
"relationships": {
"pickup": {
"data": [
{
"type": "package",
"id": 521,
"attributes": {
// ...
}
},
// ...
]
},
"delivery": {
"data": []
}
}
},
// ...
]
}
}
}
}
... where pickup has an array of objects and delivery has an empty array. However, when I try to retrieve the response in the callback, delivery is an exact copy of pickup.
var promise = window.axios({
url: window.baseApi + '/my-object/34',
method: 'get'
})
promise.then(function (response) {
console.log(response)
})
Whenever you run console.log(response) in the callback, Vue's observers are applied to the response object, which makes me wonder if this is a Vue issue considering that only the relationships of the first r1 object experience this.
Screenshot of log from callback (incorrect):
Additionally, I checked the response from the axios transformResponse function and the raw json was correct (without observers). This is only happening in the callback.
Screenshot of log from transformResponse (correct):
Will update with fiddle, as soon as I can.
EDIT:
The axios function is being called in a vuex action. Here is the code:
fetchData ({commit, dispatch}) {
var promise = window.axios({
url: window.baseApi + '/my-object/34',
method: 'get'
})
promise
.then(function (response) {
console.log(response)
commit('toggleProgress', {key: 'fetchingData'})
commit('setActive', response.data.data)
dispatch('otherModule/setActiveShipments', response.data.data, {root: true})
dispatch('history/clear')
})
.catch(function () {
//
})
return promise
},
I am having an issue trying to use the addInitialFiles method listed here:
http://docs.fineuploader.com/branch/master/api/methods.html#addInitialFiles
I get a javascript error in my chrome dev console that says:
1032:381 Uncaught TypeError: uploader.addInitialFiles is not a function
This is the code I use to initialize Fine Uploader, and make the call the addInitialFiles():
<script type="text/javascript">
$(function () {
var uploader = $('#fine-uploader').fineUploaderS3({
request: {
endpoint: "myfineuploaderbucket.com.s3.amazonaws.com",
accessKey: "XXXXXXXXXXXXXXXXXXXXXXXX",
},
signature: {
endpoint: "/SignatureHandler",
version: 4
},
validation: {
allowedExtensions: ["gif", "jpeg", "jpg", "png", "bmp"],
acceptFiles: "image/gif, image/jpeg, image/png, image/bmp",
sizeLimit: 5000000,
itemLimit: 3
},
retry: {
enableAuto: true
},
deleteFile: {
enabled: true,
endpoint: "/DeleteImage/?id=#Model.Id",
method: 'POST',
},
paste: {
targetElement: $(document),
promptForName: true
},
uploadSuccess: {
endpoint: "/UploadSuccessful/?id=#Model.Id"
},
iframeSupport: { //This path needs to be a blank HTML page and is used for fine-uploader to support IE9 and older
localBlankPagePath: "/Blank"
},
objectProperties: {
acl: "public-read",
key: function (fileId) {
var re = /(?:\.([^.]+))?$/;
fileExt = re.exec($("#fine-uploader").fineUploader("getName", fileId))[0];
uuid = $("#fine-uploader").fineUploader("getUuid", fileId);
filename = uuid + fileExt;
key = "/#ViewBag.Id + "/" + filename;
return key;
}
},
scaling: {
hideScaled: true,
sizes: [
{ name: "small", maxSize: 350 },
{ name: "large", maxSize: 800 },
]
},
callbacks: {
onDelete: function (id) {
if (id == 2) {
$("#fine-uploader").fineUploader("deleteFile", 0);
$("#fine-uploader").fineUploader("deleteFile", 1);
}
},
},
});
uploader.addInitialFiles([
{
"name": "a3ef2360-881d-452c-a5f6-a173d5291066.jpg",
"uuid": "a3ef2360-881d-452c-a5f6-a173d5291066",
"size": "66000",
"thumbnailUrl": "https://s3.amazonaws.com/myfineuploaderbucket.com/1032/ecdca7bb-fb02-4072-b526-4e51cedb1f2b.jpg",
"s3Key": "1032/a3ef2360-881d-452c-a5f6-a173d5291066.jpg",
"s3Bucket": "myfineuploaderbucket.com"
}
]);
Is there something that I am doing wrong? Is addInitialFiles not a method, but an option that needs to be initialized when creating the Fine Uploader instance? I have tried adding "addInitialFiles" to the options of the Fine Uploader instance as well, and I do not receive a javascript error, but it does not load the initial file either.
I am using the latest version, 5.7.1.
Just like any other jQuery plug-in, the Fine Uploader jQuery wrapper returns a jQuery-wrapped element. This means that you are attempting to call an addInitialFiles method on a jQuery object. Of course, this method does not exist. If you really want to continue using the jQuery wrapper, you must change uploader.addInitialFiles(...) to uploader.fineUploaderS3('addInitialFiles', ...).
But you should know that you don't need jQuery for any of this, especially when using Fine Uploader. There is no benefit to using the jQuery wrapper with Fine Uploader, and you can fix your code simply by forgoing the wrapper (and saving a few bytes) and changing the first couple lines of your Fine Uploader initialization to:
var uploader = new qq.s3.FineUploader({
element: document.querySelector('#fine-uploader'),
...
})
Now, uploader.addInitialFiles works as you would expect.
I have looked over the doc and searched for forums but I can not seem to find an examples on how to implement the Initial File List functionality for fine-uploader.
Below is the script that I am using - works great but what I would like to do is to use the Initial File List function to populate the fineuploader with the existing files that have been uploaded during this session.
I have code that will return a json feed with the required files in an array format.
I just can ot figure out where our how to call the function to initalize.
Thanks in advance.
<script>
// Wait until the DOM is 'ready'
$(document).ready(function () {
$("#fine-uploader").fineUploader({
debug: true,
request: {
endpoint: 'upload.cfm'
},
session : {
endpoint: 'imageStatus.cfm',
refreshOnRequest:true
},
validation: {
itemLimit: 2,
allowedExtensions: ["jpeg", "jpg", "gif" , "png"],
sizeLimit: 5000000 // 5 MiB
},
messages: {
tooManyItemsError: 'You can only add 2 images'
},
deleteFile: {
enabled: true, // defaults to false
endpoint: 'upload_delete.cfm?uuid=',
method: 'post'
},
retry: {
enableAuto: false
},
scaling: {
sendOriginal: true,
hideScaled: true,
sizes: [
{name: "THUMB_XX", maxSize: 113},
{name: "FULLIMAGE", maxSize: 450}
]
},
});
});
</script>
I solved the issue.
ends up that I did a custom build of the JS files and did not include the status function.
rebuild the downloads and works like a charm.
thanks everyone for the help.
The initial file list feature is not a function that you call, per say, it is an option that you set in the client. More or less, all you need to set is the endpoint where the uploader can retrieve this list of files, and then have your server correctly process them.
The server response should be a JSON Array of Objects.
[{ name: 'foo.jpg', uuid: "7afs-sdf8-sdaf-7asdf" }, ... ]
The trickiest part is getting that list of files server-side, and you may want to ask some Coldfusion folks about how to do that.