Commit 54cc928b324ad9cfdb6e45cf2995dd1310e5d2c6

Authored by Ryan Glover
Exists in master

Merge branch 'feature/ES2015_#49' into v3.0.0

Closes #49
Showing 51 changed files   Show diff stats
... ... @@ -0,0 +1,3 @@
  1 +{
  2 + "esnext": true
  3 +}
... ...
... ... @@ -23,4 +23,6 @@ fourseven:scss
23 23 standard-minifiers
24 24  
25 25  
26   -npm-container
27 26 \ No newline at end of file
  27 +npm-container
  28 +ecmascript
  29 +digilord:faker
... ...
... ... @@ -17,6 +17,7 @@ caching-compiler@1.0.0
17 17 caching-html-compiler@1.0.1
18 18 callback-hook@1.0.4
19 19 check@1.0.6
  20 +coffeescript@1.0.9
20 21 ddp@1.2.2
21 22 ddp-client@1.2.1
22 23 ddp-common@1.2.1
... ... @@ -24,6 +25,7 @@ ddp-rate-limiter@1.0.0
24 25 ddp-server@1.2.1
25 26 deps@1.0.9
26 27 diff-sequence@1.0.1
  28 +digilord:faker@1.0.7
27 29 ecmascript@0.1.4
28 30 ecmascript-collections@0.1.6
29 31 ejson@1.0.7
... ...
both/methods/insert/collection.js
... ... @@ -0,0 +1,12 @@
  1 +Meteor.methods({
  2 + insertMethod( argument ) {
  3 + check( argument, Object );
  4 +
  5 + try {
  6 + var documentId = Collection.insert( argument );
  7 + return documentId;
  8 + } catch( exception ) {
  9 + return exception;
  10 + }
  11 + }
  12 +});
... ...
both/methods/insert/example.js
... ... @@ -1,20 +0,0 @@
1   -/*
2   -* Methods: Insert - Example
3   -* Example of a method used for inserting into the database.
4   -*/
5   -
6   -Meteor.methods({
7   - exampleInsertMethod: function(argument){
8   - // Check the argument. Assuming an Object type here.
9   - check(argument, Object);
10   -
11   - // Perform the insert.
12   - try {
13   - var exampleId = Example.insert(argument);
14   - return exampleId;
15   - } catch(exception) {
16   - // If an error occurs, return it to the client.
17   - return exception;
18   - }
19   - }
20   -});
both/methods/read/collection.js
... ... @@ -0,0 +1,13 @@
  1 +Meteor.methods({
  2 + readMethod( argument ) {
  3 + check( argument, String );
  4 +
  5 + var document = Collection.findOne( argument );
  6 +
  7 + if ( !document ) {
  8 + throw new Meteor.Error( 'document-not-found', 'No documents found matching this query.' );
  9 + }
  10 +
  11 + return document;
  12 + }
  13 +});
... ...
both/methods/read/example.js
... ... @@ -1,22 +0,0 @@
1   -/*
2   -* Methods: Read - Example
3   -* Example of a method used for reading from the database.
4   -*/
5   -
6   -Meteor.methods({
7   - exampleReadMethod: function(argument){
8   - // Check the argument. Assuming a String type here.
9   - check(argument, String);
10   -
11   - // Perform the read.
12   - var exampleItem = Example.findOne(argument);
13   -
14   - // If the read fails (no documents found), throw an error.
15   - if (!exampleItem) {
16   - throw new Meteor.Error(500, 'Error 500: Not Found', 'No documents found.');
17   - }
18   -
19   - // Return either the result or the error.
20   - return exampleItem;
21   - }
22   -});
both/methods/remove/collection.js
... ... @@ -0,0 +1,11 @@
  1 +Meteor.methods({
  2 + removeMethod( argument ) {
  3 + check( argument, String );
  4 +
  5 + try {
  6 + Collection.remove( argument );
  7 + } catch( exception ) {
  8 + return exception;
  9 + }
  10 + }
  11 +});
... ...
both/methods/remove/example.js
... ... @@ -1,20 +0,0 @@
1   -/*
2   -* Methods: Remove - Example
3   -* Example of a method used for removing a document from the database.
4   -*/
5   -
6   -Meteor.methods({
7   - exampleRemoveMethod: function(argument){
8   - // Check the argument. Assuming a String type here.
9   - check(argument, String);
10   -
11   - // Perform the remove.
12   - try {
13   - var exampleId = Example.remove(argument);
14   - return exampleId;
15   - } catch(exception) {
16   - // If an error occurs, return it to the client.
17   - return exception;
18   - }
19   - }
20   -});
both/methods/update/collection.js
... ... @@ -0,0 +1,14 @@
  1 +Meteor.methods({
  2 + updateMethod( argument ) {
  3 + check( argument, Object );
  4 +
  5 + try {
  6 + var documentId = Collection.update( argument._id, {
  7 + $set: { 'key': argument.key }
  8 + });
  9 + return documentId;
  10 + } catch( exception ) {
  11 + return exception;
  12 + }
  13 + }
  14 +});
... ...
both/methods/update/example.js
... ... @@ -1,24 +0,0 @@
1   -/*
2   -* Methods: Update - Example
3   -* Example of a method used for updating a document in the database.
4   -*/
5   -
6   -Meteor.methods({
7   - exampleUpdateMethod: function(argument){
8   - // Check the argument. Assuming an Object type here.
9   - check(argument, Object);
10   -
11   - // Perform the update.
12   - try {
13   - var exampleId = Example.update(argument._id, {
14   - $set: {
15   - "someKey": argument.someKey
16   - }
17   - });
18   - return exampleId;
19   - } catch(exception) {
20   - // If an error occurs, return it to the client.
21   - return exception;
22   - }
23   - }
24   -});
both/modules/startup.js
1   -var startup = function() {};
  1 +let startup = () => {};
2 2  
3 3 Modules.both.startup = startup;
... ...
1   -Meteor.startup( function() { Modules.both.startup(); } );
  1 +Meteor.startup( () => Modules.both.startup() );
... ...
client/helpers/template.js
1   -/*
2   -* UI Helpers
3   -* Define UI helpers for common template functionality.
4   -*/
5   -
6   -/*
7   -* Current Route
8   -* Return an active class if the currentRoute session variable name
9   -* (set in the appropriate file in /client/routes/) is equal to the name passed
10   -* to the helper in the template.
11   -*/
12   -
13   -UI.registerHelper('currentRoute', function(route){
14   - return Session.equals('currentRoute', route) ? 'active' : '';
  1 +Template.registerHelper( 'currentRoute', ( route ) => {
  2 + return Session.equals( 'currentRoute', route ) ? 'active' : '';
15 3 });
... ...
client/modules/login.js
... ... @@ -0,0 +1,46 @@
  1 +let login = ( options ) => {
  2 + _validate( options.form, options.template );
  3 +};
  4 +
  5 +let _validate = ( form, template ) => {
  6 + $( form ).validate( validation( template ) );
  7 +};
  8 +
  9 +let validation = ( template ) => {
  10 + return {
  11 + rules: {
  12 + emailAddress: {
  13 + required: true,
  14 + email: true
  15 + },
  16 + password: {
  17 + required: true
  18 + }
  19 + },
  20 + messages: {
  21 + emailAddress: {
  22 + required: 'Need an email address here.',
  23 + email: 'Is this email address legit?'
  24 + },
  25 + password: {
  26 + required: 'Need a password here.'
  27 + }
  28 + },
  29 + submitHandler() { _handleLogin( template ); }
  30 + };
  31 +};
  32 +
  33 +let _handleLogin = ( template ) => {
  34 + let email = template.find( '[name="emailAddress"]' ).value,
  35 + password = template.find( '[name="password"]' ).value;
  36 +
  37 + Meteor.loginWithPassword( email, password, ( error ) => {
  38 + if ( error ) {
  39 + Bert.alert( error.reason, 'warning' );
  40 + } else {
  41 + Bert.alert( 'Logged in!', 'success' );
  42 + }
  43 + });
  44 +};
  45 +
  46 +Modules.client.login = login;
... ...
client/modules/recover-password.js
... ... @@ -0,0 +1,39 @@
  1 +let recoverPassword = ( options ) => {
  2 + _validate( options.form, options.template );
  3 +};
  4 +
  5 +let _validate = ( form, template ) => {
  6 + $( form ).validate( validation( template ) );
  7 +};
  8 +
  9 +let validation = ( template ) => {
  10 + return {
  11 + rules: {
  12 + emailAddress: {
  13 + required: true,
  14 + email: true
  15 + }
  16 + },
  17 + messages: {
  18 + emailAddress: {
  19 + required: 'Need an email address here.',
  20 + email: 'Is this email address legit?'
  21 + }
  22 + },
  23 + submitHandler() { _handleRecovery( template ); }
  24 + };
  25 +};
  26 +
  27 +let _handleRecovery = ( template ) => {
  28 + let email = template.find( '[name="emailAddress"]' ).value;
  29 +
  30 + Accounts.forgotPassword( { email: email }, ( error ) => {
  31 + if ( error ) {
  32 + Bert.alert( error.reason, 'warning' );
  33 + } else {
  34 + Bert.alert( 'Check your inbox for a reset link!', 'success' );
  35 + }
  36 + });
  37 +};
  38 +
  39 +Modules.client.recoverPassword = recoverPassword;
... ...
client/modules/reset-password.js
... ... @@ -0,0 +1,49 @@
  1 +let resetPassword = ( options ) => {
  2 + _validate( options.form, options.template );
  3 +};
  4 +
  5 +let _validate = ( form, template ) => {
  6 + $( form ).validate( validation( template ) );
  7 +};
  8 +
  9 +let validation = ( template ) => {
  10 + return {
  11 + rules: {
  12 + newPassword: {
  13 + required: true,
  14 + minlength: 6
  15 + },
  16 + repeatNewPassword: {
  17 + required: true,
  18 + minlength: 6,
  19 + equalTo: '[name="newPassword"]'
  20 + }
  21 + },
  22 + messages: {
  23 + newPassword: {
  24 + required: "Enter a new password, please.",
  25 + minlength: "Use at least six characters, please."
  26 + },
  27 + repeatNewPassword: {
  28 + required: "Repeat your new password, please.",
  29 + equalTo: "Hmm, your passwords don't match. Try again?"
  30 + }
  31 + },
  32 + submitHandler() { _handleReset( template ); }
  33 + };
  34 +};
  35 +
  36 +let _handleReset = ( template ) => {
  37 + var token = "Test",
  38 + password = template.find( '[name="newPassword"]' ).value;
  39 +
  40 + Accounts.resetPassword( token, password, ( error ) => {
  41 + if ( error ) {
  42 + Bert.alert( error.reason, 'danger' );
  43 + } else {
  44 + Bert.alert( 'Password reset!', 'success' );
  45 + }
  46 + });
  47 +};
  48 +
  49 +Modules.client.resetPassword = resetPassword;
... ...
client/modules/signup.js
... ... @@ -0,0 +1,50 @@
  1 +let signup = ( options ) => {
  2 + _validate( options.form, options.template );
  3 +};
  4 +
  5 +let _validate = ( form, template ) => {
  6 + $( form ).validate( validation( template ) );
  7 +};
  8 +
  9 +let validation = ( template ) => {
  10 + return {
  11 + rules: {
  12 + emailAddress: {
  13 + required: true,
  14 + email: true
  15 + },
  16 + password: {
  17 + required: true,
  18 + minlength: 6
  19 + }
  20 + },
  21 + messages: {
  22 + emailAddress: {
  23 + required: 'Need an email address here.',
  24 + email: 'Is this email address legit?'
  25 + },
  26 + password: {
  27 + required: 'Need a password here.',
  28 + minlength: 'Use at least six characters, please.'
  29 + }
  30 + },
  31 + submitHandler() { _handleSignup( template ); }
  32 + };
  33 +};
  34 +
  35 +let _handleSignup = ( template ) => {
  36 + let user = {
  37 + email: template.find( '[name="emailAddress"]' ).value,
  38 + password: template.find( '[name="password"]' ).value
  39 + };
  40 +
  41 + Accounts.createUser( user, ( error ) => {
  42 + if ( error ) {
  43 + Bert.alert( error.reason, 'danger' );
  44 + } else {
  45 + Bert.alert( 'Welcome!', 'success' );
  46 + }
  47 + });
  48 +};
  49 +
  50 +Modules.client.signup = signup;
... ...
client/modules/startup.js
1   -var startup = function() {};
  1 +let startup = () => {};
2 2  
3 3 Modules.client.startup = startup;
... ...
client/startup.js
1   -Meteor.startup( function() { Modules.client.startup(); } );
  1 +Meteor.startup( () => Modules.client.startup() );
... ...
client/stylesheets/application.scss
1 1 @import "tools/extends";
2 2  
  3 +@import "objects/forms";
  4 +
3 5 @import "components/login";
... ...
client/stylesheets/objects/_forms.scss
... ... @@ -0,0 +1,6 @@
  1 +label.error {
  2 + display: block;
  3 + margin-top: 10px;
  4 + font-weight: normal;
  5 + color: lighten( red, 20% );
  6 +}
... ...
client/templates/authenticated/index.html
1 1 <template name="index">
2   - <h1>Index</h1>
  2 + {{> loading}}
3 3 </template>
... ...
client/templates/authenticated/index.js
... ... @@ -0,0 +1,3 @@
  1 +Template.index.onCreated( () => {
  2 + Template.instance().subscribe( 'template', () => console.log( "Subscribed!" ) );
  3 +});
... ...
client/templates/globals/authenticated-navigation.html
... ... @@ -0,0 +1,10 @@
  1 +<template name="authenticatedNavigation">
  2 + <ul class="nav navbar-nav navbar-right">
  3 + <li class="dropdown">
  4 + <a href="#" class="dropdown-toggle" data-toggle="dropdown">{{currentUser.emails.[0].address}} <span class="caret"></span></a>
  5 + <ul class="dropdown-menu" role="menu">
  6 + <li class="logout"><a href="#">Logout</a></li>
  7 + </ul>
  8 + </li>
  9 + </ul>
  10 +</template>
... ...
client/templates/globals/header.html
... ... @@ -2,7 +2,7 @@
2 2 <nav class="navbar navbar-default" role="navigation">
3 3 <div class="container">
4 4 <div class="navbar-header">
5   - <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
  5 + <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse">
6 6 <span class="sr-only">Toggle navigation</span>
7 7 <span class="icon-bar"></span>
8 8 <span class="icon-bar"></span>
... ... @@ -10,23 +10,13 @@
10 10 </button>
11 11 <a class="navbar-brand" href="{{pathFor 'index'}}">Application Name</a>
12 12 </div>
13   - <div id="bs-example-navbar-collapse-1" class="collapse navbar-collapse">
  13 + <div id="navbar-collapse" class="collapse navbar-collapse">
14 14 {{#if currentUser}}
15   - <ul class="nav navbar-nav navbar-right">
16   - <li class="dropdown">
17   - <a href="#" class="dropdown-toggle" data-toggle="dropdown">{{currentUser.emails.[0].address}} <span class="caret"></span></a>
18   - <ul class="dropdown-menu" role="menu">
19   - <li class="logout"><a href="#">Logout</a></li>
20   - </ul>
21   - </li>
22   - </ul>
  15 + {{> authenticatedNavigation}}
23 16 {{else}}
24   - <ul class="nav navbar-nav navbar-right">
25   - <li class="{{currentRoute 'login'}}"><a href="{{pathFor 'login'}}">Login</a></li>
26   - <li class="{{currentRoute 'signup'}}"><a href="{{pathFor 'signup'}}">Sign Up</a></li>
27   - </ul>
  17 + {{> publicNavigation}}
28 18 {{/if}}
29   - </div> <!-- end .navbar-collapse -->
30   - </div> <!-- end .container-fluid -->
  19 + </div>
  20 + </div>
31 21 </nav>
32 22 </template>
... ...
client/templates/globals/header.js
1   -/*
2   -* Controller: Header
3   -* Template: /client/includes/_header.html
4   -*/
5   -
6   -/*
7   -* Created
8   -*/
9   -
10   -Template.header.onCreated(function(){
11   - // Code to run when template is created goes here.
12   -});
13   -
14   -/*
15   -* Rendered
16   -*/
17   -
18   -Template.header.onRendered(function() {
19   - // Code to run when template is rendered goes here.
20   -});
21   -
22   -/*
23   -* Helpers
24   -*/
25   -
26   -Template.header.helpers({
27   - example: function(){
28   - // Code to run for helper function.
29   - }
30   -});
31   -
32   -/*
33   -* Events
34   -*/
35   -
36 1 Template.header.events({
37   - 'click .logout': function(){
38   - Meteor.logout(function(error){
39   - if(error){
40   - Bert.alert(error.reason, 'danger');
  2 + 'click .logout' () {
  3 + Meteor.logout( ( error ) => {
  4 + if ( error ) {
  5 + Bert.alert( error.reason, 'warning' );
41 6 } else {
42   - Bert.alert('Succesfully logged out!', 'success');
  7 + Bert.alert( 'Logged out!', 'success' );
43 8 }
44 9 });
45 10 }
... ...
client/templates/globals/loading.html
... ... @@ -0,0 +1,18 @@
  1 +<template name="loading">
  2 + <svg version="1.1" id="loader-1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
  3 + width="40px" height="40px" viewBox="0 0 40 40" enable-background="new 0 0 40 40" xml:space="preserve">
  4 + <path opacity="1.0" fill="#eee" d="M20.201,5.169c-8.254,0-14.946,6.692-14.946,14.946c0,8.255,6.692,14.946,14.946,14.946
  5 + s14.946-6.691,14.946-14.946C35.146,11.861,28.455,5.169,20.201,5.169z M20.201,31.749c-6.425,0-11.634-5.208-11.634-11.634
  6 + c0-6.425,5.209-11.634,11.634-11.634c6.425,0,11.633,5.209,11.633,11.634C31.834,26.541,26.626,31.749,20.201,31.749z"/>
  7 + <path fill="#da5347" d="M26.013,10.047l1.654-2.866c-2.198-1.272-4.743-2.012-7.466-2.012h0v3.312h0
  8 + C22.32,8.481,24.301,9.057,26.013,10.047z">
  9 + <animateTransform attributeType="xml"
  10 + attributeName="transform"
  11 + type="rotate"
  12 + from="0 20 20"
  13 + to="360 20 20"
  14 + dur="0.5s"
  15 + repeatCount="indefinite"/>
  16 + </path>
  17 + </svg>
  18 +</template>
... ...
client/templates/globals/public-navigation.html
... ... @@ -0,0 +1,6 @@
  1 +<template name="publicNavigation">
  2 + <ul class="nav navbar-nav navbar-right">
  3 + <li class="{{currentRoute 'login'}}"><a href="{{pathFor 'login'}}">Login</a></li>
  4 + <li class="{{currentRoute 'signup'}}"><a href="{{pathFor 'signup'}}">Sign Up</a></li>
  5 + </ul>
  6 +</template>
... ...
client/templates/public/loading.html
... ... @@ -1,3 +0,0 @@
1   -<template name="loading">
2   - <p>Loading...</p>
3   -</template>
client/templates/public/login.html
1 1 <template name="login">
2 2 <div class="row">
3 3 <div class="col-xs-12 col-sm-6 col-md-4">
4   - <h3 class="page-header">Login</h3>
5   - <form id="application-login" class="login">
  4 + <h4 class="page-header">Login</h4>
  5 + <form id="login" class="login">
6 6 <div class="form-group">
7 7 <label for="emailAddress">Email Address</label>
8 8 <input type="email" name="emailAddress" class="form-control" placeholder="Email Address">
9   - </div> <!-- end .form-group -->
  9 + </div>
10 10 <div class="form-group">
11 11 <label for="password"><span class="pull-left">Password</span> <a class="pull-right" href="{{pathFor 'recover-password'}}">Forgot Password?</a></label>
12 12 <input type="password" name="password" class="form-control" placeholder="Password">
13   - </div> <!-- end .form-group -->
  13 + </div>
14 14 <div class="form-group">
15 15 <input type="submit" class="btn btn-success" value="Login">
16   - </div> <!-- end .form-group -->
  16 + </div>
17 17 </form>
18 18 <p>Don't have an account? <a href="{{pathFor 'signup'}}">Sign Up</a>.</p>
19   - </div> <!-- end .col-xs-12 -->
20   - </div> <!-- end .row -->
  19 + </div>
  20 + </div>
21 21 </template>
... ...
client/templates/public/login.js
1   -/*
2   -* Controller: Login
3   -* Template: /client/views/public/login.html
4   -*/
5   -
6   -/*
7   -* Created
8   -*/
9   -
10   -Template.login.onCreated(function(){
11   - // Code to run when template is created goes here.
12   -});
13   -
14   -/*
15   -* Rendered
16   -*/
17   -
18   -Template.login.onRendered(function(){
19   - $('#application-login').validate({
20   - rules: {
21   - emailAddress: {
22   - required: true,
23   - email: true
24   - },
25   - password: {
26   - required: true
27   - }
28   - },
29   - messages: {
30   - emailAddress: {
31   - required: "Please enter your email address to login.",
32   - email: "Please enter a valid email address."
33   - },
34   - password: {
35   - required: "Please enter your password to login."
36   - }
37   - },
38   - submitHandler: function(){
39   - // Grab the user's details.
40   - user = {
41   - email: $('[name="emailAddress"]').val(),
42   - password: $('[name="password"]').val()
43   - }
44   -
45   - // Log the user in.
46   - Meteor.loginWithPassword(user.email, user.password, function(error){
47   - if(error){
48   - Bert.alert(error.reason, 'danger');
49   - } else {
50   - Bert.alert('Logged in!', 'success');
51   - }
52   - });
53   - }
54   - });
  1 +Template.login.onRendered( () => {
  2 + Modules.client.login( { form: "#login", template: Template.instance() } );
55 3 });
56 4  
57   -/*
58   -* Helpers
59   -*/
60   -
61   -Template.login.helpers({
62   - example: function(){
63   - // Code to run for helper function.
64   - }
65   -});
66   -
67   -/*
68   -* Events
69   -*/
70   -
71 5 Template.login.events({
72   - 'submit form': function(e){
73   - // Prevent form from submitting.
74   - e.preventDefault();
75   - }
  6 + 'submit form': ( event ) => event.preventDefault()
76 7 });
... ...
client/templates/public/recover-password.html
1 1 <template name="recoverPassword">
2 2 <div class="row">
3 3 <div class="col-xs-12 col-sm-6 col-md-4">
4   - <h3 class="page-header">Recover Password</h3>
5   - <form id="application-recover-password" class="recover-password">
6   - <p>Enter the email address associated with your account below and click the "Recover Password" button. You will receive an email with further instructions on how to reset your password.</p>
  4 + <h4 class="page-header">Recover Password</h4>
  5 + <form id="recover-password" class="recover-password">
  6 + <p class="alert alert-info">Enter your email address below to receive a link to reset your password.</p>
7 7 <div class="form-group">
8 8 <label for="emailAddress">Email Address</label>
9 9 <input type="email" name="emailAddress" class="form-control" placeholder="Email Address">
10   - </div> <!-- end .form-group -->
  10 + </div>
11 11 <div class="form-group">
12 12 <input type="submit" class="btn btn-success" value="Recover Password">
13   - </div> <!-- end .form-group -->
  13 + </div>
14 14 </form>
15   - </div> <!-- end .col-xs-12 -->
16   - </div> <!-- end .row -->
  15 + </div>
  16 + </div>
17 17 </template>
... ...
client/templates/public/recover-password.js
1   -/*
2   -* Controller: Recover Password
3   -* Template: /client/views/public/recover-password.html
4   -*/
5   -
6   -/*
7   -* Created
8   -*/
9   -
10   -Template.recoverPassword.onCreated(function(){
11   - // Code to run when template is created goes here.
12   -});
13   -
14   -/*
15   -* Rendered
16   -*/
17   -
18   -
19   -Template.recoverPassword.onRendered(function(){
20   - $('#application-recover-password').validate({
21   - rules: {
22   - emailAddress: {
23   - required: true,
24   - email: true
25   - }
26   - },
27   - messages: {
28   - emailAddress: {
29   - required: "Please enter your email address to recover your password.",
30   - email: "Please enter a valid email address."
31   - }
32   - },
33   - submitHandler: function(){
34   - // Grab the user's email address.
35   - var email = $('[name="emailAddress"]').val();
36   -
37   - // Call the send reset password email method.
38   - Accounts.forgotPassword({email: email}, function(error){
39   - if(error){
40   - Bert.alert(error.reason, 'danger');
41   - } else {
42   - Bert.alert('Check your inbox for a reset link!', 'success');
43   - }
44   - });
45   - }
  1 +Template.recoverPassword.onRendered( () => {
  2 + Modules.client.recoverPassword({
  3 + form: "#recover-password",
  4 + template: Template.instance()
46 5 });
47 6 });
48 7  
49   -/*
50   -* Helpers
51   -*/
52   -
53   -Template.recoverPassword.helpers({
54   - example: function(){
55   - // Code to run for helper function.
56   - }
57   -});
58   -
59   -/*
60   -* Events
61   -*/
62   -
63 8 Template.recoverPassword.events({
64   - 'submit form': function(e){
65   - // Prevent form from submitting.
66   - e.preventDefault();
67   - }
  9 + 'submit form': ( event ) => event.preventDefault()
68 10 });
... ...
client/templates/public/reset-password.html
1 1 <template name="resetPassword">
2 2 <div class="row">
3 3 <div class="col-xs-12 col-sm-6 col-md-4">
4   - <h3 class="page-header">Reset Password</h3>
5   - <form id="application-reset-password" class="reset-password">
6   - <p>Enter your new password below and repeat it to confirm. This will reset your password and log you into the application.</p>
  4 + <h4 class="page-header">Reset Password</h4>
  5 + <form id="reset-password" class="reset-password">
  6 + <p class="alert alert-info">To reset your password, enter a new one below. You will be logged in with your new password.</p>
7 7 <div class="form-group">
8 8 <label for="newPassword">New Password</label>
9 9 <input type="password" name="newPassword" class="form-control" placeholder="New Password">
10   - </div> <!-- end .form-group -->
  10 + </div>
11 11 <div class="form-group">
12 12 <label for="password">Repeat New Password</label>
13 13 <input type="password" name="repeatNewPassword" class="form-control" placeholder="Password">
14   - </div> <!-- end .form-group -->
  14 + </div>
15 15 <div class="form-group">
16 16 <input type="submit" class="btn btn-success" value="Reset Password &amp; Login">
17   - </div> <!-- end .form-group -->
  17 + </div>
18 18 </form>
19   - </div> <!-- end .col-xs-12 -->
20   - </div> <!-- end .row -->
  19 + </div>
  20 + </div>
21 21 </template>
... ...
client/templates/public/reset-password.js
1   -/*
2   -* Controller: Reset Password
3   -* Template: /client/views/public/reset-password.html
4   -*/
5   -
6   -/*
7   -* Created
8   -*/
9   -
10   -Template.resetPassword.onCreated(function(){
11   - // Code to run when template is created goes here.
12   -});
13   -
14   -/*
15   -* Rendered
16   -*/
17   -
18   -Template.resetPassword.onRendered(function(){
19   - $('#application-reset-password').validate({
20   - rules: {
21   - newPassword: {
22   - required: true,
23   - minlength: 6
24   - },
25   - repeatNewPassword: {
26   - required: true,
27   - minlength: 6,
28   - equalTo: "[name='newPassword']"
29   - }
30   - },
31   - messages: {
32   - newPassword: {
33   - required: "Please enter a new password.",
34   - minlength: "Please use at least six characters."
35   - },
36   - repeatNewPassword: {
37   - required: "Please repeat your new password.",
38   - equalTo: "Your password do not match. Please try again."
39   - }
40   - },
41   - submitHandler: function(){
42   - // Grab the user's reset token and new password.
43   - var token = Session.get('resetPasswordToken'),
44   - password = $('[name="newPassword"]').val();
45   -
46   - // Reset the user's password.
47   - Accounts.resetPassword(token, password, function(error){
48   - if(error){
49   - Bert.alert(error.reason, 'danger');
50   - } else {
51   - Bert.alert('Password successfully reset!', 'success');
52   - Session.set('resetPasswordToken', null);
53   - }
54   - });
55   - }
  1 +Template.resetPassword.onRendered( () => {
  2 + Modules.client.resetPassword({
  3 + form: "#reset-password",
  4 + template: Template.instance()
56 5 });
57 6 });
58 7  
59   -/*
60   -* Helpers
61   -*/
62   -
63   -Template.resetPassword.helpers({
64   - example: function(){
65   - // Code to run for helper function.
66   - }
67   -});
68   -
69   -/*
70   -* Events
71   -*/
72   -
73 8 Template.resetPassword.events({
74   - 'submit form': function(e){
75   - // Prevent form from submitting.
76   - e.preventDefault();
77   - }
  9 + 'submit form': ( event ) => event.preventDefault()
78 10 });
... ...
client/templates/public/signup.html
1 1 <template name="signup">
2 2 <div class="row">
3 3 <div class="col-xs-12 col-sm-6 col-md-4">
4   - <h3 class="page-header">Sign Up</h3>
5   - <form id="application-signup" class="signup">
  4 + <h4 class="page-header">Sign Up</h4>
  5 + <form id="signup" class="signup">
6 6 <div class="form-group">
7 7 <label for="emailAddress">Email Address</label>
8 8 <input type="email" name="emailAddress" class="form-control" placeholder="Email Address">
9   - </div> <!-- end .form-group -->
  9 + </div>
10 10 <div class="form-group">
11 11 <label for="password">Password</label>
12 12 <input type="password" name="password" class="form-control" placeholder="Password">
13   - </div> <!-- end .form-group -->
  13 + </div>
14 14 <div class="form-group">
15 15 <input type="submit" class="btn btn-success" value="Sign Up">
16   - </div> <!-- end .form-group -->
  16 + </div>
17 17 </form>
18 18 <p>Already have an account? <a href="{{pathFor 'login'}}">Log In</a>.</p>
19   - </div> <!-- end .col-xs-12 -->
20   - </div> <!-- end .row -->
  19 + </div>
  20 + </div>
21 21 </template>
... ...
client/templates/public/signup.js
1   -/*
2   -* Controller: Signup
3   -* Template: /client/views/public/signup.html
4   -*/
5   -
6   -/*
7   -* Created
8   -*/
9   -
10   -Template.signup.onCreated(function(){
11   - // Code to run when template is created goes here.
12   -});
13   -
14   -/*
15   -* Rendered
16   -*/
17   -
18   -Template.signup.onRendered(function(){
19   - $('#application-signup').validate({
20   - rules: {
21   - emailAddress: {
22   - required: true,
23   - email: true
24   - },
25   - password: {
26   - required: true,
27   - minlength: 6
28   - }
29   - },
30   - messages: {
31   - emailAddress: {
32   - required: "Please enter your email address to sign up.",
33   - email: "Please enter a valid email address."
34   - },
35   - password: {
36   - required: "Please enter a password to sign up.",
37   - minlength: "Please use at least six characters."
38   - }
39   - },
40   - submitHandler: function(){
41   - // Grab the user's details.
42   - user = {
43   - email: $('[name="emailAddress"]').val(),
44   - password: $('[name="password"]').val()
45   - }
46   -
47   - // Create the user's account.
48   - Accounts.createUser({email: user.email, password: user.password}, function(error){
49   - if(error){
50   - Bert.alert(error.reason, 'danger');
51   - } else {
52   - Bert.alert('Welcome!', 'success');
53   - }
54   - });
55   - }
  1 +Template.signup.onRendered( () => {
  2 + Modules.client.signup({
  3 + form: "#signup",
  4 + template: Template.instance()
56 5 });
57 6 });
58 7  
59   -/*
60   -* Helpers
61   -*/
62   -
63   -Template.signup.helpers({
64   - example: function(){
65   - // Code to run for helper function.
66   - }
67   -});
68   -
69   -/*
70   -* Events
71   -*/
72   -
73 8 Template.signup.events({
74   - 'submit form': function(e){
75   - // Prevent form from submitting.
76   - e.preventDefault();
77   - }
  9 + 'submit form': ( event ) => event.preventDefault()
78 10 });
... ...
collections/collection.js
... ... @@ -0,0 +1,13 @@
  1 +Collection = new Meteor.Collection( 'collection' );
  2 +
  3 +Collection.allow({
  4 + insert: () => false,
  5 + update: () => false,
  6 + remove: () => false
  7 +});
  8 +
  9 +Collection.deny({
  10 + insert: () => true,
  11 + update: () => true,
  12 + remove: () => true
  13 +});
... ...
collections/example.js
... ... @@ -1,39 +0,0 @@
1   -Example = new Meteor.Collection('example');
2   -
3   -/*
4   -* Allow
5   -*/
6   -
7   -Example.allow({
8   - insert: function(){
9   - // Disallow inserts on the client by default.
10   - return false;
11   - },
12   - update: function(){
13   - // Disallow updates on the client by default.
14   - return false;
15   - },
16   - remove: function(){
17   - // Disallow removes on the client by default.
18   - return false;
19   - }
20   -});
21   -
22   -/*
23   -* Deny
24   -*/
25   -
26   -Example.deny({
27   - insert: function(){
28   - // Deny inserts on the client by default.
29   - return true;
30   - },
31   - update: function(){
32   - // Deny updates on the client by default.
33   - return true;
34   - },
35   - remove: function(){
36   - // Deny removes on the client by default.
37   - return true;
38   - }
39   -});
collections/users.js
1   -/*
2   -* Allow
3   -*/
4   -
5 1 Meteor.users.allow({
6   - insert: function(){
7   - // Disallow user inserts on the client by default.
8   - return false;
9   - },
10   - update: function(){
11   - // Disallow user updates on the client by default.
12   - return false;
13   - },
14   - remove: function(){
15   - // Disallow user removes on the client by default.
16   - return false;
17   - }
  2 + insert: () => false,
  3 + update: () => false,
  4 + remove: () => false
18 5 });
19 6  
20   -/*
21   -* Deny
22   -*/
23   -
24 7 Meteor.users.deny({
25   - insert: function(){
26   - // Deny user inserts on the client by default.
27   - return true;
28   - },
29   - update: function(){
30   - // Deny user updates on the client by default.
31   - return true;
32   - },
33   - remove: function(){
34   - // Deny user removes on the client by default.
35   - return true;
36   - }
  8 + insert: () => true,
  9 + update: () => true,
  10 + remove: () => true
37 11 });
... ...
server/admin/reset-password.js
... ... @@ -0,0 +1,12 @@
  1 +Accounts.emailTemplates.resetPassword.siteName = () => "Application Name";
  2 +Accounts.emailTemplates.resetPassword.from = () => "Application Name <admin@application.com>";
  3 +Accounts.emailTemplates.resetPassword.subject = () => "[Application Name] Reset Your Password";
  4 +
  5 +Accounts.emailTemplates.resetPassword.text = ( user, url ) => {
  6 + let emailAddress = user.emails[0].address,
  7 + urlWithoutHash = url.replace( '#/', '' ),
  8 + supportEmail = "support@application.com",
  9 + emailBody = `A password reset has been requested for the account related to this address (${emailAddress}). To reset the password, visit the following link:\n\n${urlWithoutHash}\n\n If you did not request this reset, please ignore this email. If you feel something is wrong, please contact our support team: ${supportEmail}.`;
  10 +
  11 + return emailBody;
  12 +};
... ...
server/admin/startup-functions/browser-policies.js
... ... @@ -1,9 +0,0 @@
1   -/*
2   -* Browser Policies
3   -* Browser policy customizations.
4   -* Documentation: https://atmospherejs.com/meteor/browser-policy
5   -*/
6   -
7   -customBrowserPolicies = function(){
8   - // Define any custom browser policies here.
9   -}
server/admin/startup-functions/test-accounts.js
... ... @@ -1,29 +0,0 @@
1   -/*
2   -* Generate Test Accounts
3   -* Creates a collection of test accounts automatically on startup.
4   -*/
5   -
6   -generateTestAccounts = function(){
7   - // Create an array of user accounts.
8   - var users = [
9   - { name: "Admin", email: "admin@admin.com", password: "password" }
10   - ]
11   -
12   - // Loop through array of user accounts.
13   - for(i=0; i < users.length; i++){
14   - // Check if the user already exists in the DB.
15   - var userEmail = users[i].email,
16   - checkUser = Meteor.users.findOne({"emails.address": userEmail});
17   -
18   - // If an existing user is not found, create the account.
19   - if ( !checkUser ) {
20   - Accounts.createUser({
21   - email: userEmail,
22   - password: users[i].password,
23   - profile: {
24   - name: users[i].name
25   - }
26   - });
27   - }
28   - }
29   -}
server/admin/startup.js
... ... @@ -1,15 +0,0 @@
1   -/*
2   -* Startup
3   -* Functions to run on server startup. Note: this file is for calling functions
4   -* only. Define functions in /server/admin/startup-functions.
5   -*/
6   -
7   -Meteor.startup(function(){
8   -
9   - // Custom Browser Policies
10   - customBrowserPolicies();
11   -
12   - // Generate Test Accounts
13   - generateTestAccounts();
14   -
15   -});
server/email/templates/reset-password.js
... ... @@ -1,20 +0,0 @@
1   -/*
2   -* Reset Password Email Template
3   -* Override Meteor defaults when sending a reset password email.
4   -*/
5   -
6   -// Set name and from email.
7   -Accounts.emailTemplates.resetPassword.siteName = "Application Name";
8   -Accounts.emailTemplates.resetPassword.from = "Application Admin Email <admin@application.com>";
9   -
10   -// Set a subject for the reset password email.
11   -Accounts.emailTemplates.resetPassword.subject = function(user){
12   - return "[Application Name] Reset Your Password";
13   -}
14   -
15   -// Set the body of the reset password email.
16   -Accounts.emailTemplates.resetPassword.text = function(user, url){
17   - var email = user.emails[0].address,
18   - removeHash = url.replace('#/', '');
19   - return "A password reset has been requested for the account related to this address(" + email + "). To reset the password, visit the following link:\n\n" + removeHash + "\n\n If you did not request this reset, please ignore this email. If you feel something is wrong, please contact support: admin@application.com."
20   -}
server/modules/generate-accounts.js
... ... @@ -0,0 +1,63 @@
  1 +let administrators = [
  2 + {
  3 + name: { first: 'Admin', last: 'McAdmin' },
  4 + email: 'admin@admin.com',
  5 + password: 'password'
  6 + }
  7 +];
  8 +
  9 +let generateAccounts = () => {
  10 + let fakeUserCount = 5,
  11 + usersExist = _checkIfAccountsExist( administrators.length + fakeUserCount );
  12 +
  13 + if ( !usersExist ) {
  14 + _createUsers( administrators );
  15 + _createUsers( _generateFakeUsers( fakeUserCount ) );
  16 + }
  17 +};
  18 +
  19 +let _checkIfAccountsExist = ( count ) => {
  20 + let userCount = Meteor.users.find().count();
  21 + return userCount < count ? false : true;
  22 +};
  23 +
  24 +let _createUsers = ( users ) => {
  25 + for ( let i = 0; i < users.length; i++ ) {
  26 + let user = users[ i ],
  27 + userExists = _checkIfUserExists( user.email );
  28 +
  29 + if ( !userExists ) {
  30 + _createUser( user );
  31 + }
  32 + }
  33 +};
  34 +
  35 +let _checkIfUserExists = ( email ) => {
  36 + return Meteor.users.findOne( { 'emails.address': email } );
  37 +};
  38 +
  39 +let _createUser = ( user ) => {
  40 + Accounts.createUser({
  41 + email: user.email,
  42 + password: user.password,
  43 + profile: {
  44 + name: user.name
  45 + }
  46 + });
  47 +};
  48 +
  49 +let _generateFakeUsers = ( count ) => {
  50 + let users = [];
  51 +
  52 + for ( let i = 0; i < count; i++ ) {
  53 + users.push({
  54 + name: { first: faker.name.firstName(), last: faker.name.lastName() },
  55 + email: faker.internet.email(),
  56 + password: 'password'
  57 + });
  58 + }
  59 +
  60 + return users;
  61 +};
  62 +
  63 +Modules.server.generateAccounts = generateAccounts;
... ...
server/modules/startup.js
1   -var startup = function() {};
  1 +let startup = () => {
  2 + _setBrowserPolicies();
  3 + _generateAccounts();
  4 +};
  5 +
  6 +var _setBrowserPolicies = () => {};
  7 +
  8 +var _generateAccounts = () => Modules.server.generateAccounts();
2 9  
3 10 Modules.server.startup = startup;
... ...
server/publications/example.js
... ... @@ -1,17 +0,0 @@
1   -/*
2   -* Publications: Example
3   -* Data publications for the Example collection.
4   -*/
5   -
6   -Meteor.publish('examplePublication', function(){
7   - // If need be, Meteor gives us access to the current user via this.userId.
8   - // Example below shows using this.userId to locate documents where the
9   - // owner field is equal to a userId. Additionally, a fields projection is
10   - // added to specify which fields you want to return (where 1 = true and
11   - // 0 = false).
12   -
13   - var user = this.userId;
14   - var data = Example.find({"owner": user}, {fields: {"owner": 1}});
15   -
16   - return data;
17   -});
server/publications/template.js
... ... @@ -0,0 +1,3 @@
  1 +Meteor.publish( 'template', function() {
  2 + return Collection.find( { 'owner': this.userId }, { fields: { 'owner': 1 } } );
  3 +});
... ...
server/startup.js
1   -Meteor.startup( function() { Modules.server.startup(); } );
  1 +Meteor.startup( () => Modules.server.startup() );
... ...