mirror of
https://github.com/fazo96/homework.git
synced 2025-01-10 12:14:22 +01:00
parent
a841e3d9b2
commit
6b42e24e57
@ -1,28 +1,47 @@
|
||||
# Homework - Client Side
|
||||
|
||||
# Variables and utility stuff
|
||||
notes = new Meteor.Collection "notes"
|
||||
getUser = -> Meteor.user()
|
||||
myNotes = -> Meteor.subscribe "my-notes"
|
||||
deleteAccount = ->
|
||||
Meteor.call 'deleteMe', (r) -> if r is yes then Router.go 'home'
|
||||
amIValid = ->
|
||||
return no unless getUser()
|
||||
return yes for mail in getUser().emails when mail.verified is yes; no
|
||||
|
||||
# Common Helpers
|
||||
# Common Helpers for the Templates
|
||||
UI.registerHelper "loggingIn", -> Meteor.loggingIn()
|
||||
UI.registerHelper "email", -> getUser().emails[0].address
|
||||
UI.registerHelper "verified", -> amIValid()
|
||||
|
||||
# Router
|
||||
###
|
||||
Important: before rendering and routing, always "dispatch" the user to 'home'
|
||||
if he doesn't have the permission to access the current route. 'home' then
|
||||
dispatches the user to the correct landing page.
|
||||
Routes are client side, but even if by hacking the client you can access pages
|
||||
without being logged in, it's impossible to inteact with data because
|
||||
the server checks all the things before providing the data. It's safe.
|
||||
###
|
||||
Router.configure
|
||||
layoutTemplate: 'layout'
|
||||
loadingTemplate: 'loading'
|
||||
notFoundTemplate: '404'
|
||||
Router.map ->
|
||||
@route 'home',
|
||||
onBeforeAction: (pause)->
|
||||
onBeforeAction: ->
|
||||
# Dispatch user to the right landing page based on his account status
|
||||
if getUser()
|
||||
if amIValid() is yes then Router.go 'notes' else Router.go 'verifyEmail'
|
||||
else Router.go 'login'
|
||||
path: '/'
|
||||
template: 'auth'
|
||||
@route 'login',
|
||||
onBeforeAction: -> Router.go 'home' if getUser()
|
||||
@route 'register',
|
||||
onBeforeAction: -> Router.go 'home' if getUser()
|
||||
@route 'account',
|
||||
onBeforeAction: ->
|
||||
if not getUser() then Router.go 'home'
|
||||
@route 'notes',
|
||||
waitOn: -> Meteor.subscribe "my-notes"
|
||||
onBeforeAction: ->
|
||||
@ -38,21 +57,23 @@ Router.map ->
|
||||
onBeforeAction: ->
|
||||
if @params.token?
|
||||
Accounts.verifyEmail @params.token, (err) ->
|
||||
if err
|
||||
Router.go 'home'
|
||||
errCallback err
|
||||
else Router.go 'notes'
|
||||
else if not getUser()
|
||||
Router.go 'home'
|
||||
else if amIValid() is yes then Router.go 'notes'
|
||||
if err then errCallback err else Router.go 'home'
|
||||
@route '404', path: '*'
|
||||
|
||||
logoutCallback = (err) -> if err then errCallback err else Router.go 'home'
|
||||
|
||||
# Client Templates
|
||||
|
||||
# Some utilities
|
||||
logoutCallback = (err) -> if err then errCallback err else Router.go 'home'
|
||||
errCallback = (err) ->
|
||||
if err.reason
|
||||
showError msg: err.reason
|
||||
else showErrror msg: err
|
||||
|
||||
# Menu
|
||||
Template.menu.at_home = ->
|
||||
if Router.current() then return "active" if Router.current().path is "/notes"
|
||||
Template.menu.events
|
||||
'click .go-home': -> Router.go 'home'
|
||||
'click .go-account': -> Router.go 'account'
|
||||
'click .go-archive': -> Router.go 'archive'
|
||||
|
||||
# User Interface
|
||||
Template.account.events
|
||||
@ -76,7 +97,7 @@ Template.notelist.events
|
||||
# Note Editor
|
||||
Template.editor.note = -> Router.current.data() # Only when we're in /note/:_id
|
||||
saveCurrentNote = (t,e) ->
|
||||
if e and e.keyCode isnt 13 then return;
|
||||
if e and e.keyCode isnt 13 then return
|
||||
notes.update Router.current().data()._id,
|
||||
$set:
|
||||
title: t.find('.editor-title').value
|
||||
@ -89,10 +110,6 @@ Template.editor.events
|
||||
# Notifications
|
||||
alerts = []
|
||||
alertDep = new Deps.Dependency
|
||||
errCallback = (err) ->
|
||||
if err.reason
|
||||
showError msg: err.reason
|
||||
else showErrror msg: err
|
||||
# Show a notification
|
||||
notify = (data) ->
|
||||
alerts.push
|
||||
@ -128,33 +145,41 @@ Template.verifyEmail.events
|
||||
if err
|
||||
errCallback err
|
||||
else showError { type:"success", msg: "Confirmation email sent" }
|
||||
'click #btn-delete': ->
|
||||
Meteor.call 'deleteMe', (r) -> if r is yes then Router.go 'home'
|
||||
'click #btn-delete': -> deleteAccount()
|
||||
'click #btn-logout': -> Meteor.logout logoutCallback
|
||||
|
||||
# Login and Register
|
||||
pressLogin = (template) ->
|
||||
mail = template.find('#mail').value; pass = template.find('#pass').value
|
||||
Meteor.loginWithPassword mail, pass, errCallback
|
||||
# Login
|
||||
loginRequest = (e,template) ->
|
||||
if e and e.keyCode isnt 13 then return
|
||||
mail = template.find('#l-mail').value; pass = template.find('#l-pass').value
|
||||
Meteor.loginWithPassword mail, pass, (err) ->
|
||||
if err then errCallback err else Router.go 'home'
|
||||
|
||||
Template.auth.events
|
||||
# Login
|
||||
'keypress .login': (e,template) -> if e.keyCode is 13 then pressLogin template
|
||||
'click #login': (e,template) -> pressLogin template
|
||||
# Register
|
||||
'click #register': (e,template) ->
|
||||
mail = template.find('#mail').value; pass = template.find('#pass').value
|
||||
if not mail
|
||||
showError msg: "Please enter an Email"
|
||||
else if not pass
|
||||
showError msg: "Please enter a password"
|
||||
else if pass.length < 8
|
||||
showError msg: "Password too short"
|
||||
else # Sending actual registration request
|
||||
try
|
||||
Accounts.createUser {
|
||||
email: mail,
|
||||
password: pass
|
||||
}, (err) -> if err then errCallback err else Router.go 'confirmEmail'
|
||||
catch err
|
||||
showError msg: err
|
||||
Template.login.events
|
||||
'keypress .login': (e,template) -> loginRequest e,template
|
||||
'click #login-btn': (e,template) -> loginRequest null,template
|
||||
|
||||
# Register
|
||||
registerRequest = (e,template) ->
|
||||
if e and e.keyCode isnt 13 then return
|
||||
mail = template.find('#r-mail').value; pass = template.find('#r-pass').value
|
||||
pass2 = template.find('#r-pass-2').value
|
||||
if not mail
|
||||
showError msg: "Please enter an Email"
|
||||
else if not pass
|
||||
showError msg: "Please enter a password"
|
||||
else if pass.length < 8
|
||||
showError msg: "Password too short"
|
||||
else if pass2 isnt pass
|
||||
showError msg: "The passwords don't match"
|
||||
else # Sending actual registration request
|
||||
try
|
||||
Accounts.createUser {
|
||||
email: mail,
|
||||
password: pass
|
||||
}, (err) -> if err then errCallback err else Router.go 'confirmEmail'
|
||||
catch err
|
||||
showError msg: err
|
||||
Template.register.events
|
||||
'click #register-btn': (e,t) -> registerRequest null,t
|
||||
'keypress .register': (e,t) -> registerRequest e,t
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* Generics and bootstrap classes */
|
||||
input {
|
||||
text-align:center;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
@ -15,10 +16,22 @@ input {
|
||||
.custom-link { color: #999; }
|
||||
.custom-link:hover { color: #101010;}
|
||||
|
||||
.cool-header {
|
||||
margin-bottom: 22px;
|
||||
}
|
||||
|
||||
.btns-account {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
margin-right: 100px; margin-left:100px;
|
||||
}
|
||||
|
||||
.in-bt {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.note {
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
@ -71,7 +84,7 @@ input {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.btn-auth {
|
||||
.btn-fix {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
@ -106,7 +119,3 @@ input {
|
||||
max-width: 250px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#mail {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
<!-- Homework UI Templates -->
|
||||
|
||||
<template name="layout">
|
||||
<div class="container">
|
||||
<div class="page-header">
|
||||
@ -7,7 +8,6 @@
|
||||
</h1>
|
||||
</div>
|
||||
<div class="center-block" id="ui-container">
|
||||
{{> error}}
|
||||
{{> yield}}
|
||||
</div>
|
||||
<hr>
|
||||
@ -17,20 +17,22 @@
|
||||
</template>
|
||||
|
||||
<template name="menu">
|
||||
<ul class="nav nav-pills nav-justified">
|
||||
<li class="menu-item {{at_archive}}"><a href="/archive">Archive</a></li>
|
||||
<li class="menu-item {{at_home}}"><a href="/notes">Home</a></li>
|
||||
<li class="menu-item {{at_account}}"><a href="/account">Account</a></li>
|
||||
</ul>
|
||||
<div align="center" class="menu-container">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-success go-archive">
|
||||
<i class="fa fa-book fa-inverse"></i> Archive
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary go-home">
|
||||
<i class="fa fa-home fa-inverse"></i> Home
|
||||
</button>
|
||||
<button type="button" class="btn btn-warning go-account">
|
||||
<i class="fa fa-user fa-inverse"></i> Account
|
||||
</button>
|
||||
</div></div>
|
||||
</template>
|
||||
|
||||
<template name="notes">
|
||||
{{> notelist }} <hr> {{> account }}
|
||||
</template>
|
||||
|
||||
<template name="note">
|
||||
{{> editor }} {{> notelist }} <hr> {{> account }}
|
||||
</template>
|
||||
<template name="notes">{{> error }} {{> notelist }} {{> menu}}</template>
|
||||
<template name="note">{{> error }} {{> editor }} {{> notelist }} <hr> {{> menu}}</template>
|
||||
|
||||
<template name="noteadder">
|
||||
<div align="center">
|
||||
@ -58,35 +60,59 @@
|
||||
{{> noteadder }}
|
||||
</template>
|
||||
|
||||
<template name="auth">
|
||||
<template name="login">
|
||||
<div align="center">
|
||||
<p>Register a new Account or login</p>
|
||||
<h3 class="cool-header"><i class="fa fa-sign-in fa-2x"></i><br>Login</h3>
|
||||
{{> error}}
|
||||
{{#if loggingIn}}
|
||||
{{> loading}}
|
||||
{{else}}
|
||||
<input type="text" id="mail" class="form-control login" placeholder="Email">
|
||||
<input type="password" id="pass" class="form-control login" placeholder="Password">
|
||||
<br>
|
||||
<input type="text" id="l-mail" class="form-control login in-bt" placeholder="Email">
|
||||
<input type="password" id="l-pass" class="form-control login in-bt" placeholder="Password">
|
||||
{{/if}}
|
||||
<p>Password must be at least 8 characters. Email must be a valid email</p>
|
||||
{{#unless loggingIn}}
|
||||
<button type="button" id="register" class="btn-auth btn btn-success">Register</button>
|
||||
<button type="button" id="login" class="btn-auth btn btn-primary">Login</button>
|
||||
<a role="button" href="{{pathFor 'register'}}" class="btn-fix btn btn-success">Register</a>
|
||||
<a role="button" id="login-btn" class="btn-fix btn btn-primary">Login</a>
|
||||
{{/unless}}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template name="account">
|
||||
{{#if loggingIn}} {{> loading}} {{/if}}
|
||||
<template name="register">
|
||||
<div align="center">
|
||||
<p>{{email}}</p>
|
||||
<button type="button" id="btn-logout" class="btn btn-danger">Logout</button>
|
||||
<h3 class="cool-header"><i class="fa fa-user fa-2x"></i><br>New Account</h3>
|
||||
{{#if loggingIn}}
|
||||
{{> loading}}
|
||||
{{else}}
|
||||
<p>Password must be at least 8 characters. You will need to confirm your email.</p>
|
||||
{{> error}}
|
||||
<input type="text" id="r-mail" class="form-control register in-bt" placeholder="Email">
|
||||
<input type="password" id="r-pass" class="form-control register in-bt" placeholder="Password">
|
||||
<input type="password" id="r-pass-2" class="form-control register pass-rep in-bt" placeholder="Repeat Password">
|
||||
<button type="button" id="register-btn" class="btn-fix btn btn-primary">Create</button>
|
||||
<a role="button" href="{{pathFor 'home'}}" class="btn-fix btn btn-success">Home</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template name="account">
|
||||
<div align="center">
|
||||
<h3 class="cool-header"><i class="fa fa-user fa-2x"></i><br>{{email}}</h3>
|
||||
{{> menu}}
|
||||
<div class="btn-group btns-account">
|
||||
<button type="button" id="btn-logout" class="btn btn-warning">
|
||||
<i class="fa fa-sign-out fa-inverse"></i> Logout
|
||||
</button>
|
||||
<button type="button" id="btn-delete-me" class="btn btn-danger">
|
||||
<i class="fa fa-exclamation-circle fa-inverse"></i> Delete
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template name="verifyEmail">
|
||||
<div align="center">
|
||||
<p>Insert the token you received by email at the address {{email}} here, or click the link in the email we sent you.</p>
|
||||
{{> error}}
|
||||
<input type="text" id="token-field" class="form-control" placeholder="Token">
|
||||
<div align="center" class="buttons">
|
||||
<button type="button" class="btn btn-warning btn-ver" id="btn-resend">Resend Email</button>
|
||||
@ -98,7 +124,6 @@
|
||||
</template>
|
||||
|
||||
<template name="editor">
|
||||
<div align="center">{{> error }}</div>
|
||||
{{#if _id}}
|
||||
<div class="panel panel-info">
|
||||
<div class="panel-heading">
|
||||
@ -118,29 +143,29 @@
|
||||
</template>
|
||||
|
||||
<template name="notifications">
|
||||
{{#each notification}}
|
||||
<div class="alert alert-{{type}} notification">
|
||||
<p align="center">{{msg}}</p>
|
||||
<button type="button" class="close close-notification">×</button>
|
||||
</div>
|
||||
{{/each}}
|
||||
{{#each notification}}
|
||||
<div class="alert alert-{{type}} notification">
|
||||
<p align="center">{{msg}}</p>
|
||||
<button type="button" class="close close-notification">×</button>
|
||||
</div>
|
||||
{{/each}}
|
||||
</template>
|
||||
|
||||
<template name="error">
|
||||
{{#if error}}
|
||||
<div align="center"><div class="alert alert-{{error.type}} error">
|
||||
<p align="center">{{error.msg}}</p>
|
||||
<button type="button" class="close close-error">×</button>
|
||||
</div></div>
|
||||
{{/if}}
|
||||
{{#if error}}
|
||||
<div align="center"><div class="alert alert-{{error.type}} error">
|
||||
<p align="center">{{error.msg}}</p>
|
||||
<button type="button" class="close close-error">×</button>
|
||||
</div></div>
|
||||
{{/if}}
|
||||
</template>
|
||||
|
||||
<template name="ribbon">
|
||||
<div class="github-fork-ribbon-wrapper right">
|
||||
<div class="github-fork-ribbon">
|
||||
<a href="http://github.com/fazo96/homework">Fork me on GitHub</a>
|
||||
<div class="github-fork-ribbon-wrapper right">
|
||||
<div class="github-fork-ribbon">
|
||||
<a href="http://github.com/fazo96/homework">Fork me on GitHub</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template name="loading">
|
||||
@ -159,6 +184,7 @@
|
||||
|
||||
<template name="404">
|
||||
<div align="center">
|
||||
<h2>Acciderbolina!<br><small>Page not found</small></h2>
|
||||
<h2><i class="fa fa-exclamation-triangle fa-2x"></i><br>
|
||||
Acciderbolina!<br><small>Page not found</small></h2>
|
||||
</div>
|
||||
</template>
|
||||
|
22
server/accounts.coffee
Normal file
22
server/accounts.coffee
Normal file
@ -0,0 +1,22 @@
|
||||
# Homework - Server side accounts code
|
||||
|
||||
validateEmail = (email) ->
|
||||
x = /^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/
|
||||
x.test email
|
||||
|
||||
Accounts.validateNewUser (user) ->
|
||||
mail = user.emails[0].address
|
||||
if Match.test(mail,String) is no or validateEmail(mail) is no
|
||||
throw new Meteor.Error 403, "Invalid Email"
|
||||
return yes
|
||||
|
||||
Accounts.config {
|
||||
sendVerificationEmail: true
|
||||
loginExpirationInDays: 1
|
||||
}
|
||||
|
||||
Accounts.emailTemplates.siteName = "Homework App"
|
||||
Accounts.emailTemplates.verifyEmail.text = (user,url) ->
|
||||
urlist = url.split('/'); token = urlist[urlist.length-1]
|
||||
'''Welcome to Homework! To activate your account, click on the \
|
||||
following link: http://homework.meteor.com/verify/'''+token
|
@ -1,9 +1,5 @@
|
||||
# Homework - Server Side
|
||||
|
||||
validateEmail = (email) ->
|
||||
expr = /^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/
|
||||
expr.test email
|
||||
|
||||
notes = share.notes
|
||||
console.log "Started Homework server!"
|
||||
if process.env.MAIL_URL
|
||||
console.log "Sending emails using "+process.env.MAIL_URL
|
||||
@ -14,17 +10,6 @@ notes = new Meteor.Collection "notes"
|
||||
|
||||
getUser = (id) -> Meteor.users.findOne { _id: id }
|
||||
|
||||
Accounts.config {
|
||||
sendVerificationEmail: true
|
||||
loginExpirationInDays: 1
|
||||
}
|
||||
|
||||
Accounts.emailTemplates.siteName = "Homework App";
|
||||
Accounts.emailTemplates.verifyEmail.text = (user,url) ->
|
||||
urlist = url.split('/'); token = urlist[urlist.length-1]
|
||||
'''Welcome to Homework! To activate your account, click on the \
|
||||
following link: http://homework.meteor.com/verify/'''+token
|
||||
|
||||
# Returns true if the user has verified at least one email address
|
||||
userValidated = (user) ->
|
||||
if not user?
|
||||
@ -37,13 +22,6 @@ Meteor.publish "my-notes", ->
|
||||
if userValidated getUser(@userId)
|
||||
notes.find userId: @userId
|
||||
|
||||
# Authentication
|
||||
Accounts.validateNewUser (user) ->
|
||||
mail = user.emails[0].address
|
||||
if Match.test(mail,String) is no or validateEmail(mail) is no
|
||||
throw new Meteor.Error 403, "Invalid Email"
|
||||
return yes
|
||||
|
||||
# Methods that the clients can invoke
|
||||
Meteor.methods
|
||||
resendConfirmEmail: ->
|
||||
|
Loading…
Reference in New Issue
Block a user