Parse.com User.get("column") only works for current user - javascript

I have an object called Group, which stores an array of Users (default Parse user) as a column. I am trying to list all of these users' display names (column called "displayName") in a certain group, but for some reason, when I try to use the .get function on a user in the retrieved array, it only gives me the information for the current user. I checked my permissions and ACL and it says for each user Public Read, and the User class has public read and write permissions. Here is the code I am using:
var groupObject = Parse.Object.extend("Group");
var users = [];
var groupQuery = new Parse.Query(groupObject);
groupQuery.get(groupId,{
success: function(group)
{
users = group.get("Users");
for(var i=0;i<users.length;i++)
{
var user = users[i];
console.log("display name: " + user.get("displayName") + "username: " + user.get("username") + "id: " + user.id);
}
doneCallback(users);
},
error: function(object, error)
{
errorCallback(error);
}
});
I am able to console.log all of their ids, and the query is successful, but the only thing I can use get("column") on is the current user (which is part of the group users array).

I think you should use a Relation instead of an Array to store your users in the Group object. It will be way easier to add, remove, fetch and access your user objects via the relation. You also avoid some headache when the list of your users becomes large. Then you should be able to fetch all the users in any given group like this:
var groupObject = new Parse.Object("Group");
groupObject.set("objectId", yourGroupId);
var query = groupObject.relation("Users").query();
Parse.Cloud.useMasterKey();
query.find().then( function(users) {
_.each(users, function(user) {
console.log(user.get("displayName"));
});
});

Related

Dialogflow Firebase Realtime Database Getting Error: No responses defined for platform: Undefined yet method still goes through

I've been trying for a project I'm working on to develop a function for a Food chatbot. What I'm currently working on is to perform a method for a user to make a purchase of an order that is stored in firebase realtime database.
The method is set as the method for an actionMap and the actionMap is linked to an intent for knowing when to call the method and for retrieving the parameters.
My current method uses a simple check for a user's existence and status within the database before identifying the existence of the order they're trying to make a purchase for by its id by going through the user's reference path and doing a .forEach to check every order found and look at its parent folder name to check if it matches the user's order id. My code is as follows:
const MakePurchaseACTION = 'Make Purchase';
function makePurchase(app){
let email = parameter.email;
let orderId = parameter.orderId;
var currDate = currDateGenerator();
var name = email.split(".com");
//Check if User exists first in database
var userRef = database.ref().child('user/' + name);
return userRef.once('value').then(function(snapshot) {
if (snapshot.exists()) {
let statusRetrieved = snapshot.child('Status').val();
//Check if user's status in database is signed in.
if (statusRetrieved == "Signed In") {
var orderRef = database.ref().child('order/' + name);
//Check the order table for the user.
return orderRef.once('value').then(function(orderSnapshot){
let orderVal = orderSnapshot.val();
console.log(orderVal);
//Check through every child for the matching id.
orderSnapshot.forEach(function(childSnapshot) {
let orderIdFound = childSnapshot.key;
//let cost = childSnapshot.child('Cost').val();
console.log(orderIdFound);
if(orderId == orderIdFound) {
let eateryName = childSnapshot.child('Eatery').val();
let eateryLocation = childSnapshot.child('EateryLocation').val();
let deliveryAddress = childSnapshot.child('DeliveryAddress').val();
let orderItem = childSnapshot.child('OrderItem').val();
let quantity = childSnapshot.child('Quantity').val();
let cost = childSnapshot.child('Cost').val();
var purchaseRef = database.ref().child('purchase/' + name + "/" + currDate + "/" + orderId);
purchaseRef.set({
"Eatery" : eateryName,
"EateryLocation" : eateryLocation,
"DeliveryAddress": deliveryAddress,
"OrderItem" : orderItem,
"Quantity": quantity,
"Cost": cost,
"DateCreated": currDate
});
app.add("You have successfully purchased Order " + orderId);
} else {
app.add("There is no order with that id.");
}
});
});
} else {
app.add("You need to be signed in before you can order!");
}
}
else {
app.add("Sorry pal you don't exist in the database.");
}
});
}
actionMap.set(MakePurchaseACTION, makePurchase);
After checking through some firebase logs
Firebase Logs screenshot here
Firebase Realtime Database Order Table Sample
I found that the method actually completes Purchase table sample but my dialogflow returns with the stated error of:
Error: No responses defined for platform: undefined and displays "Not Available" back to the user. My question is how do I go about resolving this error?

How to link a user ID with a to-do list in Firebase so that the list appears only to him when the user logs in?

I want to use the following function to add to-do things from a list that is linked to a user.
$(document).ready(function(){
$("#toDoButton").click(function(){
var lol = $("#somethingToDo").val();
// $("#myList").append("<li> X " + lol + "</li>").addClass("deleted");
$("<li> X " + lol + "</li>").addClass("deleted").appendTo("#myList");
database.ref('users/' + useNumber).push({
data: lol
});
});
});
When I create a user, I do it with the following function:
function recordUser(uid, name, surname) {
var postData = {
name: name + surname,
data: "data"
};
var updates = {};
updates['/users/' + uid] = postData;
return firebase.database().ref().update(updates);
}
Whenever a user signs in, I want only his to-do list to appear.
with the above functions, I can only create a NEW user with undefined ID.
Also I tried using the "data" field to update there the to-do-list
Can someone tell me how I can link user-id with the corresponding "to-do" list?
What am I doing wrong?
Here's my JSON tree
JSON tree
use the user's uid as a key for his todo list node, so you can fetch it at login

How to query relational data in Parse JavaScript

I am quite new to Parse.
I have a database set up using this code:
var Class = Parse.Object.extend("Class");
var Team = Parse.Object.extend("Team");
var Student = Parse.Object.extend("Student");
var newClass = new Class();
newClass.set("name", className);
newClass.set("code", classCode);
newClass.set("creator", currentUser);
var classACL = new Parse.ACL(currentUser);
classACL.setPublicReadAccess(true);
newClass.setACL(classACL);
newClass.save();
for (var i = 0; i < teamNames.length; i++) {
var team = new Team();
team.set("name", teamNames[i]);
var teamACL = new Parse.ACL(currentUser);
teamACL.setPublicReadAccess(true);
team.setACL(teamACL);
team.save();
for (var j = 0; j < studentNames[i].length; j++) {
if (studentNames[i][j]) {
var student = new Student();
student.set("name", studentNames[i][j]);
student.set("parent", team);
student.save();
}
}
team.set("parent", newClass);
team.save();
}
newClass.save(null, {
success: function(newClass) {
//success
},
error: function(newClass, error) {
//fail
}
});
Here Class, Team, and Student are modeled as one-to-many relationships.
Now when a student signs up for the class using his or her own user account, the corresponding Student's user column is set to the current user.
Then I want to list all the classes whose creator OR one of its student's user column (if exists) equals to currentUser.
How do I create such a query referencing multiple classes in Parse (or how can I optimize the database so that such a query can be made as efficient as possible -- without having to create two separate queries?)
Any help is appreciated.
Clarification:
I knew that I could do an or query as described in Parse docs (I should have stated this in the question), however, my question is about doing so on relational data (defined by a pointer type property to parent). Here I need user be a property of a Student instance, which belongs to Team, and then to Class, and I'd like to filter only Class objects that has either its creator property or one of its grandchildren's (an instance of Student) user property equal to the currentUser, effectively listing only the classes that you created or are registered as a student.
Since the current database schema is having nested Pointers, there is no easy way to achieve this without adjusting it.
Database Schema
In Class class, add a Relation or Array field to contain references to Student/User objects. If you use User as object pointer, we wouldn't need to look up for Student at first.
Query
I assume that you have students as new Array field in Class class. students contains User objects.
var user = Parse.User.current();
var studentQuery = new Parse.Query(Class);
var creatorQuery = new Parse.Query(Class);
studentQuery.equalTo("students", user);
creatorQuery.equalTo("creator", user);
var query = Parse.Query.or(studentQuery, creatorQuery);
query.find().then(function(objects){
// Proceed with the results
},function(error){
// Handle error
});
Ok, what you want to do in an OR query with an internal subquery. One call to parse and you can filter the student properties using the subquery.
var studentQuery = new Parse.Query(Student);
studentQuery.equalTo("user", Parse.User.current());
var firstQuery = new Parse.Query(Class);
firstQuery.matchesQuery("student", studentQuery);
var secondQuery = new Parse.Query(Class);
secondQuery.equalTo("creator", Parse.User.current());
var mainQuery = Parse.Query.or(firstQuery, secondQuery);
mainQuery.find({
success: function(results) {
// results contains a list of Classes where the user is either the creator or the user property of the student (if available)
},
error: function(error) {
// There was an error.
}
});

Cloud Code for Parse.com, Query about Parse.User

I need to write a background job in Cloud Code.
It should query the 'User' class for each user, get the array of skills in the "offer" column. Then it should query the 'User' class again for each user comparing the skills from the first user on a match with all the other users.
Here is what I currently have..
Parse.Cloud.job("backgroundJob", function(request, status) {
// Set up to modify user data
Parse.Cloud.useMasterKey();
var counter = 0;
// Query for all users
var users_query = new Parse.Query(Parse.User);
users_query.find(function(user) {
for(var i = 0; i < user.length; i++){
var searchSkills = user[i].get("search");
var query = new Parse.Query(Parse.User);
query.containedIn("offer", searchSkills);
var pushQuery = new Parse.Query(Parse.Installation);
pushQuery.matchesQuery('user', query);
}
Parse.Push.send({
where: pushQuery,
data: {
alert: "Found someone close to you!"
}
}, {
success: function() {
// Push was successful
},
error: function(error) {
// Handle error
}
});
status.message(counter + " users processed.");
counter++;
}).then(function() {
// Set the job's success status
status.success("Success");
}, function(error) {
// Set the job's error status
status.error("Error has been encountered");
});
});
I get following error in the Push Notification saying:
Cannot perform operation on non-existing column "offer"
Apparently it creates a new empty 'User' Class for my second user query.
Any help would be very much appreciated.
UPDATE! Thats how my user class looks like:
Here's the link for the containedIn method: https://parse.com/docs/js/api/classes/Parse.Query.html#methods_containedIn
So you need to have an "offer" column on your user, that contains a value that would be found in the array searchSkills. Sounds like you don't have an "offer" column. Maybe you have "Offer"? These are case sensitive.
For the second part, do you have a "user" field on your installations? That's something you'd have to set manually, I believe. So it sounds like you never set that, and it's creating a blank user field for the query.
Also, Query.find can only return 1000 results. If you want to go through all of your users, you'll have to use Query.each instead.

Store Properties for a SharePoint-hosted app

I'm trying to figure of the best--or really any working way-- to store key/value pairs in a SharePoint hosted app. The pairs need to:
Be loaded on start up, if the settings exist, otherwise use defaults.
Be created on demand--i.e. a user can add a new setting in the UI, then I use that setting elsewhere in the code to make changes. For example a use a custom string of text as a list name instead of the app's default setting.
I've tried using the PropertyBag, but get an Access Denied error when trying to write to it.
I've also tried to use a list but had problems getting that technique to work correctly.
Does anyone have a suggestion of a good method and how it would be done. I'd be happy to revisit the techniques I've already attempted, if those are the best ways.
Keep in mind that this question should be restricted to things that work with a SharePoint-hosted app. That means that C#, and server-side code are out.
Here's the solution I ended up using--storing settings in a list in the hostweb of the app.
It's made up of a few functions seen below.
CreateSettingsList:
Create makes an ordinary list with the fields Title and Value, which I use to store a setting name and a value to be associated with it. This is called in the document ready function to ensure that a list has been created, and if one already has, it goes on and tries to read from it. If a list didn't exist before, I call a function to initialize default variable values in the list.
//___________________________________Create settings list________________________________________
function createSettingsList()
{
// Create a SharePoint list with the name that the user specifies.
var hostUrl = decodeURIComponent(getQueryStringParameter("SPHostUrl"));
var hostContext = new SP.AppContextSite(currentContext, hostUrl);
var hostweb = hostContext.get_web();
var listCreationInfo = new SP.ListCreationInformation();
//title the list
listCreationInfo.set_title("PTOAppSettings");
//set the base type of the list
listCreationInfo.set_templateType(100); //generic list
listCreationInfo.set_description("A list for custom app settings. If you have uninstalled the Paid Time Off App with no intention of reinstalling, this list can be safely deleted.");
var lists = hostweb.get_lists();
//use the creation info to create the list
var newList = lists.add(listCreationInfo);
var fieldCollection = newList.get_fields();
//add extra fields (columns) to the list & any other info needed.
fieldCollection.addFieldAsXml('<Field Type="Text" DisplayName="Value" Name="Value" />', true, SP.AddFieldOptions.AddToDefaultContentType);
newList.update();
currentContext.load(fieldCollection);
currentContext.load(newList);
currentContext.executeQueryAsync(onSettingsListCreationSuccess, onSettingsListCreationFail);
}
function onSettingsListCreationSuccess(){
//All is well.
initializeSettings();
}
function onSettingsListCreationFail(sender, args) {
//alert("We didn't create the list. Here's why: " + args.get_message());
//If a list already exists, we expect the creation to fail, and instead try to read from the existing one.
getSetting("VAR_CCEmail");
}
Initialize:
Initialize creates new list items for the variables that I may be storing in the future. I set their value to "" or null if they're not being used.
//___________________________________Initialize setting(s)________________________________________
function initializeSettings()
{
//Get info to access host web
var hostUrl = decodeURIComponent(getQueryStringParameter("SPHostUrl"));
var hostContext = new SP.AppContextSite(currentContext, hostUrl);
var hostweb = hostContext.get_web();
//Get list in host web
var lstObject = hostweb.get_lists().getByTitle("PTOAppSettings");
//Prepare an object to add a new list item.
var listItemCreationInfo = new SP.ListItemCreationInformation();
var newItem = lstObject.addItem(listItemCreationInfo);
//Create item. You should repeat this for all the settings you want to track.
newItem.set_item('Title', "VAR_CCEmail");
newItem.set_item('Value', "");
//Write this new item to the list
newItem.update();
currentContext.executeQueryAsync(onListItemSuccess, onListItemFailure);
function onListItemSuccess() {
//Load customizations, if any exist
getSetting("VAR_CCEmail");
}
function onListItemFailure(sender, args) {
bootbox.dialog({
title: "Something went wrong!",
message: "We were unable to initialize the app settings! Here's what we know about the problem: " + args.get_message() + '\n' + args.get_stackTrace(),
buttons: {
success:{
label: "Ok"
}
}
});
}
}
Set:
Set is a fairly straightforward function that accepts a setting name and a value and allows you to update the value stored in a given variable.
//___________________________________Set setting________________________________________
function setSetting(setting, value){
//Get info to access host web
var hostUrl = decodeURIComponent(getQueryStringParameter("SPHostUrl"));
var hostContext = new SP.AppContextSite(currentContext, hostUrl);
var hostweb = hostContext.get_web();
//Get list in host web
var list = hostweb.get_lists().getByTitle("PTOAppSettings");
//A caml query get the appropriate setting
var queryXml = "<View><Query><Where><Eq><FieldRef Name='Title' /><Value Type='Text'>" + setting + "</Value></Eq></Where></Query></View>"
var query = new SP.CamlQuery();
query.set_viewXml(queryXml);
var items = list.getItems(query);
currentContext.load(items);
currentContext.executeQueryAsync(onListItemSuccess, onListItemFailure);
function onListItemSuccess() {
//looking up a specific setting should only return one item in the array.
var item = items.getItemAtIndex(0);
//update the value for the item.
item.set_item("Value", value);
item.update();
}
function onListItemFailure(sender, args) {
bootbox.dialog({
title: "Something went wrong!",
message: "We were unable to set app settings! Here's what we know about the problem: " + args.get_message() + '\n' + args.get_stackTrace(),
buttons: {
success:{
label: "Ok"
}
}
});
}
}
Get:
Get reads the list, finds the setting that you specified, and then determines if the Value associated with that setting "" or null or if it is an actual value. If it is an actual value, I write the value to the global variable that the program uses to do things with that setting.
//___________________________________Get setting________________________________________
function getSetting(setting) {
var hostUrl = decodeURIComponent(getQueryStringParameter("SPHostUrl"));
var hostContext = new SP.AppContextSite(currentContext, hostUrl);
var hostweb = hostContext.get_web();
var list = hostweb.get_lists().getByTitle("PTOAppSettings");
//A caml query to get manager name for the record where user is equal to current user.
var queryXml = "<View><Query><Where><Eq><FieldRef Name='Title' /><Value Type='Text'>" + setting + "</Value></Eq></Where></Query></View>"
var query = new SP.CamlQuery();
query.set_viewXml(queryXml);
var items = list.getItems(query);
currentContext.load(items);
currentContext.executeQueryAsync(
function() //on success.
{
//get first (and only) item.
var item = items.getItemAtIndex(0);
var value = item.get_item("Value");
//If the property is empty it hasn't been set.
if (value === "" || value === null){
//Return null to the appropriate global variable. Not all of the settings in this switch are implemented in the program yet, but may be later.
switch(setting) {
case "VAR_PaidTimeOff":
paidTimeOffListName = "";
break;
case "VAR_Contacts":
contactsListName = "";
break;
case "VAR_CCEmail":
carbonCopyEmail = "";
break;
}
}
else
{
//Return the value. Not all of the settings in this switch are implemented in the program yet, but may be later.
switch(setting) {
case "VAR_PaidTimeOff":
paidTimeOffListName = value;
break;
case "VAR_Contacts":
contactsListName = value;
break;
case "VAR_CCEmail":
carbonCopyEmail = value;
break;
}
}
},
function(sender,args){
bootbox.dialog({
title: "Something went wrong!",
message: "We were unable to get app settings! Here's what we know about the problem: " + args.get_message() + '\n' + args.get_stackTrace(),
buttons: {
success:{
label: "Ok"
}
}
});
});
}
This could be expanded to include other functions to do other special tasks, for example you could make a "createSetting" function that would allow you to add new settings on the fly (one of the requirements I mentioned in my initial question). In my case, initializing a set group of settings fulfilled my needs, but other may want a way to write more.

Categories

Resources