Loop Through all users to send email Node JS - javascript

I tried finding the answer but couldn't. I'm new to Node Js and have a user schema that includes users emails. I want to have a form that has 'subject' and 'message' fields, and a submit button which would then send the contents of the form in an email. I'm currently using Mailgun, and a standard email looks like this:
var data = {
to: user.email,
from: '"Lighthouse Studios" <noreply#reception.lighthousespace.co.uk>',
subject: 'Your password has been changed',
text: 'Hello,\n\n' +
'This is a confirmation that the password for your account ' + user.email + ' has just been changed.\n'
};
mailgun.messages().send(data, function (error, body) {
console.log(body);
});
And my user schema looks like:
var UserSchema = new mongoose.Schema({
username: {type: String, unique: true, required: true},
name: {type: String, required: true},
email: {type: String, unique: true, required: true},
password: String,
studio: {type: String, required: true},
resetPasswordToken: String,
resetPasswordExpires: Date,
comments: [
{
quantity: String,
received: { type: Date, default: Date.now },
collected: { type: String, default: "At Reception" }
}
],
isAdmin: {type: Boolean, default: false}
});
Here's the form code:
<form action="/" method="POST">
<div class="form-group">
<input class="form-control" type="text" name="subject" placeholder="Subject">
</div>
<div class="form-group">
<textarea class="form-control" rows="5" id="comment" name="message" placeholder="Message"></textarea>
</div>
<div class="form-group">
<input class="btn btn-lg btn-primary btn-block" type="submit" value="Send">
</div>
</form>
So to summarise, I want to use the form to send all users an email when the button 'submit' is clicked. Thanks for your time reading this.

UserModel.find({})
.select('email')
.lean()
.exec((err,users)=>{
if(users){
let userEmails = "";
let recp = users.reduce((a,u)=>{ a[u.email]={}; a[u.email].email = u.email; userEmails+=u.email; return a; },{})
let data = {
to: userEmails,
from: '"Lighthouse Studios" <noreply#reception.lighthousespace.co.uk>',
subject: 'Your password has been changed',
text: 'Hello,\n\n' +'This is a confirmation that the password for your account ' + %recipient.email% + ' has just been changed.\n',
'recipient-variables': JSON.stringify(recp)
};
mailgun.messages().send(data, function (error, body) {
console.log(body);
});
}
})
Hope this one will work

Related

MethodOverride PUT not working

I am using Node.js, Express and MethodOverride to try and have a form update only 1 part of a model (my user model).
User model:
var userSchema = new mongoose.Schema({
email: { type: String, unique: true, lowercase: true },
password: String,
profile: {
name: { type: String, default: 'Company Name' },
location: { type: String, default: 'Location' },
website: { type: String, default: 'Your Website' },
picture: { type: String, default: '' }
},
assetNumPre: { type: String, default: 'test' }, // this is the one I want to change
});
module.exports = mongoose.model('User', userSchema);
HTML form:
<form role="form-inline"action="/dashboard/settings/assetNumber?_method=PUT" method="POST">
<div class="col-md-3">
<div class="form-group">
<label for="prefix" class="control-label">Prefix for Asset Number</label>
<br>
<small>Any alphanumeric characters to a limit of 6</small>
<input type="text" class="form-control" id="prefix" name="prefix" placeholder="Prefix max 6 characters" maxlength="6" value="{{ prefix }}">
</div><!-- Prefix for Asset Number-->
<br>
<div class="box-footer">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</form>
Then route:
app.put('/dashboard/settings/assetNumber',
setRender('dashboard/settings/assetNumbers'),
setRedirect({auth: '/login'}),
isAuthenticated,
dashboard.getDefault,
(req, res) => {
var prefix = req.body.prefix;
console.log(req.params);
User.findByIdAndUpdate({_id: req.params.user_id}, prefix, function(err, UpdatedUser) {
if (err) {
res.send(err);
}
console.log(UpdatedUser);
});
res.locals.prefix = req.user.assetNumPre;
});
One thing my route is missing is req.user.assetNumPre which is where I need to save it but I have no clue how to do this PUT request. Docs are not helping much either.
I got the route from a Stack Overflow example a few days ago and can't find the link to it. My app.js had method override working because I have done DELETE requests already. The model has the correct field and has a default test value that shows up in my show page.
You're calling this:
User.findByIdAndUpdate({_id: req.params.user_id}, prefix...
But prefix is only the value:
var prefix = req.body.prefix;
findByIdAndUpdate takes an Object, not a value, to update a specific field.
So try:
User.findByIdAndUpdate({_id: req.params.user_id}, { assetNumPre: prefix }...
Here is the fixed route:
app.put('/dashboard/settings/assetNumber',
setRedirect({auth: '/login', success: '/dashboard/settings/assetNumber', failure: '/dashboard/settings/assetNumber'}),
isAuthenticated,
(req, res) => {
User.findById(req.user.id, function(err, user) {
if (err) return (err);
user.assetNumPre = req.body.prefix || 'pre';
user.save(function(err) {
if (err) return (err);
req.flash('success', { msg: 'Asset Number Prefix updated.' });
res.redirect(req.redirect.success);
});
});
res.locals.prefix = req.user.assetNumPre;
});
So a few things changed that were not part of the issue. I figured out I need to just set the data inside the callback function. Then do a user.save.

Creating new array with variables coming back as undefined

I am creating a blog web application. I currently have the blogSchema set up as
var BlogSchema = new mongoose.Schema({
title: String,
image: String,
body: String,
created:
{type: Date, default: Date.now},
author: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
username: String
},
comments: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Comment"
}
]
});
module.exports = mongoose.model("Blog", BlogSchema);
I have a post form of the following
<div class="ui main text container segment">
<div class="ui huge header">New Blog</div>
<form class="ui form" action="/blogs" method="POST">
<div class="field">
<label>Title</label>
<input type="text" name="blog[title]" placeholder="title">
</div>
<div class="field">
<label>Image</label>
<input type="text" name="blog[image]" placeholder="image">
</div>
<div class="field">
<label>Blog Content</label>
<textarea name="blog[body]"></textarea>
</div>
<input class="ui violet big basic button" type="submit">
</form>
</div>
On my blog routes page I have my create route as
router.post("/blogs", function(req, res){
// create blog
//req.body.blog.body = req.sanitize(req.body.blog.body);
var title = req.body.title;
var image = req.body.image;
var desc = req.body.body;
var author= {
id: req.user._id,
username: req.user.username
}
var newBlogpost = {title: title, image: image, body: desc, author: author}
Blog.create(newBlogpost, function(err, newBlog){
if(err){
res.render("blogs/new");
} else {
//then, redirect to the index
console.log(newBlogpost)
res.redirect("/blogs");
}
});
});
However when I sign in on the web application and complete the form and view my commmand line for the return of console.log(newBlogpost) after I submit, I get:
{ title: undefined,
image: undefined,
body: undefined,
author: { id: 5a0cbcc3d6c7070a7bb6c45e, username: 'cat' }
I am not sure why the new variable array I am creating has these three variable as undefinded and would appreciate help.

ERROR SyntaxError: Unexpected token < in JSON at position 0

ERROR:
core.es5.js?0445:1084 ERROR SyntaxError: Unexpected token < in JSON at position 0
at JSON.parse (<anonymous>
SITUATION:
What I am trying to achieve is to pre-select the choice the user already made previously and prevent him from voting twice.
CODE:
component.html
<article class="panel panel-default">
<div class="panel-body">
{{ poll.title }}
<br>
<br>
<form #form="ngForm">
<fieldset [disabled]="alreadyVotedFor(-1)">
{{ poll.counter1 }} votes <input type="radio" id="{{ poll.choice1 }}" name="my_radio" value="{{ poll.choice1 }}" (click)="onChoice1(form)" [checked]="alreadyVotedFor(1)"> {{ poll.choice1 }}
<br>
{{ poll.counter2 }} votes <input type="radio" id="{{ poll.choice2 }}" name="my_radio" value="{{ poll.choice2 }}" (click)="onChoice2(form)" [checked]="alreadyVotedFor(2)"> {{ poll.choice2 }}
</fieldset>
</form>
</div>
<footer class="panel-footer">
<div class="author">
{{ poll.username }}
</div>
<div class="config" *ngIf="belongsToUser()">
<a (click)="onEdit()">Edit</a>
<a (click)="onDelete()">Delete</a>
</div>
</footer>
</article>
component.ts
votes: any;
ngOnInit() {
this.pollService.voted(this.poll, localStorage.getItem('userId')).subscribe(
data => {
this.votes = data.votes;
console.log("NGONINIT this.votes: "+ this.votes);
},
err => { console.log("NGONINIT ERROR: "+ err) },
() => { console.log("SUBSCRIBE COMPLETE this.votes: "+ this.votes); }
);
}
alreadyVotedFor(choice: number) {
let result = "";
if (this.votes) {
console.log("THIS.VOTES: "+this.votes);
for (var i = 0; i < this.votes.length; i ++) {
if (this.votes[i].poll == this.poll.pollId) {
result = "disabled";
if (this.votes[i].choice == choice) {
result = "selected";
}
}
}
}
return result;
}
service
voted(poll: Poll, userID: string) {
return this.http.get('http://localhost:3000/'+userID)
.map(response => response.json());
}
routes/user.js
router.get('/:userid', function (req, res, next) {
var userId = req.params.userid;
User.findById(userID, function (err, user) {
console.log("USER JSON? :"+user.json());
return res.send(user.json());
});
});
models/user
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var mongooseUniqueValidator = require('mongoose-unique-validator');
var schema = new Schema({
firstName: {type: String, required: true},
lastName: {type: String, required: true},
password: {type: String, required: true},
email: {type: String, required: true, unique: true},
polls: [{type: Schema.Types.ObjectId, ref: 'Poll'}],
votes: [{
poll: {type: Schema.Types.ObjectId, ref: 'Poll'},
choice: {type: Number},
}],
});
schema.plugin(mongooseUniqueValidator);
module.exports = mongoose.model('User', schema);
This error happens when server responds with HTML instead of JSON, particularly when a route is not found and the response is 404 page.
It's unlikely that API has the only route which is mounted at root and available as http://localhost:3000/'+userID, just because it's not possible for the server to do anything else in this case.
If the route is mounted to some path, like
app.use('/user', userRoutes);
then the requests should be performed to this path as well
return this.http.get('http://localhost:3000/user/'+userID)

how do i store ng-repeat array form data in meanjs?

I am using MEANJS from meanjs.org.
trying to store ng-repeat array data for deal which has dealtype and dealprice as array under it, but unable to do so.
i have setup addFields for the ng-repeat input tag in the create form, but it does not store the data. here is my code.
food.server.model.js
var FoodSchema = new Schema({
created: {
type: Date,
default: Date.now
},
name: {
type: String,
default: '',
required: 'Please fill Food name',
trim: true
},
deal: [{
dealtype: {
type: String,
default: '',
trim: true
},
dealprice: {
type: String,
default: '',
trim: true
}
}],
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
foods.client.controller.js
// initial array setup
var deal = [ { dealtype: '',dealprice: '' }, {dealtype: '',dealprice: '' } ];
$scope.food = {};
$scope.food.deal = deal;
$scope.addItem = function() {
$scope.food.deal.push({
dealtype: '',
dealprice: ''
});
};
// Create new Food
$scope.create = function (isValid) {
$scope.error = null;
if (!isValid) {
$scope.$broadcast('show-errors-check-validity', 'foodForm');
return false;
}
// Create new Food object
var food = new Foods({
name: this.name,
deal:[{
dealtype: this.dealtype,
dealprice: this.dealprice,
}],
});
// Redirect after save
food.$save(function (response) {
$location.path('foods/' + response._id);
// Clear form fields
$scope.name = '';
$scope.dealtype = '';
$scope.dealprice = '';
}, function (errorResponse) {
$scope.error = errorResponse.data.message;
});
};
create-food.client.view.html
<form name="foodForm" class="form-horizontal" ng-submit="create(foodForm.$valid)" novalidate>
<fieldset>
<div class="col-md-12">
<md-input-container flex="">
<label >Food Name</label>
<input type="text" data-ng-model="name" id="name" required>
</md-input-container>
</div>
<div ng-repeat="de in food.deal">
<div class="col-md-6">
<md-input-container class="">
<label class="" for="dealtype">Dealtype</label>
<input type="text" data-ng-model="de.dealtype" id="dealtype" >
</md-input-container>
</div>
<div class="col-md-6">
<md-input-container class="">
<label class="" for="dealprice">Dealprice</label>
<input type="text" data-ng-model="de.dealprice" id="dealprice" >
</md-input-container>
</div>
</div>
<a href ng:click="addItem()" class="btn btn-small">add item</a>
<button class="md-primary md-raised width-100 md-whiteframe-5dp" type="submit">Create Food</button>
<div ng-show="error" class="text-danger">
<strong ng-bind="error"></strong>
</div>
</fieldset>
</form>
Try to set your schema up without the embedded array and send without deal. If that works you may need to set up your schema with a subdocument.
If you are wanting to set your deal property up as a Subdocument you would need to follow this. You would define a schema for deal separately. Something like this:
var dealSchema = new Schema({ {
dealtype: {
type: String,
default: '',
trim: true
},
dealprice: {
type: String,
default: '',
trim: true
}
} });
var FoodSchema = new Schema({
...,
deal: [dealSchema]
})

extend mean module findOne() to handle other attributes that strings

When start a new meanjs project (mongoose, angular etc.) using the generator and add a CRUD-module i get methods like this:
$scope.findOne = function() {
$scope.income = Incomes.get({
incomeId: $stateParams.incomeId
});
In my income server model is shown below, it has some different attributes and some different object types on these attributes, for example, number, date and string.
When i get data in my $scope.income after the promise "$scope.findOne" has succeded all my data are strings. Do i need to cast each and every one of them to their proper type?
In my front end i want to present the different types in the input elements of my "update" view. For example:
<label class="control-label" for="date">Date of transaction</label>
<div class="list-group-item">
<div class="controls">
<input type="date" data-ng-model="income.date" id="date" class="form-control" placeholder="Date" required>
</div>
This does not work since the object $scope.income.date consists of a string. Changing the input type to string makes it show up. But I want to use a date picker here.
Should I write something like:
$scope.findOne = function() {
Incomes.get({
incomeId: $stateParams.incomeId
}).then(function(data){
var dateVar=new Date(data.date);
var amountVar =Number(data.amount)
$scope.income ={date: dateVar, name: data.name, amount:amountVar}()
);
What is best practise here?
Model I am using:
'use strict';
/**
* Module dependencies.
*/
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
/**
* Income Schema
*/
var IncomeSchema = new Schema({
name: {
type: String,
default: '',
required: 'Please fill Income name',
trim: true
},
amount: {
type: String,
default: '',
required: 'Please fill Income amount',
trim: true
},
date: {
type: Date,
default: '',
required: 'Please fill Income date',
trim: true
},
monthly: {
type: Boolean,
default: '',
required: 'Please fill whether income is recurring monthly',
trim: true
},
yearly: {
type: Boolean,
default: '',
required: 'Please fill whether income is recurring yearly',
trim: true
},
account: {
type: Schema.ObjectId,
ref: 'Account',
required: 'Please select account'
},
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
mongoose.model('Income', IncomeSchema);
First I had to get a hold of the promise, than I easily could build more complex objects from the Incomes.get response. The data is sent over the network as JSON and there fore it is just text, so I needed to instantiate it to the proper types using f ex. Date and Number:
Incomes.get({
incomeId: $stateParams.incomeId
}).$promise.then(function(data){
var dateVar=new Date(data.date);
var amountVar =Number(data.amount)
$scope.income ={date: dateVar, name: data.name, amount:amountVar}()
);
To make the resources function for remove work properly "this" needed to be used, dont forget that the promise is in another namespace so "that=this" is needed.
var that=this;
Incomes.get({
incomeId: $stateParams.incomeId
}).$promise.then(function(income){
income.date= new Date(income.date);
var recurringVar;
if(income.monthly===true){
recurringVar = 'monthly';
} else if( income.yearly===true){
recurringVar = 'yearly';
}
income.recurring=recurringVar;
that.income=income;
});

Categories

Resources