Skip to content

Commit

Permalink
first initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Waler Chau authored and Waler Chau committed Jun 5, 2017
1 parent aa27432 commit f46580f
Show file tree
Hide file tree
Showing 18 changed files with 544 additions and 29 deletions.
2 changes: 2 additions & 0 deletions .meteor/packages
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,5 @@ [email protected] # Server-side component of the `meteor shell` comm
accounts-password
session
fourseven:scss
practicalmeteor:mocha
react-meteor-data
2 changes: 1 addition & 1 deletion client/main.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<head>
<title>Meteor BoilerPlate</title>
<title>Todo Apps</title>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
</head>

Expand Down
74 changes: 74 additions & 0 deletions import/api/notes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import {Meteor} from 'meteor/meteor'
import {Mongo} from 'meteor/mongo'

import moment from 'moment'
import SimpleSchema from 'simpl-schema';

export const Notes = new Mongo.Collection('notes')

if(Meteor.isServer){
Meteor.publish('notes', function(){
return Notes.find({userId:this.userId})
})
}

Meteor.methods({
'notes.insert'(){
if(!this.userId){
throw new Meteor.Error('not-authenticated')
}
return Notes.insert({
title:'',
body:'',
userId: this.userId,
updatedAt: moment().valueOf()
})
},

'notes.remove'(_id){
if(!this.userId){
throw new Meteor.Error('not-authenticated')
}
try{
new SimpleSchema({
_id:{
type:String,
min:1
}
}).validate({_id})
}catch(e){
console.log('e',e,e.message);
throw new Meteor.Error(400, e.message)
}

Notes.remove({_id, userId:this.userId});
},
'notes.update'(_id, updates){
if(!this.userId){
throw new Meteor.Error('not-authenticated')
}

try{
new SimpleSchema({
_id:{
type:String,
min:1
},
title:{
type:String,
optional:true
},
body:{
type:String,
optional:true
}
}).validate({_id, ...updates})
}catch(e){
console.log('e',e,e.message);
throw new Meteor.Error(400, e.message)
}

Notes.update({_id, userId:this.userId },{$set:{updatedAt: moment().valueOf(), ...updates}})

}
})
116 changes: 116 additions & 0 deletions import/api/notes.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import {Meteor} from 'meteor/meteor'
import expect from 'expect';

import {Notes} from './notes'

if(Meteor.isServer){
describe('notes',function(){

const noteOne = {
_id:'testNoteId1',
title:'My Title',
body:'My body for note',
userId: 'testUserId1',
updatedAt: 0
}

const noteTwo = {
_id:'testNoteId2',
title:'My Title 2',
body:'My body for note 2',
userId: 'testUserId2',
updatedAt: 0
}

beforeEach(function(){
Notes.remove({});
Notes.insert(noteOne)
Notes.insert(noteTwo)
})

it('should insert new note', function(){
const userId = 'testId'
const _id = Meteor.server.method_handlers['notes.insert'].apply({userId:'testId'})

expect(Notes.findOne({_id, userId})).toExist();
})

it('should not insert note if not authentciated',function(){
expect(()=>{
Meteor.server.method_handlers['notes.insert']();
}).toThrow();
})

it('should remove note', function(){
Meteor.server.method_handlers['notes.remove'].apply({userId:noteOne.userId},[noteOne._id])

expect(Notes.findOne({_id: noteOne._id})).toNotExist();
})

it('should not remove note if unauthenticated', function(){
expect(()=>{
Meteor.server.method_handlers['notes.remove'].apply({},[noteOne._id])
}).toThrow();
})

it('should not remove note if invalid _id', function(){
expect(()=>{
Meteor.server.method_handlers['notes.remove'].apply({userId:noteOne.userId},[])
}).toThrow();
})

it('should update note', function(){
const title = 'This is an updated title'

Meteor.server.method_handlers['notes.update'].apply({userId:noteOne.userId},[noteOne._id, {title}])

const note = Notes.findOne(noteOne._id)

expect(note.updatedAt).toBeGreaterThan(0)
expect(note).toInclude({title,body:noteOne.body})
})

it('should throw err if extra updates', function(){
expect(()=>{
Meteor.server.method_handlers['notes.remove'].apply({userId:noteOne.userId},[noteOne._id, title:'new title', name:'name'])
}).toThrow();
})

it('should not update note if user is not creater', function(){
const title = 'This is an updated title'
Meteor.server.method_handlers['notes.remove'].apply({userId:'testid'},[noteOne._id, {title}])
const note = Notes.findOne(noteOne._id)
expect(note).toInclude(noteOne)
})

it('should not update note if unauthenticated', function(){
expect(()=>{
Meteor.server.method_handlers['notes.update'].apply({},[noteOne._id])
}).toThrow();
})

it('should not update note if invalid _id', function(){
expect(()=>{
Meteor.server.method_handlers['notes.update'].apply({userId:noteOne.userId},[])
}).toThrow();
})

it('should return a users notes', function(){
const res = Meteor.server.publish_handlers.notes.apply({userId:'testUserId2'})
const notes = res.fetch();

expect(notes.length).toBe(1)
expect(notes[0]).toEqual(noteTwo)
})

it('should return zero notes', function(){
const res = Meteor.server.publish_handlers.notes.apply({userId:'testUserId3'})
const notes = res.fetch();

expect(notes.length).toBe(0)
})



})
}
35 changes: 19 additions & 16 deletions import/api/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,22 @@ import { Meteor } from 'meteor/meteor';
import SimpleSchema from 'simpl-schema';
import {Accounts} from 'meteor/accounts-base';

// Accounts.validateNewUser((user)=>{
// const email = user.emails[0].address;
// try{
// new SimpleSchema({
// email:{
// type:String,
// regEx: SimpleSchema.RegEx.Email
// }
// }).validate({email})
// } catch(e){
// console.log('e',e,e.message);
// throw new Meteor.Error(400, e.message)
// }
//
// return true;
// })
export const validateNewUser = (user)=>{
const email = user.emails[0].address;
try{
new SimpleSchema({
email:{
type:String,
regEx: SimpleSchema.RegEx.Email
}
}).validate({email})
}catch(e){
console.log('e',e,e.message);
throw new Meteor.Error(400, e.message)
}

return true;
}
if(Meteor.isServer){
Accounts.validateNewUser(validateNewUser)
}
63 changes: 63 additions & 0 deletions import/api/users.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import {Meteor} from 'meteor/meteor'
import expect from 'expect'

import {validateNewUser} from './users'

if(Meteor.isServer){
describe('users', function(){
it('should allow valid email address',function(){
const testUser = {
emails:[
{address:'[email protected]'}
]
}
const res = validateNewUser(testUser)

expect(res).toBe(true);
})

it('should reject invalid email', function(){
const testUser={
emails:[
{address:'testtests'}
]
}

expect(()=>{
validateNewUser(testUser);
}).toThrow();
})
})

}

// const add = (a,b) => {
// if (typeof b !== 'number') return a + a;
// else return a+b;
// }
//
// const square = (a)=>{
// return a*a;
// }
//
// describe('add', function(){
// it('should add two number', function(){
// const res = add(3,4)
// // if(res!==7) throw new Error('Sum was not equal to expected value')
// expect(res).toBe(20);
// });
//
// it('should double a single number' , function(){
// const res = add(33);
// // if(res!==88) throw new Error('Number was not doubled')
// expect(res).toBe(66);
// })
//
// })
//
// describe('square', function(){
// it('should square a number', function(){
// const res = square(11);
// expect(res).toBe(121);
// })
// })
3 changes: 2 additions & 1 deletion import/ui/dashboard.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import React from 'react';

import PrivateHeader from './privateHeader';
import NoteList from './noteList'

export default () =>{
return(
<div>
<PrivateHeader title="Dashboard"/>
<div className="page-content">
Dasboard page content
<NoteList/>
</div>
</div>
)
Expand Down
16 changes: 14 additions & 2 deletions import/ui/login.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import {Meteor} from 'meteor/meteor';
import React from 'react';
import {Link} from 'react-router-dom';
import {createContainer} from 'meteor/react-meteor-data'
import PropTypes from 'prop-types'

export default class Login extends React.Component{
export class Login extends React.Component{
constructor(props){
super(props);

Expand All @@ -17,7 +19,7 @@ export default class Login extends React.Component{
let email = this.refs.email.value.trim();
let password = this.refs.password.value.trim();

Meteor.loginWithPassword({email},password,(err)=>{
this.props.loginWithPassword({email},password,(err)=>{
err? this.setState({error: err.reason}):this.setState({error: ""})
})

Expand All @@ -43,3 +45,13 @@ export default class Login extends React.Component{
)
}
}

Login.propTypes={
loginWithPassword:PropTypes.func
}

export default createContainer(()=>{
return{
loginWithPassword: Meteor.loginWithPassword()
}
}, Login)
Loading

0 comments on commit f46580f

Please sign in to comment.