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 # Homework - Client Side
# Variables and utility stuff
notes = new Meteor.Collection "notes" notes = new Meteor.Collection "notes"
getUser = -> Meteor.user() getUser = -> Meteor.user()
myNotes = -> Meteor.subscribe "my-notes" deleteAccount = ->
Meteor.call 'deleteMe', (r) -> if r is yes then Router.go 'home'
amIValid = -> amIValid = ->
return no unless getUser() return no unless getUser()
return yes for mail in getUser().emails when mail.verified is yes; no 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 "loggingIn", -> Meteor.loggingIn()
UI.registerHelper "email", -> getUser().emails[0].address UI.registerHelper "email", -> getUser().emails[0].address
UI.registerHelper "verified", -> amIValid() UI.registerHelper "verified", -> amIValid()
# Router # 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 Router.configure
layoutTemplate: 'layout' layoutTemplate: 'layout'
loadingTemplate: 'loading' loadingTemplate: 'loading'
notFoundTemplate: '404' notFoundTemplate: '404'
Router.map -> Router.map ->
@route 'home', @route 'home',
onBeforeAction: (pause)-> onBeforeAction: ->
# Dispatch user to the right landing page based on his account status
if getUser() if getUser()
if amIValid() is yes then Router.go 'notes' else Router.go 'verifyEmail' if amIValid() is yes then Router.go 'notes' else Router.go 'verifyEmail'
else Router.go 'login'
path: '/' 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', @route 'notes',
waitOn: -> Meteor.subscribe "my-notes" waitOn: -> Meteor.subscribe "my-notes"
onBeforeAction: -> onBeforeAction: ->
@ -38,21 +57,23 @@ Router.map ->
onBeforeAction: -> onBeforeAction: ->
if @params.token? if @params.token?
Accounts.verifyEmail @params.token, (err) -> Accounts.verifyEmail @params.token, (err) ->
if err if err then errCallback err else Router.go 'home'
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'
@route '404', path: '*' @route '404', path: '*'
logoutCallback = (err) -> if err then errCallback err else Router.go 'home'
# Client Templates # 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 # Menu
Template.menu.at_home = -> Template.menu.events
if Router.current() then return "active" if Router.current().path is "/notes" 'click .go-home': -> Router.go 'home'
'click .go-account': -> Router.go 'account'
'click .go-archive': -> Router.go 'archive'
# User Interface # User Interface
Template.account.events Template.account.events
@ -76,7 +97,7 @@ Template.notelist.events
# Note Editor # Note Editor
Template.editor.note = -> Router.current.data() # Only when we're in /note/:_id Template.editor.note = -> Router.current.data() # Only when we're in /note/:_id
saveCurrentNote = (t,e) -> 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, notes.update Router.current().data()._id,
$set: $set:
title: t.find('.editor-title').value title: t.find('.editor-title').value
@ -89,10 +110,6 @@ Template.editor.events
# Notifications # Notifications
alerts = [] alerts = []
alertDep = new Deps.Dependency alertDep = new Deps.Dependency
errCallback = (err) ->
if err.reason
showError msg: err.reason
else showErrror msg: err
# Show a notification # Show a notification
notify = (data) -> notify = (data) ->
alerts.push alerts.push
@ -128,33 +145,41 @@ Template.verifyEmail.events
if err if err
errCallback err errCallback err
else showError { type:"success", msg: "Confirmation email sent" } else showError { type:"success", msg: "Confirmation email sent" }
'click #btn-delete': -> 'click #btn-delete': -> deleteAccount()
Meteor.call 'deleteMe', (r) -> if r is yes then Router.go 'home'
'click #btn-logout': -> Meteor.logout logoutCallback 'click #btn-logout': -> Meteor.logout logoutCallback
# Login and Register # Login
pressLogin = (template) -> loginRequest = (e,template) ->
mail = template.find('#mail').value; pass = template.find('#pass').value if e and e.keyCode isnt 13 then return
Meteor.loginWithPassword mail, pass, errCallback 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 Template.login.events
# Login 'keypress .login': (e,template) -> loginRequest e,template
'keypress .login': (e,template) -> if e.keyCode is 13 then pressLogin template 'click #login-btn': (e,template) -> loginRequest null,template
'click #login': (e,template) -> pressLogin template
# Register # Register
'click #register': (e,template) -> registerRequest = (e,template) ->
mail = template.find('#mail').value; pass = template.find('#pass').value if e and e.keyCode isnt 13 then return
if not mail mail = template.find('#r-mail').value; pass = template.find('#r-pass').value
showError msg: "Please enter an Email" pass2 = template.find('#r-pass-2').value
else if not pass if not mail
showError msg: "Please enter a password" showError msg: "Please enter an Email"
else if pass.length < 8 else if not pass
showError msg: "Password too short" showError msg: "Please enter a password"
else # Sending actual registration request else if pass.length < 8
try showError msg: "Password too short"
Accounts.createUser { else if pass2 isnt pass
email: mail, showError msg: "The passwords don't match"
password: pass else # Sending actual registration request
}, (err) -> if err then errCallback err else Router.go 'confirmEmail' try
catch err Accounts.createUser {
showError msg: err 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

View File

@ -1,6 +1,7 @@
/* Generics and bootstrap classes */ /* Generics and bootstrap classes */
input { input {
text-align:center; text-align:center;
max-width: 400px;
} }
.page-header { .page-header {
@ -15,10 +16,22 @@ input {
.custom-link { color: #999; } .custom-link { color: #999; }
.custom-link:hover { color: #101010;} .custom-link:hover { color: #101010;}
.cool-header {
margin-bottom: 22px;
}
.btns-account {
margin-top: 20px;
}
.menu-item { .menu-item {
margin-right: 100px; margin-left:100px; margin-right: 100px; margin-left:100px;
} }
.in-bt {
margin-bottom: 10px;
}
.note { .note {
padding-bottom: 5px; padding-bottom: 5px;
} }
@ -71,7 +84,7 @@ input {
margin-top: 10px; margin-top: 10px;
} }
.btn-auth { .btn-fix {
width: 100px; width: 100px;
} }
@ -106,7 +119,3 @@ input {
max-width: 250px; max-width: 250px;
margin-bottom: 10px; margin-bottom: 10px;
} }
#mail {
margin-bottom: 10px;
}

View File

@ -1,4 +1,5 @@
<!-- Homework UI Templates --> <!-- Homework UI Templates -->
<template name="layout"> <template name="layout">
<div class="container"> <div class="container">
<div class="page-header"> <div class="page-header">
@ -7,7 +8,6 @@
</h1> </h1>
</div> </div>
<div class="center-block" id="ui-container"> <div class="center-block" id="ui-container">
{{> error}}
{{> yield}} {{> yield}}
</div> </div>
<hr> <hr>
@ -17,20 +17,22 @@
</template> </template>
<template name="menu"> <template name="menu">
<ul class="nav nav-pills nav-justified"> <div align="center" class="menu-container">
<li class="menu-item {{at_archive}}"><a href="/archive">Archive</a></li> <div class="btn-group">
<li class="menu-item {{at_home}}"><a href="/notes">Home</a></li> <button type="button" class="btn btn-success go-archive">
<li class="menu-item {{at_account}}"><a href="/account">Account</a></li> <i class="fa fa-book fa-inverse"></i> Archive
</ul> </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>
<template name="notes"> <template name="notes">{{> error }} {{> notelist }} {{> menu}}</template>
{{> notelist }} <hr> {{> account }} <template name="note">{{> error }} {{> editor }} {{> notelist }} <hr> {{> menu}}</template>
</template>
<template name="note">
{{> editor }} {{> notelist }} <hr> {{> account }}
</template>
<template name="noteadder"> <template name="noteadder">
<div align="center"> <div align="center">
@ -58,35 +60,59 @@
{{> noteadder }} {{> noteadder }}
</template> </template>
<template name="auth"> <template name="login">
<div align="center"> <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}} {{#if loggingIn}}
{{> loading}} {{> loading}}
{{else}} {{else}}
<input type="text" id="mail" class="form-control login" placeholder="Email"> <input type="text" id="l-mail" class="form-control login in-bt" placeholder="Email">
<input type="password" id="pass" class="form-control login" placeholder="Password"> <input type="password" id="l-pass" class="form-control login in-bt" placeholder="Password">
<br>
{{/if}} {{/if}}
<p>Password must be at least 8 characters. Email must be a valid email</p>
{{#unless loggingIn}} {{#unless loggingIn}}
<button type="button" id="register" class="btn-auth btn btn-success">Register</button> <a role="button" href="{{pathFor 'register'}}" class="btn-fix btn btn-success">Register</a>
<button type="button" id="login" class="btn-auth btn btn-primary">Login</button> <a role="button" id="login-btn" class="btn-fix btn btn-primary">Login</a>
{{/unless}} {{/unless}}
</div> </div>
</template> </template>
<template name="account"> <template name="register">
{{#if loggingIn}} {{> loading}} {{/if}}
<div align="center"> <div align="center">
<p>{{email}}</p> <h3 class="cool-header"><i class="fa fa-user fa-2x"></i><br>New Account</h3>
<button type="button" id="btn-logout" class="btn btn-danger">Logout</button> {{#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> </div>
</template> </template>
<template name="verifyEmail"> <template name="verifyEmail">
<div align="center"> <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> <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"> <input type="text" id="token-field" class="form-control" placeholder="Token">
<div align="center" class="buttons"> <div align="center" class="buttons">
<button type="button" class="btn btn-warning btn-ver" id="btn-resend">Resend Email</button> <button type="button" class="btn btn-warning btn-ver" id="btn-resend">Resend Email</button>
@ -98,7 +124,6 @@
</template> </template>
<template name="editor"> <template name="editor">
<div align="center">{{> error }}</div>
{{#if _id}} {{#if _id}}
<div class="panel panel-info"> <div class="panel panel-info">
<div class="panel-heading"> <div class="panel-heading">
@ -118,29 +143,29 @@
</template> </template>
<template name="notifications"> <template name="notifications">
{{#each notification}} {{#each notification}}
<div class="alert alert-{{type}} notification"> <div class="alert alert-{{type}} notification">
<p align="center">{{msg}}</p> <p align="center">{{msg}}</p>
<button type="button" class="close close-notification">&times;</button> <button type="button" class="close close-notification">&times;</button>
</div> </div>
{{/each}} {{/each}}
</template> </template>
<template name="error"> <template name="error">
{{#if error}} {{#if error}}
<div align="center"><div class="alert alert-{{error.type}} error"> <div align="center"><div class="alert alert-{{error.type}} error">
<p align="center">{{error.msg}}</p> <p align="center">{{error.msg}}</p>
<button type="button" class="close close-error">&times;</button> <button type="button" class="close close-error">&times;</button>
</div></div> </div></div>
{{/if}} {{/if}}
</template> </template>
<template name="ribbon"> <template name="ribbon">
<div class="github-fork-ribbon-wrapper right"> <div class="github-fork-ribbon-wrapper right">
<div class="github-fork-ribbon"> <div class="github-fork-ribbon">
<a href="http://github.com/fazo96/homework">Fork me on GitHub</a> <a href="http://github.com/fazo96/homework">Fork me on GitHub</a>
</div>
</div> </div>
</div>
</template> </template>
<template name="loading"> <template name="loading">
@ -159,6 +184,7 @@
<template name="404"> <template name="404">
<div align="center"> <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> </div>
</template> </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 # Homework - Server Side
notes = share.notes
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
console.log "Started Homework server!" console.log "Started Homework server!"
if process.env.MAIL_URL if process.env.MAIL_URL
console.log "Sending emails using "+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 } 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 # Returns true if the user has verified at least one email address
userValidated = (user) -> userValidated = (user) ->
if not user? if not user?
@ -37,13 +22,6 @@ Meteor.publish "my-notes", ->
if userValidated getUser(@userId) if userValidated getUser(@userId)
notes.find userId: @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 # Methods that the clients can invoke
Meteor.methods Meteor.methods
resendConfirmEmail: -> resendConfirmEmail: ->