I have created a collection called Nodes and have defined it as follows:
(located in project/lib so it has access to both client and server)
Nodes = new Mongo.Collection('nodes');
Nodes.allow({
insert: function (userId, node) {
return !!userId;
}
});
I have an insert method that lies within the same file:
Meteor.methods({
nodeInsert: function(nodeAttributes) {
var node = _.extend(nodeAttributes, {
userId: user._id, author: user.username, submitted: new Date()
});
var nodeIdentity = Nodes.insert(node, function(error,result){
if (error)
console.log(error);
if (result)
console.log(result);
});
}
});
However, there is no error that is logged on the console.
I have also published this collection on the server:
(located in project/server)
Meteor.publish('nodes', function(){
return Nodes.find();
});
I have also subscribed to this collection in the template where I use my insert method:
(located in project/lib so it has access to both client and server)
Router.route('/workflow',{
waitOn: function () {
return [Meteor.subscribe('uploads'),Meteor.subscribe('nodes')];
},
action: function () {
if (this.ready())
this.render('workflow');
else
this.render('Loading');
}
});
Finally, this is how I call my nodeInsert function from my client side template:
(located in project/client)
var node = {
title: d.title
};
Meteor.call('nodeInsert', node, function(error, result) {
if (error)
return throwError(error.reason);
});
The node appears to insert into the collection, but when I use the "show collections" command in mongo, the nodes collection does not come up.I also get an internal server error when I do the insert. What may be the reason for this error?
Related
I am trying to use the search method of Ldap.js in my node.js code. Here is my code for the client side. It adds successfully a user, but searching for the newly added user does not yield any results. (The ldap server is running in a docker container from https://github.com/osixia/docker-openldap)
var ldap = require("ldapjs");
var assert = require("assert");
var client = ldap.createClient({
url: "ldap://localhost:389",
});
client.bind("cn=admin,dc=example,dc=org", "admin", function (err) {
assert.ifError(err);
let newUser = {
cn: "userId7",
userPassword: "password",
objectClass: "person",
sn: "efub",
};
// Here i successfully add this user "userId7"
client.add(
"cn=userId7,dc=example,dc=org",
newUser,
(err, response) => {
if (err) return console.log(err);
return response;
}
);
var options = {
filter: "(objectClass=*)",
scope: "sub",
};
// Now the search, it runs without error, but does never receive a searchEntry
client.search(
"cn=userId7,dc=example,dc=org",
options,
function (error, search) {
console.log("Searching.....");
client.on("searchEntry", function (entry) {
console.log("I found a result in searchEntry");
});
client.on("error", function (error) {
console.error("error: " + error.message);
});
client.unbind(function (error) {
if (error) {
console.log(error.message);
} else {
console.log("client disconnected");
}
});
}
);
});
client.on('error', function (err) {
if (err.syscall == "connect") {
console.log(err);
}
});
Also, if it helps, this is how the newly added user looks like when i display all users from ldap by running docker exec my-openldap-container ldapsearch -x -H ldap://localhost:389 -b dc=example,dc=org -D "cn=admin,dc=example,dc=org" -w admin
# userId7, example.org
dn: cn=userId7,dc=example,dc=org
cn: userId7
userPassword:: cGFzc3dvcmQ=
objectClass: person
sn: efub
Update: I can successfully search for the user "userId7" with the shell command: docker exec ldap-service ldapsearch -LLL -x -D "cn=admin,dc=example,dc=org" -w "admin" -b "cn=userId7,dc=example,dc=org" "(objectclass=*)". How can i make ldapJS also run this search successfully?
Update 2: I can also successfully search by using the frontend "phpLDAPadmin" as seen in the screenshots below:
So i solved it. The correct client.search code is:
client.search(
"cn=userId7,dc=example,dc=org",
options,
function (error, res) {
console.log("Searching.....");
res.on("searchEntry", function (entry) {
console.log("I found a result in searchEntry", JSON.stringify(entry.object));
});
res.on("error", function (error) {
console.error("error: " + error.message);
});
client.unbind(function (error) {
if (error) {
console.log(error.message);
} else {
console.log("client disconnected");
}
});
}
);
Inside function (error, res) { I listened for the events via client.on("searchEntry", instead of res.on("searchEntry", therefore missing the events from the search results. The root cause was a classic copy and paste error and changing the variable while misunderstanding the origin of the event.
I'm calling three functions, after the completion of these functions I want my script to close on it's own but it just hangs.
I've tried making the functions async/promise based, closing the database after each 'mongodb' type function, and using process.exit() within a function as a callback to the last called function.
Connecting to the (local - not Atlas) Database:
MongoClient.connect(local, {useNewUrlParser: true, useUnifiedTopology: true}, function(err, db) {
if (err) {
console.log(err)
}
else {
console.log('Connected to MongoDB...')
//Read in data from jsonfiles and store each file's contents into the database : This is where the functions are being called... within a successful connect to the MongoDB
insertJSON(db, jsonfiles, 'requests', jsonfilesSource)
insertJSON(db, issuedfiles, 'issuedLicenses', isssuedfilesSource)
insertLicenses(db)
}
db.close()
})
Function 1:
function insertJSON(db, dirBuf,collection, sourceFolder) {
var database = db.db('license-server')
var collection = database.collection(collection)
fs.readdir(dirBuf, function(err, files) {
if (err) {
console.log(err.message)
}
else {
files.forEach(function(filename) {
var text = fs.readFileSync(sourceFolder + filename);
var filecontents = JSON.parse(text)
//collection.insertOne(filecontents)
collection.findOne({"DisplayTitle" : filecontents.DisplayTitle, "NodeInformation" : filecontents.NodeInformation, "Date": filecontents.Date})
.then(function(result) {
if(result) {
console.log(`An Item could already be in the database: A file is unique if its display title, nodeinformation, and date are different.
the items display title is ${result.DisplayTitle}`)
return
}
else {
collection.insertOne(filecontents)
console.log(`Added ${filecontents.DisplayTitle} to database`)
}
})
.catch(function(error) {
console.log(error)
})
})
}
})
}
Function 2:
function insertLicenses(db) {
// Set up GridFS to import .lic and .licx files into the database
var database = db.db('license-server')
var collection = database.collection('fs.files')
var bucket = new mongodb.GridFSBucket(database);
var dirBuf = Buffer.from('../license-server/private/licenses')
fs.readdir(dirBuf, function(err, files) {
if (err) {
console.log(err.message)
}
else {
files.forEach(function(filename) {
collection.findOne({"filename": filename}).
then(function(result) {
if(result) {
console.log(`The file ${filename} is already in the database`)
return
}
else {
fs.createReadStream('./private/licenses/' + filename).
pipe(bucket.openUploadStream(filename)).
on('error', function(error) {
assert.ifError(error)
}).
on('finish', function() {
console.log(`Uploaded ${filename}`)
})
}
})
})
}
})
// I tried calling db.close() here since this is the last function to be called. No luck.
}
I'm guessing it has something to do with the mongodb functions having their own way to close themselves but I couldn't seem to find what I was looking for in previous attempts to resolve this issue.
The expected result should be the script closing itself, the actual result is a handing script.
All of these database calls are asynchronous -- the result of this code running is to immediately call db.close and then do the work in insertJSON and insertLicenses. If you were to rewrite this to use async/await (and you'd need to update your other functions as well) the db.close call would close the db, and that would allow the script to exit:
await insertJSON(db, jsonfiles, 'requests', jsonfilesSource)
await insertJSON(db, issuedfiles, 'issuedLicenses', isssuedfilesSource)
await insertLicenses(db)
db.close()
https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Introducing
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
Before registering a new User I need to delete a previous one with that email and query an API to fill more information into User as a product requirement.
Unfortunately I can not achieve it, this is the error I get from the server: Exception while invoking method 'createUser' Error: insert requires an argument.
What I did so far is this:
Client:
Accounts.createUser({ email, password, profile: { something } }, (err) => {
if (err) {
console.error(err2.reason);
}
history.replace('/account');
});
Server:
Accounts.onCreateUser((options, user) => {
Meteor.users.remove({ email: options.email }, () => {
try {
const res = request.postSync(authenticate, {
method: 'POST',
json: true,
body: {
email: options.email,
password: options.profile.password
}
});
if (res.response.statusCode < 300) {
const newUser = user;
newUser.profile = {};
newUser.profile.user_id = res.body.response.user_id;
newUser.profile.token = res.body.response.token;
return newUser;
}
throw new Meteor.Error(res.response.body.error.message);
} catch (err) {
throw new Meteor.Error(err.message);
}
});
});
What I'm doing wrong? Thanks
From the Accounts.onCreateUser documentation:
The function should return the user document (either the one passed in or a newly-created object) with whatever modifications are desired. The returned document is inserted directly into the Meteor.users collection.
You function returns nothing though, it just calls Meteor.users.remove() with some function as second argument. Don't forget that DB calls are synchronous in Meteor, so it should be like this:
Accounts.onCreateUser((options, user) => {
Meteor.users.remove({ email: options.email });
// do something else
return user;
});
I have written a node.js lambda function that triggers based on a dynamodb stream when new records are inserted into a particular table.
The function receives only new events, filters for inserted records, and then for each record, uses a couple of fields to retrieve data from other tables. Using this combined data a message is composed and sent via SNS to specific target ARN.
The function performs correctly. All the relevant data is retrieved, and a push notification is sent out.
However, for some reason the function appears to be called several times for the same stream, and processes the newly inserted records several times. The result is the target device receiving the same push notification several times.
Should I be placing the callback in a different place, or am I not calling on the context correctly?
This is the function:
'use strict';
var AWS = require("aws-sdk");
var dynamodb = new AWS.DynamoDB();
var sns = new AWS.SNS();
console.log('Loading function');
exports.handler = (event, context, callback) => {
console.log('Received event:', JSON.stringify(event, null, 2));
event.Records.forEach((record) => {
console.log(record.eventID);
console.log(record.eventName);
console.log('DynamoDB Record: %j', record.dynamodb);
if (record.eventName == 'INSERT') {
var matchId = record.dynamodb.NewImage.eventId.S;
var match_params = {
Key: {
"eventId": {
S: matchId
}
},
TableName: "xxxxxxxxxxx-mobilehub-xxxxxxx-Event"
};
//retrieve the match information from Event table
dynamodb.getItem(match_params, function(err, data) {
var match_description = "";
if (err) {
console.log(err, err.stack);
context.fail('No match event record found in Event table');
} else {
match_description = data.Item.description.S;
var uId = record.dynamodb.NewImage.participantUserId.S; //participantUserId
var user_params = {
Key: {
"userId": {
S: uId
}
},
TableName: "xxxxxxxxxxx-mobilehub-xxxxxxxxx-User"
};
//retrieve the user record from User table
dynamodb.getItem(user_params, function(err, data) {
if (err) {
console.log(err, err.stack); // an error occurred
context.fail('Error occurred. See log.');
} else {
console.log(data); // successful response
if (data.length === 0) {
console.log("No User Record Found.");
context.fail('No user found for participantUserId.');
} else {
var deviceARN = data.Item.device_arn.S;
if (deviceARN <= 1) {
console.log("User has not registered their device for push notifications.");
context.fail('User has not registered for notifications');
} else {
var json_message = JSON.stringify({
APNS_SANDBOX: JSON.stringify({
aps: {
alert: "You are playing in an upcoming match " + match_description,
badge: 1,
sound: 'default'
}
})
});
var snsparams = {
Message: json_message,
MessageStructure: 'json',
TargetArn: deviceARN
};
sns.publish(snsparams, function(err, data) {
if (err) {
console.log(err); // an error occurred
context.fail('SNS send failed. See log.');
} else {
console.log(data); // successful response
context.success('Push notification sent to user.');
}
});
}
}
}
});
}
});
}
});
callback(null, `Successfully processed ${event.Records.length} records.`);
};
In my case, I added the same event source multiple times.
Quote from the conversation with an AWS support engineer:
Using my internal tools, I noticed that the Lambda function xxxxxx has
the event source:
arn:aws:events:my_region:my_acct_id:rule/my_event_target
configured twice as push event source. This means that this might be the cause
why you are seeing two invokes at every minute. Would you please
confirm on your side if this event is configured twice for the $LATEST
version of your lambda and also confirm if it's intended?
I hope this could save someelse :)
In your lambda page at the bottom, try tweaking "Concurrency" Unreserved account concurrency to 1 and "Asynchronous invocation" Retry attempts to 0 . As a test try these and observe the behaviour. Might help.
I am using the imap-simple NPM package to check emails, and I am having trouble getting the insert to work properly.
I have already read through this page: https://guide.meteor.com/using-npm-packages.html#async-callbacks - and I have tried the suggestions but none of them are working!
I've also simplified the code a bit just to try to get it working, but still have no luck.
The problem should be very easy to reproduce - meteor npm install imap-simple, throw the above code on the server, add some email credentials, and call the method.
Here is my code:
var imaps = require('imap-simple');
var config = {
imap: {
user: '<removed>',
password: '<removed>',
host: 'imap.gmail.com',
port: 993,
tls: true,
authTimeout: 3000
}
};
Meteor.methods({
api_connectEmail: function () {
console.log('Received call to connect email');
imaps.connect(config).then(function (connection) {
return connection.openBox('INBOX').then(function () {
var searchCriteria = [
'UNSEEN'
];
var fetchOptions = {
bodies: ['HEADER', 'TEXT'],
markSeen: true
};
return connection.search(searchCriteria, fetchOptions).then(function (results) {
results.map(function (res) {
var subject = res.parts.filter(function (part) {return part.which === 'HEADER';})[0].body.subject[0];
console.log("Subject: " + subject);
// insert
var attributes = {
subject: subject
};
console.log("Attempting to insert to collection...");
var newData = TempEmailCollection.insert(attributes);
console.log("New Database Entry ID: " + newData);
});
});
});
})
}
});
The console.log with the subject is working. The insert is not working. No error, no console.log post insert, nothing.
I've tried both strategies recommended in the guide, neither work.
The problem is that you are calling a Meteor function inside asynchronously called Promise handlers.
However, all Meteor functions that are called on the server have to run in a fiber.
Meteor actually throws an error in this case but you are ignoring it because you haven't specified catch functions for the Promises.
Consider the following simplified example (it just connects to the server and tries to insert a new document):
import { Meteor } from 'meteor/meteor';
import imaps from 'imap-simple';
const Storage = new Mongo.Collection('storage');
const config = {
imap: {
…
}
};
Meteor.methods({
connect() {
console.log('Method called');
imaps.connect(config).then(function(connection) {
console.log('Connected');
Storage.insert({
value: 'success'
});
console.log('Document inserted');
})
.catch(function(err) {
console.error(err);
});
}
});
The following message will arrive in the catch function:
[Error: Meteor code must always run within a Fiber. Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment.]
You could do something like this to wrap the insert call:
Meteor.methods({
connect() {
console.log('Method called');
const insert = Meteor.bindEnvironment(function() {
Storage.insert({
value: 'success'
});
});
imaps.connect(config).then(function(connection) {
console.log('Connected');
insert();
console.log('Document inserted');
})
.catch(function(err) {
console.error(err);
});
}
});
Then the document will be inserted as expected.