Nothing is more frustrating than failing on a simple task.
I am following along with : https://docs.mongodb.com/stitch/getting-started/first-stitch-app/ - and I get to setp 9 - which is supposed to clear the permissions rule, so anyone can view my posts; however, I still get the permissions error.
Uncaught (in promise) Error: no rule exists for namespace 'blog.comments'
at client.js:343
at <anonymous>
Here's the entire code - but I suspect the error is on the stitch setting side.
YES - i have replaced "your-app-id" with my app id...
I DID clear the filter, and I did change the READ permission to {}...
<html>
<head>
<script src="https://s3.amazonaws.com/stitch-sdks/js/library/v2/stable/stitch.min.js"></script>
<script>
const client = new stitch.StitchClient('<your-app-id>');
const db = client.service('mongodb', 'mongodb-atlas').db('blog');
function displayComments() {
db.collection('comments').find({}).execute().then(docs => {
var html = docs.map(c => '<div>' + c.comment + '</div>').join('');
document.getElementById('comments').innerHTML = html;
});
}
function displayCommentsOnLoad() {
client.login().then(displayComments)
}
function addComment() {
var c = document.getElementById('new_comment');
db.collection('comments').insertOne({owner_id : client.authedId(), comment: c.value})
.then(displayComments);
c.value = '';
}
</script>
</head>
<body onload="displayCommentsOnLoad()">
<h3>Aspirational blog post</h3>
<div id="content">
I like to write about technology, because I want to get on the front page of hacker news (in a good way).
</div>
<hr>
<div id="comments"></div>
<hr>
Add comment:
<input id="new_comment"><input type="submit" onClick="addComment()">
</body>
</html>
Cant go any further, if the first real steps fail.
ANY help is appreciated.
Go to mongodb-atlas in the Stitch console and cross check if you have a collection named blog.comments. It's not the permission error, it's most likely due to the absence of the collection algogether.
I tried setting up stitch once and got into the same problem. Just make sure if the <databasename>.<collectionname> is matching with what you are using in your script which here should be blog.comments. Or just try deleting the collection from there and create a new one.
Related
I am currently having a list with some entries in my database. Now i want the users to be able to edit one of those entries.
When the "Edit" Button is clicked, it should load the original form and prefill all the fields with the values already stored in the database.
I used a mustache template for my form, looking like this:
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
<h1>Issue Form</h1>
<p>{{ errors }}</p>
<form method="post">
<label>Title: <br><input type="text" name="title">{{ value }}</label><br>
<label>Description: <br><textarea type="text" name="description">{{ value }}
</textarea></label><br>
<label>Priority: <br>
<select name="priority">
<option>high</option>
<option>medium</option>
<option>low</option>
</select>
</label><br>
<input type="submit" value="Save Entry">
</form>
</body>
</html>
This is my mongoose schema:
var issueSchema = new mongoose.Schema({
title: String,
description: String,
priority: String
});
I of course did a lot of researche on how to fill my fields. I read about the mongoose "populate()" function, but when i tried to use it, there was always some errors telling me that the function itself is undefined.
Another option was using a JSON file to store the data values, but i cannot do this in this example since the values should always be stored in my MongoDB data folder.
Another version i found was creating an object via the toObject() function. But anytime i tried that out:
router.get('/edit/:id', (req, res) => {
var objectForEditing = issueModel.findOne(req.params.id).toObject;
console.log(objectForEditing);
res.render('issueFormEdit');
});
The console.log part shows me the object as undefined.
Using JQuery like i did in any other javascript file before didn't work either, even when including the modules.
I simply need a method to connect my javascript code with my hjs file. But i simply am not able to do so, my knowledge is not enough for this. I really tried out a lot and have invested hours so far. But i simply can't get to the bottom on how to connect these two files.
This is my first time ever working with this combination of Mustache.JS and MongoDB/Mongoose/Express. Please be gentle :(
If any more code is needed, please just let me know.
Your code has the following list of issues:
1) Model.prototype.findOne() method is asynchronous, so you either need to use async/await or use promises before calling toObject() on it.
2) You are querying mongoose in the wrong way. You need to use findOneById(id) or findOne({ _id: id }).
3) toObject is a function, so it has to be called.
4) objectForEditing needs to be passed to res.render function as the second argument which represents locals, which basically is:
an object whose properties define local variables for the view
Try this code (async/await):
router.get('/edit/:id', async (req, res) => {
let objectForEditing = await issueModel.findOneById(req.params.id);
objectForEditing = objectForEditing.toObject();
res.render('issueFormEdit', objectForEditing);
});
Using Promises:
router.get('/edit/:id', (req, res) => {
issueModel.findOneById(req.params.id)
.then(issue => {
const objectForEditing = issue.toObject();
res.render('issueFormEdit', objectForEditing);
});
});
Here is the code:
<!DOCTYPE html>
<html>
<head>
<title>Google Fitness API</title>
<meta charset='utf-8' />
</head>
<body>
<p>Get your step counts using the Google Fitness API.</p>
<!--Add buttons to initiate auth sequence and sign out-->
<button id="authorize-button" style="display: none;">Authorize</button>
<button id="signout-button" style="display: none;">Sign Out</button>
<div id="content"></div>
<script type="text/javascript">
// Enter an API key from the Google API Console:
// https://console.developers.google.com/apis/credentials?project=_
var apiKey = 'API_key';
// Enter a client ID for a web application from the Google API Console:
var clientId = 'XYZ';
// Enter one or more authorization scopes. Refer to the documentation for
// the API or https://developers.google.com/identity/protocols/googlescopes
// for details.
var scopes = 'https://www.googleapis.com/auth/fitness.activity.read';
var auth2; // The Sign-In object.
var authorizeButton = document.getElementById('authorize-button');
var signoutButton = document.getElementById('signout-button');
function handleClientLoad() {
// Load the API client and auth library
gapi.load('client:auth2', initAuth);
}
function initAuth() {
gapi.client.setApiKey(apiKey);
gapi.auth2.init({
client_id: clientId,
scope: scopes
}).then(function () {
auth2 = gapi.auth2.getAuthInstance();
// Listen for sign-in state changes.
auth2.isSignedIn.listen(updateSigninStatus);
// Handle the initial sign-in state.
updateSigninStatus(auth2.isSignedIn.get());
authorizeButton.onclick = handleAuthClick;
signoutButton.onclick = handleSignoutClick;
});
}
function updateSigninStatus(isSignedIn) {
if (isSignedIn) {
authorizeButton.style.display = 'none';
signoutButton.style.display = 'block';
makeApiCall();
} else {
authorizeButton.style.display = 'block';
signoutButton.style.display = 'none';
}
}
function handleAuthClick(event) {
auth2.signIn();
}
function handleSignoutClick(event) {
auth2.signOut();
}
// Load the API and make an API call.
function makeApiCall() {
gapi.client.load('fitness', 'v1', function() {
var request = gapi.client.fitness.users.dataSources.datasets.get({
userId: 'me',
dataSourceId: 'com.google.step_count.delta',
datasetId: '1476092378000000-' + new Date().getTime() + '000000',
});
request.execute(function(resp) {
console.log(resp);
});
});
console.log(auth2.currentUser.get().getBasicProfile().getGivenName());
}
</script>
<script src="https://apis.google.com/js/api.js?onload=handleClientLoad"></script>
</body>
</html>
And here is what I get from the console:
Object {minStartTimeNs: "1476092378000000", maxEndTimeNs: "1476461775789000000", dataSourceId: "com.google.step_count.delta", point: Array[0], result: Object}
dataSourceId: "com.google.step_count.delta"
maxEndTimeNs: "1476461775789000000"
minStartTimeNs: "1476092378000000"
point: Array[0]
Other than that I don't get error messages in the console. Am I not supposed to get a series of values? If not, how could I do it? I must admit I'm fairly new to APIs :) Many thanks for your help!
Well, make sure that you use valid values for the parameters that you put in your request.
According to the documentation, The dataSources resource includes the data type (and a list of its fields) for each data source. You can specify one of these data types when you create data sources, and you can obtain the name of the data type and a list of its fields when you retrieve a data source from the fitness store.
I also found out that the datasetId is a dataset identifier that is a composite of the minimum data point start time and maximum data point end time represented as nanoseconds from the epoch. The ID is formatted like: "startTime-endTime" where startTime and endTime are 64 bit integers.
For more information, check these related SO questions:
How do I retrieve step count data from Google Fitness REST api?
How to get step count from Google Fit REST API like Google Fit app?
****Update*****
The line:
dataSourceId: 'com.google.step_count.delta'
in the code above was wrong, as 'com.google.step_count.delta' is a dataTypeName, not a dataSourceId
Works much better with an actual dataSourceId ;) Such as:
dataSourceId: 'derived:com.google.step_count.delta:com.google.android.gms:estimated_steps'
Using express and mongoose/mongo to create a todo app. Domain model: Authors have reminders.
In my app.js:
var bodyParser = require('body-parser')
var methodOverride = require('method-override')
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended:true}))
app.use(methodOverride('_method'))
my form using handlebars in views/authors/edit.hbs:
<h2>Edit {{name}}</h2>
<form action="/authors/{{_id}}" method="post">
<input type="hidden" name="_method" value="put">
<label>Name:</label>
<input type="text" name="name">
<input type="submit">
</form>
My routing for the edit view and put request to update author:
app.get("/authors/:id/edit", function(req, res){
AuthorModel.findById(req.params.id, function(err, docs){
res.render("authors/edit", docs)
})
})
app.put("/authors/:id", function(req, res){
console.log("updating")
AuthorModel.findById(req.params.id, function(err, docs){
docs.name = req.body.name
docs.save(function(err){
if(!err){
res.redirect("authors/" + req.params.id)
}
})
})
})
When I inspect the elements in the dev tools I see everything I need to see, but when I go to submit, gives me error CANNOT POST. Create functionality works fine, so my first thought is the method override isn't working. If I change put to POST, everything works great.
If it helps, link to the repo that contains this app
Judging by the documentation, there are two common ways to override the method:
using a header;
using a query string parameter;
You're using the "old" method of specifying a form variable, which you can still use, but this requires custom logic on the server side.
It seems to me that the easiest way for you to fix this is to use the query string parameter:
<form action="/authors/{{_id}}?_method=put" method="post">
I have a simple form which allows the User to enter from_date and to_date.Lets say a user enters 2014-09-01 and 2014-09-10 respectively.
How can I get this form submit to a URL ../from_date/2014-09-01/to_date/2014-09-10
You cannot do that but if you need to do something like this, you need to submit to standard class Controller and then resubmit it using redirection:
public function resubmit() {
Redirect::to('/from_date/'.Input::get('from_date').'/to_date/'.Input::get('to_date'))->withInput();
}
But to be honest I don't know why you try to do that. Usually you post data to static url and display content using dynamic urls with pretty urls.
To change the URL once the page has already loaded, you will need to use javascript, as you won't be able to do this using Laravel/PHP because you need access to the dates, which are only selected after the page has loaded.
If your form is similar to:
<form id="dateForm" onsubmit="return submitDateForm()">
<input type="text" id="from_date" name="from_date">
<input type="text" id="to_date" name="to_date">
</form>
Assuming you are using POST for the form submission, and have already imported jQuery, then insert into your view (or a separate .js file which you import) the following jQuery:
function submitDateForm() {
var from_date = $( '#from_date' ).val();
var to_date = $( '#to_date' ).val();
//Send the request
var request = $.post("../from_date/" + from_date + "/to_date/" + to_date);
//prevent the form from submitting itself normally
return false;
}
I'm trying to add a url to the logged in users collection. My final goal at least is to be able to add a field e.g {profilePicture: 'http://randompic.com/123.png'}
What i've tried so far is:
<template name="profile">
<h1>My Profile</h1>
<form class="form-inline"action="">
<label for="url"></label>
<input class="input input-large" type="url" name="url" placeholder="URL for you image..." id="url">
<button class="btn btn-success submit">Update profile picture</button>
</form>
</template>
When the user will press the Update profile picture -button i send it to this helper function:
Template.profile.events({
'click .submit': function (evt, tmpl) {
var userid = Meteor.userId();
var url = tmpl.find('#url').value;
var options = {_id: userid, profilePicture: url};
Meteor.call('addToProfile', options);
}
});
I have tried to alert out option._id and options.profilePicture and i have that data availble.
Now when i pass it along to my server.js file i get no output of my alert:
Meteor.methods({
'addToProfile': function(options) {
//Not even this alert will show..
alert(options._id); Edit: console.log() works on the server thought.
}
})
So that is my first issue.
The second problem (to come) is that i don't know how to update/add to the users collection with this profilePicture data. Would really appreciate if someone could contribute with a small example of that part.
Based on the comments everything seems to be functioning as expected. It appears that you are just trying to update some user data on the client. Since you have the insecure package removed you need to validate the updates on the server (that the client requests), this is how you would do that:
// only applies to client requests
Meteor.users.allow({
// validation for user inserts
insert: function ( userId, doc ) {
// perform any checks on data that you want to perform, like checking to see if the current user is an admin.
// this check just requests that a user be logged in
return userId;
}
,
// is your validation for user updates
update: function ( userId, doc, fields, modifier ) {
// again, perform any validation you want. A typical check is to make sure they didn't add any extra fields.
// this makes sure a user is logged in and that they are only attempting to update themself
return userId === doc._id;
}
});
There are some more thorough examples in the docs. Now you can just call update like you normally would and rely on the server to perform any validation!