How to get PFUser from array ? [Parse.com Cloud Code] - arrays

I have a class called Chat. Its objects have two attributes: "users" and "messages". I want to detect if a message was added to the "messages" array and if so send push notification to all users from "users" array.
This is my code:
Parse.Cloud.beforeSave(„Chat”, function(request, response) {
if (request.object.dirty("messages")) {
var users = request.object.get("users");
for (var i=0; i<users.length; i++) {
var currentUserId = users[i].get("objectId");
console.log(currentUserId);
}
response.success();
} else {
response.error(„no messages sent”);
}
});
I know how to send push but I have a problem with getting the PFUser objects from "users" array. When I try to print their IDs in console I get "no message sent" error in parse.com logs. Can anyone help me ?

Related

Retrieve data from array in another function

I am trying to retrieve the data set in an array in one function, in a different function. I appended the data i want into the OtherUserArray in the
createNewConversation function. However when i try the retrieve this data in the sendMessage function, it prints an empty array.
import MessageKit
import InputBarAccessoryView
import FirebaseAuth
import Firebase
import Foundation
final class DatabaseManager {
static let shared = DatabaseManager()
var foundOtherUser:String?
var OtherUserArray = [String]()
}
extension DatabaseManager {
// create a new conversation with target user, uid and first sent message
public func createNewConversation(with otherUserUid: String, name: String, firstMessage: Message, completion: #escaping(Bool) -> Void) {
let db = Firestore.firestore()
let CurrentUser = Auth.auth().currentUser?.uid
let defaults = UserDefaults.standard
defaults.set(CurrentUser, forKey: "uid")
guard let currentUid = UserDefaults.standard.string(forKey: "uid"), let currentName = UserDefaults.standard.string(forKey: "usersFullname") else {
return
}
let messageDate = firstMessage.sentDate
let dateString = MessageViewController.dateFormatter.string(from: messageDate)
var message = ""
let conversationId = firstMessage.messageId
let newConversationData: [String:Any] = [
"id": conversationId,
"other_user-uid": otherUserUid,
"name": name,
"latest-message": [
"date": dateString,
"message": message,
"is-read": false
]
]
// save other user uid to global var
OtherUserArray.append(otherUserUid)
}
}
}
public func sendMessage(to conversation: String, name: String, newMessage: Message, completion: #escaping(Bool) -> Void) {
// update the latest message
print(self.OtherUserArray)
}
The problem is not where you access self.OtherUserArray, but when you access it.
Data is loaded from Firebase asynchronously, while the rest of you code typically runs synchronously. By the time the print(self.OtherUserArray) in your sendMessage runs, the OtherUserArray.append(otherUserUid) hasn't been executed yet, so the array in empty. You can most easily verify this by running the code in a debugger and setting breakpoints on those like, or by adding print statements and checking the order of their output.
For examples of this, as well as how to solve the problem, see these previous questions:
Why I couldn't assign fetched values from Firestore to an array in Swift?
Is Firebase getDocument run line by line?
Storing asynchronous Cloud Firestore query results in Swift
How do I save data from cloud firestore to a variable in swift?
Why are print statements not executing in correct order?? Am I crazy or is Xcode?
Get all documents at once in a completion handler with getDocuments in Firestore

res.json converts object into array nodejs

I'm responding with a JSON in my routing with the following
app.get('/loginerr', function(req, res, next){
var message = req.flash('signupMessage');
res.json({'error' : message});
});
The message is a simple String type but the JSON object is sent inside an array like this:
{
"error": [
"The email is already taken"
]
}
As you can see there is a pair of brackets for an array in the response. How I get rid of them?
you can use this :
var message = req.flash('signupMessage')[0];
res.json({'error' : message});
I was not aware that the req.flash object is an array.
I just had to take the only and first element of the array:
res.json({'error' : message[0]});

Posting Schema.Types.ObjectId arrays to MongoDB

How can I post an array of Schema.Types.ObjectId (s) to MongoDB? I'm trying to create User Groups, which is a group of the 'User' Model e.g.
var UserGroup = new Schema({
users: [{
type: Schema.Types.ObjectId,
ref: 'User'
}]
});
New UserGroup Function
module.exports.create = function(request, response) {
var group = new UserGroup({
users = request.body.users
});
group.save(function(error) {
if(error) { throw error; } else { response.send('Group Created Successfully.');
});
};
I'm currently using Postman to test the functionality, how exactly should the data be posted?
As a Javascript array i.e ['A_USER_ID', 'A_USER_ID'] ?
Thanks!
#Answer
I was using the older syntax of the select() function, and therefore was passing invalid parameters to the $push function. When sending the request, I simply pass the ObjectIds as id,id,id and once they get to the server, simply put it into an array using var my_array = request.body.users.split(','); and then push it to the database using the following:
$push: { users: { $each: my_array } }
I hope this was helpful, the documentation isn't particularly clear on this matter.

Twilio & NodeJS: can't find and delete Media instances/resources

I'm using Twilio's NodeJS module & API to send out MMS messages with images attached (from a remote URL), and I want to delete the Media instances that get created on Twilio servers as soon as I send out the messages.
My messages send out correctly, and in the callback, I'm trying to 1) list media instances for the current message, then 2) loop through those instances and delete. The problem is that the mediaList array that comes back from the API for a current message is always empty.
Here's my code:
twilio_client.messages.create({
body: "Thanks for taking a photo. Here it is!",
to: req.query.From,
from: TWILIO_SHORTCODE,
mediaUrl: photo_URL,
statusCallback: STATUS_CALLBACK_URL
}, function(error, message) {
if (!error) {
twilio_client.messages(message.sid).media.list(function(err, data) {
console.log(data);
// The correct object comes back as 'data' here per the API
// but the mediaList array is empty
}
console.log('Message sent via Twilio.');
res.status(200).send('');
} else {
console.log('Could not send message via Twilio: ');
console.log(error);
res.status(500).send('');
}
});
So, it turns out that trying to get the media list at the point I was trying to doesn't work because the media instances didn't exist yet.
I have a separate little app running at the statusCallback (I supply a URL via a constant in the code above, STATUS_CALLBACK_URL), that until now, just checked to see if a message I tried to MMS to a user wasn't handled properly by Twilio, and alerted the user to a problem via SMS. So, I added a check in that same app to see if the message was actually 'sent' to the user, and then checked for and deleted the media instance(s) associated with the message at that point, and it works fine. Here's my code:
// issue message to user if there's a problem with Twilio getting the photo
if (req.body.SmsStatus === 'undelivered' || req.body.SmsStatus === 'failed') {
twilio_client.messages.create({
body: "We're sorry, but we couldn't process your photo. Please try again.",
to: req.body.To,
from: TWILIO_SHORTCODE
}, function(error, message) {
if (!error) {
console.log('Processing error message sent via Twilio.');
res.send(200,'');
} else {
console.log('Could not send processing error message via Twilio: ' + error);
res.send(500);
}
});
}
// delete media instance from Twilio servers
if (req.body.SmsStatus === 'sent') {
twilio_client.messages(req.body.MessageSid).media.list(function(err, data) {
if (data.media_list.length > 0) {
data.media_list.forEach(function(mediaElement) {
twilio_client.media(mediaElement.sid).delete;
console.log("Twilio media instance deleted");
});
}
});
}

Parse.com Data Storage Error with Facebook API

I am building a web application using Parse.com as my backend. I have run into a problem when trying to store the response from Facebook's user profile API in a Parse database.
FB.api('/me', function(response) {
// Print Response to Console
console.log(response);
// Create New Parse Object
var Facebook = Parse.Object.extend("Facebook");
var userFacebook = new Facebook();
for(var element in response) {
userFacebook.set(element, response[element]);
}
// Store Data on Parse
userFacebook.save(null, {
success: function(user) {
console.log("User Facebook data saved.");
},
error: function(user, error) {
console.log("Facebook data storage error: " + error.code + " (" + error.message + ")");
}
});
The API response prints correctly to the console, and I receive two error messages, one after the other:
Failed to load resource: the server responded with a status of 404
(Not Found) https://api.parse.com/1/classes/Facebook/myID
and
Facebook data storage error: 101 (object not found for update)
In my Parse account, a database titled "Facebook" is created. However, it only contains a header for each of the elements in the response object (e.g., first_name, gender, email, etc.). It does not have a new row with these values.
I am really stuck on this one -- any help would be appreciated!
Note that the response object is in the form:
{
"email":"email#example.com",
"first_name":"myFirstName",
"gender":"myGender",
"id":"myID",
"last_name":"myLastName",
"link":"https://www.facebook.com/app_scoped_user_id/myID/",
"locale":"en_US",
"name":"myFullName",
"timezone":-7,
"updated_time":"2014-03-12T04:57:39+0000",
"verified":true
}
The object in for each loop
for(var element in response) {
userFacebook.set(element, response[element]);
}
FB.api('/me', function(response) {
// Print Response to Console
console.log(response);
// Create New Parse Object
var Facebook = Parse.Object.extend("Facebook");
var userFacebook = new Facebook();
for(var element in response) {
userFacebook.set(element, response[element]);
}
// Store Data on Parse
userFacebook.save(null, {
success: function(user) {
console.log("User Facebook data saved.");
},
error: function(user, error) {
console.log("Facebook data storage error: " + error.code + " (" + error.message + ")");
}
});
The "id" column on a Parse.Object is protected and cannot be set via the API. In my case, Facebook's API response includes an "id" key, which is colliding with the Parse.Object "id" key.
If you are running into the same problem, you simply need to change the name of the "id" column. You can do this with the following code:
for(var element in response) {
if(element=="id") {
userFacebook.set("userID", response[element]);
} else {
userFacebook.set(element, response[element]);
}
}
Thanks to Hector Ramos at Parse for helping me solve the problem! And thanks to Wayne for getting me part of the way!

Resources