1
0
mirror of https://github.com/fazo96/homework.git synced 2025-01-09 12:10:08 +01:00

improved UI, fixed #1, fixed #6

This commit is contained in:
fazo96 2014-05-31 18:09:56 +02:00
parent a841e3d9b2
commit 6b42e24e57
5 changed files with 178 additions and 118 deletions

View File

@ -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,28 +145,33 @@ 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
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 {
@ -158,3 +180,6 @@ Template.auth.events
}, (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

View File

@ -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;
}

View File

@ -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}}
{{#each notification}}
<div class="alert alert-{{type}} notification">
<p align="center">{{msg}}</p>
<button type="button" class="close close-notification">&times;</button>
</div>
{{/each}}
{{/each}}
</template>
<template name="error">
{{#if 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">&times;</button>
</div></div>
{{/if}}
{{/if}}
</template>
<template name="ribbon">
<div class="github-fork-ribbon-wrapper right">
<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
View 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

View File

@ -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: ->