diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore index 7dccd97..9d53ccf 100644 --- a/.gitignore +++ b/.gitignore @@ -6,10 +6,11 @@ lib-cov *.out *.pid *.gz +*.sw[nomp] pids logs results node_modules -npm-debug.log \ No newline at end of file +npm-debug.log diff --git a/app/controllers/admin/sessions_controller.coffee b/app/controllers/admin/sessions_controller.coffee new file mode 100644 index 0000000..122fda4 --- /dev/null +++ b/app/controllers/admin/sessions_controller.coffee @@ -0,0 +1,21 @@ +BaseController = require './../base_controller' +{ mongoose } = require '../../../config/database' +Administrator = mongoose.model('Administrator') + +Admin = {} + +class Admin.SessionsController extends BaseController + new: -> + @response.render 'admin/sessions/new' + + create: -> + params = + username: @request.body.admin.username + password: @request.body.admin.password + + Administrator.findOne params, (error, administrator) => + throw error if error + @request.session.administrator_id = administrator._id + @response.redirect '/' + +module.exports = Admin diff --git a/app/controllers/base_controller.coffee b/app/controllers/base_controller.coffee new file mode 100644 index 0000000..ff1f43e --- /dev/null +++ b/app/controllers/base_controller.coffee @@ -0,0 +1,4 @@ +class BaseController + constructor: (@request, @response) -> + +module.exports = BaseController diff --git a/app/controllers/homes_controller.coffee b/app/controllers/homes_controller.coffee new file mode 100644 index 0000000..da38ab1 --- /dev/null +++ b/app/controllers/homes_controller.coffee @@ -0,0 +1,14 @@ +BaseController = require './base_controller' +{ mongoose } = require '../../config/database' +Administrator = mongoose.model('Administrator') + + +class HomesController extends BaseController + show: -> + _id = @request.session.administrator_id + Administrator.findOne { _id: _id }, (error, administrator) => + throw error if error + @response.render 'homes/show', + administrator: administrator + +module.exports = HomesController diff --git a/app/models/administrator.coffee b/app/models/administrator.coffee new file mode 100644 index 0000000..15533fc --- /dev/null +++ b/app/models/administrator.coffee @@ -0,0 +1,9 @@ +{ mongoose, Schema } = require '../../config/database' + +AdministratorSchema = new Schema + username: { type: String, trim: true } + password: { type: String, trim: true } + name: { type: String, trim: true } + created_at: { type : Date, default : Date.now } + +mongoose.model('Administrator', AdministratorSchema) diff --git a/app/views/admin/sessions/new.jade b/app/views/admin/sessions/new.jade new file mode 100644 index 0000000..66a8752 --- /dev/null +++ b/app/views/admin/sessions/new.jade @@ -0,0 +1,10 @@ +html +#container + form(action='sessions/create', method='post') + label(for='admin_username') username + input(id='admin_username', name='admin[username]') + br + label(for='admin_password') password + input(id='admin_password', name='admin[password]') + br + input(type='submit', name='Login') diff --git a/app/views/homes/show.jade b/app/views/homes/show.jade new file mode 100644 index 0000000..d45e447 --- /dev/null +++ b/app/views/homes/show.jade @@ -0,0 +1,5 @@ +html +#container + a(href='admin/login') Login + if administrator != null + p "Logged in as #{ administrator.name }" diff --git a/config/app.yaml b/config/app.yaml new file mode 100644 index 0000000..9702bb3 --- /dev/null +++ b/config/app.yaml @@ -0,0 +1,11 @@ +default: + db: + uri: 'mongodb://localhost/tilt_development' + app: + port: 3000 + +test: + db: + uri: 'mongodb://localhost/tilt_test' + app: + port: 3030 diff --git a/config/application.coffee b/config/application.coffee new file mode 100644 index 0000000..1d734ba --- /dev/null +++ b/config/application.coffee @@ -0,0 +1,25 @@ +express = require 'express' +path = require 'path' +config = require 'yaml-config' +{ mongoose } = require './database' + +settings = config.readConfig('config/app.yaml', process.env.NODE_ENV) + +module.exports = (app) -> + + app.configure -> + + app.set 'port', process.env.PORT || settings.app.port || 3000 + app.set 'views', "#{app.root}/app/views" + app.set 'view engine', 'jade' + app.use express.favicon() + app.use express.bodyParser() + app.use express.methodOverride() + app.use express.cookieParser('2ee27441d3ee4a527de019325dc7e8ddee6039cc7cad9801181c6fd68204129bdf3225cafabb3f6d0324a7bd851dabbd0bd3') + app.use express.session() + app.use app.router + app.use express.static("#{ app.root }/public") + + app.configure 'development', -> + app.use express.logger('dev') + app.use express.errorHandler() diff --git a/config/bootstrap.coffee b/config/bootstrap.coffee new file mode 100644 index 0000000..cc5e1d4 --- /dev/null +++ b/config/bootstrap.coffee @@ -0,0 +1,8 @@ +fs = require 'fs' + +module.exports = (app) -> + # Bootstrap models + + for file in fs.readdirSync(app.root + '/app/models/') + if file.match(new RegExp(/.*\.coffee$/)) + require app.root + '/app/models/' + file diff --git a/config/database.coffee b/config/database.coffee new file mode 100644 index 0000000..1c79a73 --- /dev/null +++ b/config/database.coffee @@ -0,0 +1,10 @@ +mongoose = require 'mongoose' +config = require 'yaml-config' + +settings = config.readConfig('config/app.yaml', process.env.NODE_ENV) + +mongoose.connect settings.db.uri + +module.exports = + mongoose: mongoose + Schema: mongoose.Schema diff --git a/config/routes.coffee b/config/routes.coffee new file mode 100644 index 0000000..a98c83e --- /dev/null +++ b/config/routes.coffee @@ -0,0 +1,13 @@ +HomesController = require './../app/controllers/homes_controller' +Admin = require './../app/controllers/admin/sessions_controller' + +module.exports = (app) -> + + app.get '/', (request, response) -> + new HomesController(request, response).show() + + app.get '/admin/login', (request, response) -> + new Admin.SessionsController(request, response).new() + + app.post '/admin/sessions/create', (request, response) -> + new Admin.SessionsController(request, response).create() diff --git a/features/admin_logs_in.feature b/features/admin_logs_in.feature new file mode 100644 index 0000000..5b2603d --- /dev/null +++ b/features/admin_logs_in.feature @@ -0,0 +1,13 @@ +Feature: Admin creates an Event + As an admin, I can create an event + + Scenario: There is a view results link next to all my completed actions + Given an admin exists with the following information: + | username | password | name | + | admin | nimda | Admin McAdmin | + When I am on the homepage + And I click "Login" + And I fill in "admin[username]" with "admin" + And I fill in "admin[password]" with "nimda" + When I press "Login" + Then I should see "Logged in as Admin" diff --git a/features/step_definitions/admin_steps.coffee b/features/step_definitions/admin_steps.coffee new file mode 100644 index 0000000..50c33dd --- /dev/null +++ b/features/step_definitions/admin_steps.coffee @@ -0,0 +1,14 @@ +{ mongoose } = require '../../config/database' + +Administrator = mongoose.model('Administrator') + +steps = module.exports = -> + + @World = require('../support/world').World + + @Then /^an admin exists with the following information:$/, (table, next) -> + @_(table.hashes()).each (row) => + administrator = new Administrator row + administrator.save (error) -> + throw error if error + next() diff --git a/features/step_definitions/shared_steps.coffee b/features/step_definitions/shared_steps.coffee new file mode 100644 index 0000000..9a5a9a0 --- /dev/null +++ b/features/step_definitions/shared_steps.coffee @@ -0,0 +1,33 @@ +should = require 'should' + +steps = module.exports = -> + + @World = require('../support/world').World + + @After (next) -> + @clean next + + @Then /^I (?:am on|go to) (.+)$/, (path, next) -> + @browser.visit(@selectorFor(path), next) + + @Then /^I fill in "(.+)" with "(.+)"$/, (name, value, next) -> + @browser.fill(name, value, next) + + @Then /^I press "(.+)"$/, (name, next) -> + @browser.pressButton(name, next) + + @Then /^I click "(.+)"$/, (name, next) -> + @browser.clickLink(name, next) + + @Then /^I should see "(.+)"$/, (text, next) -> + @browser.html().should.include(text) + next() + + @Then /^show me the page$/, (next) -> + @browser.wait => + if @browser.errors.length + console.log "\nBrowser Errors:", @browser.errors + console.log @browser.html() + #@browser.viewInBrowser() + + next() diff --git a/features/support/selectors.coffee b/features/support/selectors.coffee new file mode 100644 index 0000000..8aaec91 --- /dev/null +++ b/features/support/selectors.coffee @@ -0,0 +1,12 @@ +module.exports = + # Elements + + '^(.*) within (.*)$': (inner, outer) -> + return "#{@selectorFor(outer)} #{@selectorFor(inner)}" + + '^(.*) containing "([^"]*)"$': (namedElement, text) -> + return "#{@selectorFor(namedElement)}:contains('#{text}')" + + # Paths + 'the home ?page': '/' + 'the admin login page': '/admin/login/' diff --git a/features/support/world.coffee b/features/support/world.coffee new file mode 100644 index 0000000..aa72906 --- /dev/null +++ b/features/support/world.coffee @@ -0,0 +1,52 @@ +process.env.NODE_ENV = 'test' + +app = require '../../tilt' + +{Factory} = require 'forgery' +selectors = require './selectors' +_ = require 'underscore' +{ mongoose } = require '../../config/database' +DatabaseCleaner = require 'database-cleaner' +zombie = require 'zombie' +zombie.site = "http://localhost:#{ app.get('port') }/" + +databaseCleaner = new DatabaseCleaner('mongodb') + +require '../../spec/factories' + +class World + constructor: (callback) -> + # this.browser will be available in step definitions + @browser = new zombie.Browser() + @_ = _ + @selectors = selectors + + # tell Cucumber we're finished and to use 'this' as the world instance + callback(@) + + clean: (next) -> + databaseCleaner.clean(mongoose.connection.db, next) + + selectorFor: (selector) -> + for regexp, path of @selectors + match = selector.match(new RegExp(regexp)) + + if match + if typeof path == 'string' + return path + else + return path.apply @, match.slice(1) + + throw new Error("Could not find path for '#{selector}'") + + Factory: (factoryName, options) -> + for key, value of options + options[key] = switch value + when 'true' then true + when 'false' then false + when 'null' then null + else value + + Factory factoryName, options + +module.exports.World = World diff --git a/package.json b/package.json new file mode 100644 index 0000000..b48a789 --- /dev/null +++ b/package.json @@ -0,0 +1,30 @@ +{ + "name": "tiltnyc", + "version": "0.0.1", + "private": true, + "scripts": { + "start": "node app", + "specs": "./node_modules/.bin/mocha --compilers coffee:coffee-script spec/*/*spec*", + "features": "./node_modules/.bin/cucumber-js features/*", + "build": "./node_modules/.bin/mocha --compilers coffee:coffee-script spec/*/*spec* && ./node_modules/.bin/cucumber-js features/*" + }, + "dependencies": { + "coffee-script": "1.3.3", + "express": "3.0.0rc4", + "fs": "latest", + "jade": "0.27.2", + "mongoose": "3.1.1", + "package": "latest", + "underscore": "1.3.1", + "walk": "latest", + "yaml-config": "latest" + }, + "devDependencies": { + "cucumber": "latest", + "database-cleaner": "latest", + "forgery": "latest", + "mocha": "latest", + "should": "latest", + "zombie": "1.4.1" + } +} diff --git a/public/stylesheets/style.css b/public/stylesheets/style.css new file mode 100644 index 0000000..30e047d --- /dev/null +++ b/public/stylesheets/style.css @@ -0,0 +1,8 @@ +body { + padding: 50px; + font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; +} + +a { + color: #00B7FF; +} \ No newline at end of file diff --git a/spec/factories/index.coffee b/spec/factories/index.coffee new file mode 100644 index 0000000..3610339 --- /dev/null +++ b/spec/factories/index.coffee @@ -0,0 +1,8 @@ +{Factory} = require 'forgery' + +# Define Factories bellow this line + +Factory.define 'Administrator', + name: 'Admin' + username: 'admin' + password: 'password' diff --git a/spec/models/administrator.spec.coffee b/spec/models/administrator.spec.coffee new file mode 100644 index 0000000..8031d5d --- /dev/null +++ b/spec/models/administrator.spec.coffee @@ -0,0 +1,8 @@ +{ mongoose } = require '../spec_helper' +Administrator = mongoose.model('Administrator') + +describe 'Administrator', -> + describe '#save()', -> + it 'saves without error', (done) -> + admin = new Administrator(username: admin) + admin.save(done) diff --git a/spec/spec_helper.coffee b/spec/spec_helper.coffee new file mode 100644 index 0000000..f9cb231 --- /dev/null +++ b/spec/spec_helper.coffee @@ -0,0 +1,6 @@ +require '../tilt' + +{ mongoose } = require '../config/database' + +module.exports = + mongoose: mongoose diff --git a/tilt.coffee b/tilt.coffee new file mode 100644 index 0000000..d8e04ad --- /dev/null +++ b/tilt.coffee @@ -0,0 +1,15 @@ +express = require 'express' +http = require 'http' + +app = express() + +app.root = __dirname + +require('./config/bootstrap' )(app) +require('./config/application')(app) +require('./config/routes' )(app) + +module.exports = app + +http.createServer(app).listen app.get('port'), -> + console.log 'Express server listening on port ' + app.get('port')