UNPKG

alpha-one

Version:

ideas about recurring tasks in Web- and Backend-Application building

415 lines (381 loc) 20.4 kB
############################################################################################################ USERDB = require 'coffeenode-userdb' OPTIONS = require 'coffeenode-options' TRM = require 'coffeenode-trm' rpr = TRM.rpr.bind TRM badge = 'α1/templates' log = TRM.get_logger 'plain', badge info = TRM.get_logger 'info', badge whisper = TRM.get_logger 'whisper', badge alert = TRM.get_logger 'alert', badge debug = TRM.get_logger 'debug', badge warn = TRM.get_logger 'warn', badge help = TRM.get_logger 'help', badge BITSNPIECES = require 'coffeenode-bitsnpieces' #........................................................................................................... TEACUP = require 'coffeenode-teacup' #........................................................................................................... app_info = OPTIONS.get_app_info() app_key = app_info[ 'name' ] #........................................................................................................... A1 = require './main' user_db = USERDB.new_db() #........................................................................................................... USERDB.validate_is_running user_db #=========================================================================================================== # TEACUP NAMESPACE ACQUISITION #----------------------------------------------------------------------------------------------------------- for name_ of TEACUP eval "#{name_} = TEACUP[ #{rpr name_} ]" #=========================================================================================================== # LAYOUT #----------------------------------------------------------------------------------------------------------- # TEMPLATES = {} @layout = ( request, response, content, done ) -> log TRM.blue 'layout' return @[ request[ 'A1' ]?[ 'layout' ] ? 'plain' ] request, response, content, done #----------------------------------------------------------------------------------------------------------- @plain = ( request, response, content, done ) -> log TRM.blue 'plain' O = request[ 'A1' ] page_style = O[ 'page-style' ] ? 'plain' title = O[ 'title' ] ? 'welcome' session = request[ 'session' ] has_session = session? if has_session user = session[ 'user' ] logged_in = user? else user = null logged_in = no #......................................................................................................... return render => DOCTYPE 5 HTML => #..................................................................................................... HEAD => COMMENT '#head-top' META charset: 'utf-8' TITLE title RAW '<!--[if lt IE 9]>' SCRIPT src: '/common/jquery.com/jquery-1.10.2.js' RAW '<![endif]--><!--[if gte IE 9]><!-->' SCRIPT src: '/common/jquery.com/jquery-2.0.3.js' RAW '<!--<![endif]-->' #=================================================================================================== # Client-Side Cookies #................................................................................................... SCRIPT src: '/common/github.com_carhartl_jquery-cookie/jquery.cookie.js' #=================================================================================================== # Notifications #................................................................................................... ### https://github.com/ehynds/jquery-notify ### ### http://www.erichynds.com/blog/a-jquery-ui-growl-ubuntu-notification-widget ### SCRIPT src: '/common/jquery.com/jquery-ui-1.10.3/ui/jquery.ui.widget.js' SCRIPT src: '/common/erichynds.com/jquery-notify/src/jquery.notify.js' LINK rel: 'stylesheet', href: '/common/erichynds.com/jquery-notify/ui.notify.css' RAW """ <style> .ui-notify-message h1 { font-size: 120%; font-weight: normal; font-style: italic; } </style>""" COFFEESCRIPT -> #................................................................................................. after = ( seconds, method ) -> setTimeout method, seconds * 1000 #................................................................................................. notification_options = sticky: no click: ( event, notification ) -> notification.close() #................................................................................................. notify = ( title, text ) -> message = title: title text: text #............................................................................................... ( $ '#notify-wrap' ).notify 'create', 'notify-default' message notification_options #................................................................................................. ( $ 'document' ).ready -> ################################################################################################ ( $ '#notify-wrap' ).notify speed: 250 # i.e. effect duration expires: 5000 # fades out after so many ms ################################################################################################ if ( flash_messages = $.cookie 'flash-messages' )? flash_messages = JSON.parse flash_messages for idx in [ flash_messages.length - 1 .. 0 ] by -1 [ title, text, ] = flash_messages[ idx ] notify title, text flash_messages.length = 0 $.cookie 'flash-messages', '[]' #............................................................................................... # after 0.5, -> notify "Attention Y'All", 'the sublime message is talking to you' # after 1.5, -> notify "Attention Y'All", 'hear hear' #=================================================================================================== # ( META name: 'description', content: O[ 'description' ] ) if O[ 'description' ]? # LINK rel: 'stylesheet', href: '/public/cssnormalize-min.css' # LINK rel: 'stylesheet', href: '/public/mingkwai.css' # LINK rel: 'stylesheet', href: '/public/font-awesome-4.0.0/css/font-awesome.css' LINK rel: 'shortcut icon', href: '/public/favicon.ico?v6' # SCRIPT src: '/public/github_com_carhartl_jquery-cookie/jquery.cookie.js' # SCRIPT src: '/public/coffeenode-tagtool/main.js' # SCRIPT src: '/public/mingkwai.js' COMMENT '#head-bottom' #..................................................................................................... BODY ".#{page_style}", => COMMENT '#body-top' #=================================================================================================== # Notifications #................................................................................................... # <div id="notify-wrap" style="display: none;"><div id="notify-default"><h1>#{title}</h1><p>#{text}</p></div></div> DIV '#notify-wrap', style: 'display: none;', => DIV '#notify-default', => H1 => TEXT '\#{title}' P => TEXT '\#{text}' #=================================================================================================== DIV id: 'login-reminder', => if logged_in TEXT "you are logged in as #{request[ 'session' ][ 'user' ]}" else null #................................................................................................... RAW content if logged_in DIV => A href: '/logout', 'log out' else unless request[ 'url' ] is '/login' DIV => A href: '/login', 'log in' DIV => A href: '/', 'home' DIV => A href: '/restricted', 'restricted' DIV => A href: '/welcome', 'welcome' DIV => A href: '/goodbye', 'goodbye' DIV => A href: '/notfound', 'not found' DIV => A href: '/contact', 'contact' DIV => A href: '/imprint', 'imprint' DIV => A href: '/privacy', 'privacy' #................................................................................................... COMMENT '#body-bottom' #=========================================================================================================== # GENERAL VIEWS #----------------------------------------------------------------------------------------------------------- @homepage = ( request, response, next ) -> log TRM.blue 'homepage' O = request[ 'A1' ] O[ 'title' ] = 'Homepage for Alpha-One' #......................................................................................................... return render => H1 'Home' DIV "homepage for alpha-one" #----------------------------------------------------------------------------------------------------------- @welcome = ( request, response, next ) -> log TRM.blue 'welcome' O = request[ 'A1' ] O[ 'title' ] = 'Welcome!' #......................................................................................................... return render => H1 'Welcome' DIV "welcome to alpha-one" #----------------------------------------------------------------------------------------------------------- @goodbye = ( request, response, next ) -> log TRM.blue 'goodbye' O = request[ 'A1' ] O[ 'title' ] = 'Good-Bye' #......................................................................................................... return render => H1 'Good-Bye' DIV "good-bye from alpha-one" #----------------------------------------------------------------------------------------------------------- @not_found = ( request, response ) -> log TRM.blue 'not_found' O = request[ 'A1' ] O[ 'title' ] = 'Not Found' A1.HTTP.not_found request, response #......................................................................................................... return render => H1 '404' DIV "nothing found for #{request[ 'url' ]}" #=========================================================================================================== # BOILERPLATE VIEWS #----------------------------------------------------------------------------------------------------------- @contact = ( request, response ) -> log TRM.blue 'contact' O = request[ 'A1' ] O[ 'title' ] = 'contact' #......................................................................................................... return render => H1 'Contact' DIV "Contact us at info@example.com" #----------------------------------------------------------------------------------------------------------- @imprint = ( request, response ) -> log TRM.blue 'imprint' O = request[ 'A1' ] O[ 'title' ] = 'imprint' request[ 'A1' ][ 'flash' ] 'Welcome...', '...to the mighty Alpha-One Imprint page!' request[ 'A1' ][ 'flash' ] 'Info', 'We accept pull requests' #......................................................................................................... return render => H1 'Imprint' DIV "The maintainers of this site are somewhat responsible for some content." #----------------------------------------------------------------------------------------------------------- @privacy = ( request, response ) -> log TRM.blue 'privacy' O = request[ 'A1' ] O[ 'title' ] = 'privacy' #......................................................................................................... return render => H1 'Privacy' DIV "Yeah, privacy. Well, we take it seriously." #=========================================================================================================== # LOGIN / LOGOUT VIEWS #----------------------------------------------------------------------------------------------------------- ### TAINT these things should probably go into their own module, no? ### #----------------------------------------------------------------------------------------------------------- @login_get = ( request, response ) -> log TRM.blue 'login_get' O = request[ 'A1' ] O[ 'title' ] = 'Log In or Sign Up' comes_from = request[ 'cookies' ]?[ 'comes-from' ] session = request[ 'session' ] has_session = session? #......................................................................................................... if has_session login_count = session[ 'login-count' ] += 1 else login_count = 0 #......................................................................................................... return render => #....................................................................................................... if comes_from? request[ 'A1' ][ 'flash' ] 'For your information...', "You must log in to visit #{comes_from}" #....................................................................................................... if login_count > 1 DIV "attempt to log in: ##{login_count}" #....................................................................................................... H1 'Log In or Sign Up' DIV => FORM '#login-form', method: 'post', action: '/login', => FIELDSET => LEGEND "Log In" DIV => TEXT_INPUT label: "Your email or user name:", name: 'uid-hint' autofocus: yes required: yes DIV => PASSWORD label: "Your password:" DIV => SUBMIT label: "submit" DIV => FORM '#signup-form', method: 'post', action: '/signup', => FIELDSET => LEGEND "Sign Up" DIV => EMAIL label: "Your email:", autocomplete: 'off' DIV => TEXT_INPUT label: "Your user name:", autocomplete: 'off' name: 'name' autofocus: yes required: yes DIV => PASSWORD label: "Your password:", autocomplete: 'off' DIV => CONFIRM_PASSWORD label: "Your password again:", autocomplete: 'off' DIV => SUBMIT label: "submit" #----------------------------------------------------------------------------------------------------------- @login_post = ( request, response, done ) -> log TRM.blue 'login_post' uid_hint = request[ 'body' ][ 'uid-hint' ] password = request[ 'body' ][ 'password' ] info '©11k', 'query arguments:', request[ 'body' ] #......................................................................................................... USERDB.authenticate_user user_db, { name: uid_hint, }, password, ( error, user_known, password_matches ) => ### TAINT code duplication ### if error? if error[ 'message' ] is 'connect ECONNREFUSED' alert """\nthe CoffeeNode UserDB specified as \n#{rpr user_db}\ncan not be accessed""" else alert error return done new Error error.stack log '©34e', ( TRM.gold uid_hint ), ( TRM.blue password ), ( TRM.truth user_known ), ( TRM.truth password_matches ) #....................................................................................................... if user_known and password_matches TRM.dir '©34e', (require 'express').session ### TAINT what to do if request.session does not exist? ### request.session.regenerate => request.session.user = uid_hint # log TRM.lime '©15z', response.headerSent # if response.headerSent? A1.HTTP.back_to request, response, '/welcome' request.session[ 'just-logged-in' ] = yes message = "You have been logged in as user #{rpr uid_hint}" request[ 'A1' ][ 'flash' ] "Welcome", message done message #....................................................................................................... else log TRM.lime '©15z', response.headerSent # if response.headerSent? A1.HTTP.redirect request, response, '/login' message = "Your ID #{rpr uid_hint} or password did not match; please try again." request[ 'A1' ][ 'flash' ] "Login failed", message done message return null #----------------------------------------------------------------------------------------------------------- @signup_post = ( request, response, done ) -> log TRM.blue 'signup_post' email = request[ 'body' ][ 'email' ] name = request[ 'body' ][ 'name' ] password = request[ 'body' ][ 'password' ] password_r = request[ 'body' ][ 'password-r' ] #......................................................................................................... unless password is password_r message = "your passwords do not match" A1.HTTP.redirect request, response, '/login' done message #......................................................................................................... ### TAINT check for password strength (maybe only on client) ### ### TAINT check for email plausibility ### ### TAINT check for email uniqueness ### ### TAINT think up a UID generation method ### entry = 'name': name 'uid': "#{email}-#{1 * new Date()}" # placeholder for a better method 'password': password 'email': email #......................................................................................................... USERDB.create_user user_db, entry, ( error, result ) -> ### TAINT code duplication ### if error? if error[ 'message' ] is 'connect ECONNREFUSED' alert """\nthe CoffeeNode UserDB specified as \n#{rpr user_db}\ncan not be accessed""" else alert error return done new Error error.stack #....................................................................................................... ### TAINT what to do if request.session does not exist? ### request.session.regenerate => request.session.user = entry[ 'uid' ] message = "you have been registered as #{entry[ 'uid' ]}" request[ 'A1' ][ 'flash' ] "Welcome", message A1.HTTP.back_to request, response, '/welcome-new-user' done message #......................................................................................................... return null #----------------------------------------------------------------------------------------------------------- @logout = ( request, response, done ) -> log TRM.blue 'restricted' request.session.destroy => A1.HTTP.back_to request, response, '/goodbye' done "You have been logged out." #......................................................................................................... return null #=========================================================================================================== # RESCTRICTED VIEWS #----------------------------------------------------------------------------------------------------------- @restricted = ( request, response ) -> log TRM.blue 'restricted' O = request[ 'A1' ] O[ 'title' ] = 'Restricted Area' uid = request.session.user #......................................................................................................... return render => H1 'Restricted Area' DIV "This is the Restricted Area"