Skip to content
Browse files

Starting merge

  • Loading branch information...
2 parents 3aeb8f5 + 565c6a6 commit 52fa62f2554c41ef36dd9f5bb29436d0ab461ed6 @tbergeron committed Apr 13, 2012
View
2 core.js
@@ -1,3 +1,3 @@
require("ncore/modules/moduleLoader").core(
- require("path").join(__dirname, ".")
+ require("path").join(__dirname, "modules")
)
View
7 modules/app/controllers/home.js
@@ -0,0 +1,7 @@
+module.exports = {
+ index: function(req, res) {
+ res.render('index', {
+ title: 'ThinAir'
+ });
+ }
+};
View
87 modules/app/controllers/project.js
@@ -0,0 +1,87 @@
+var helpers = require('../../libs/helpers');
+
+var ProjectController = {
+ // properties
+ Projects: null,
+
+ // constructor
+ initialize: function(req, res) {
+ helpers.check_if_authorized(req, res);
+ this.Projects = this.repositories.Projects;
+ },
+
+ // GET: /projects
+ list: function(req, res) {
+ this.initialize(req, res);
+
+ this.Projects.allByDate(function(projects) {
+ if (projects) {
+ res.render('projects/list', {
+ title: 'List of projects',
+ projects: projects
+ });
+ } else {
+ helpers.flash(req, 'error', 'No projects found.');
+ res.redirect('/');
+ }
+ });
+ },
+
+ // GET: /projects/new
+ new: function(req, res) {
+ this.initialize(req, res);
+
+ res.render('projects/edit', {
+ title: 'Create a new project'
+ });
+ },
+
+ // GET&POST: /projects/edit/:project_code
+ edit: function(req, res) {
+ this.initialize(req, res);
+
+ if (helpers.is_post(req)) {
+ // if this is POST, validates and saves the object.
+ this.Projects.save(req.body.project, function(project, errors) {
+ if (errors) {
+ flashErrors(req, errors);
+ } else {
+ helpers.flash(req, 'success', 'Saved with success.');
+ }
+
+ res.render('projects/edit', {
+ title: 'Editing project: ' + project.name,
+ project: project
+ });
+
+ });
+ } else {
+ // if this is no POST, then it's an edit form
+ this.Projects.byCode(req.params.project_code, function(project) {
+ if (project) {
+ res.render('projects/edit', {
+ title: 'Editing project: ' + project.name,
+ project: project
+ });
+ } else {
+ helpers.flash(req, 'error', 'Unable to find project.');
+ res.redirect('/projects');
+ }
+ });
+ }
+ },
+
+ // GET: /projects/delete
+ delete: function(req, res) {
+ this.initialize(req, res);
+ this.Projects.delete(req.params.project_code, function(err) {
+ if (!err) {
+ helpers.flash(req, 'success', 'Project with code "' + req.params.project_code + '" has been deleted with success.');
+ }
+ res.redirect('/projects');
+ });
+ }
+
+};
+
+module.exports = ProjectController;
View
41 modules/app/controllers/user.js
@@ -0,0 +1,41 @@
+var helpers = require('../../libs/helpers');
+
+var UserController = {
+ // properties
+ Users: null,
+
+ // constructor
+ initialize: function() {
+ this.Users = this.repositories.Users;
+ },
+
+ // POST: /users/login
+ login: function(req, res) {
+ this.initialize();
+
+ var username = req.body.username;
+ var password = req.body.password;
+
+ this.Users.byUsernameAndPassword(username, password, function(user) {
+ if (!user) {
+ helpers.flash(req, 'error', 'We are unable to find this user or maybe your password is wrong? Please try again.');
+ } else {
+ req.session.is_logged = true;
+ req.session.username = username;
+ helpers.flash(req, 'success', 'Welcome back ' + username + '!');
+ }
+ res.redirect('/');
+ });
+ },
+
+ // GET: /users/logout
+ logout: function(req, res) {
+ req.session.is_logged = null;
+ req.session.username = null;
+
+ res.redirect('/');
+ }
+
+};
+
+module.exports = UserController;
View
86 modules/app/repositories/Projects.js
@@ -0,0 +1,86 @@
+var collection = require('mongo-col'),
+ pd = require('pd');
+
+var Projects = pd.extend(Object.create(collection('projects', 'thinair')), {
+
+ // gets a list of all projects sorting by date_created ascending.
+ allByDate: function(callback) {
+ this.find().sort({ date_created: 1 }).toArray(function(err, projects) {
+ if (err) console.log(err);
+
+ if (projects) {
+ callback(projects);
+ } else {
+ callback(null);
+ }
+ });
+ },
+
+ // gets a project by its code
+ byCode: function(code, callback) {
+ this.findOne({ code: code }, function(err, project) {
+ if (err) console.log(err);
+
+ if (project) {
+ callback(project);
+ } else {
+ callback(null);
+ }
+ });
+ },
+
+ // saves a project
+ save: function(project, callback) {
+ var project_code = slugify(project.name);
+
+ //todo: CHECK FOR DUPLICATES
+ // validates('project', project, function(errors) {
+ // if (!errors) {
+ if (isNew(project)) {
+ //if it's a new project, save it
+ this.save({ code: project_code, name: project.name });
+ //fetch the saved project
+ this.findOne({ code: project_code }, function(err, new_project) {
+ return callback(new_project);
+ });
+ } else {
+ //if it's not a new project, update the existing one
+ this.update({ _id: db.ObjectId(project._id) }, {
+ $set: { code: project_code, name: project.name }
+ });
+ //fetch the created project
+ this.findOne({ _id: db.ObjectId(project._id) }, function(err, updated_project) {
+ return callback(updated_project);
+ });
+ }
+ // } else {
+ // // todo: remove this when validations are done
+ // var errors = null;
+ // //if there's validation errors
+ // if (isNew(project)) {
+ // //if it's a new project, send it as it is
+ // return callback(project, errors);
+ // } else {
+ // //if it's an existing one, fetch it and put and replace the values with the on from the form
+ // this.findOne({
+ // _id: db.ObjectId(project._id)
+ // }, function(err, fetched_project) {
+ // fetched_project.code = project_code;
+ // fetched_project.name = project.name;
+ // return callback(fetched_project, errors);
+ // });
+ // }
+ // }
+ //});
+ },
+
+ // deletes an object
+ delete: function(code, callback) {
+ this.remove({ code: code }, function(err) {
+ if (err) callback(err);
+ });
+ }
+
+});
+
+module.exports = Projects;
View
20 modules/app/repositories/Users.js
@@ -0,0 +1,20 @@
+var collection = require('mongo-col'),
+ pd = require('pd');
+
+var Users = pd.extend(Object.create(collection('users', 'thinair')), {
+
+ byUsernameAndPassword: function(username, password, callback) {
+ this.findOne({ username: username, password: password }, function(err, user) {
+ if (err) console.log(err);
+
+ if (user) {
+ callback(user);
+ } else {
+ callback(null);
+ }
+ });
+ }
+
+});
+
+module.exports = Users;
View
5 modules/app/repositories/validations/projects.validations.json
@@ -0,0 +1,5 @@
+[{
+ "name": [{
+ "minimumLength": 5
+ }]
+}]
View
23 modules/app/routes.js
@@ -0,0 +1,23 @@
+module.exports = {
+ registerRoutes: function(app) {
+ // home
+ app.get('/', this.controllers.home.index);
+
+ // users
+ app.post('/users/login', this.controllers.user.login);
+ app.get('/users/logout', this.controllers.user.logout);
+
+ // projects
+ app.get('/projects', this.controllers.project.list);
+ app.get('/projects/new', this.controllers.project.new);
+ app.get('/projects/edit/:project_code', this.controllers.project.edit);
+ app.post('/projects/edit', this.controllers.project.edit);
+ //app.get('/projects/delete/:project_code', projectController.delete);
+
+ // projects' milestones
+ //app.get('/projects/:project_code/milestones/new', this.controllers.milestone.new);
+ //app.get('/projects/:project_code/milestones/edit/:milestone_code', this.controllers.milestone.edit);
+ //app.post('/projects/:project_code/milestones/edit', this.controllers.milestone.edit);
+ //app.get('/projects/:project_code/milestones/delete/:milestone_code', this.controllers.milestone.delete);
+ }
+};
View
7 modules/app/views/index.html
@@ -0,0 +1,7 @@
+{{> header}}
+
+Hello World!
+
+{{> login}}
+
+{{> footer}}
View
5 modules/app/views/partials/footer.html
@@ -0,0 +1,5 @@
+ <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
+ <script src="/js/bootstrap.js"></script>
+ <script src="/js/thinair.js"></script>
+ </body>
+</html>
View
50 modules/app/views/partials/header.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>{{title}}</title>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="description" content="">
+ <meta name="author" content="">
+
+ <link rel='stylesheet' href='/css/bootstrap.css' />
+ <link rel='stylesheet' href='/css/bootstrap-responsive.css' />
+
+ <style type="text/css">
+ body {
+ padding-top: 60px;
+ padding-left: 40px;
+ padding-right: 40px;
+ padding-bottom: 40px;
+ }
+ .sidebar-nav {
+ padding: 9px 0;
+ }
+ </style>
+
+ <!--[if lt IE 9]>
+ <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
+ <![endif]-->
+ </head>
+ <body>
+
+ <div class="navbar navbar-fixed-top">
+ <div class="navbar-inner">
+ <div class="container-fluid">
+ <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ </a>
+ <a class="brand" href="/">ThinAir</a>
+ <div class="nav-collapse">
+ {{> navigation}}
+ </div><!--/.nav-collapse -->
+ </div>
+ </div>
+ </div>
+
+ <h2>{{title}}</h2>
+ <br />
+
+ {{> messages}}
View
17 modules/app/views/partials/login.html
@@ -0,0 +1,17 @@
+{{^session.is_logged}}
+<p>Please enter your connection informations before proceeding.</p>
+
+<form action="/users/login" method="post">
+
+ <input id="username" class="input-medium" placeholder="Username" type="text" name="username">
+
+ <br />
+
+ <input id="password" class="input-medium" placeholder="Password" type="password" name="password">
+
+ <br />
+
+ <button class="btn btn-primary">Login</button>
+
+</form>
+{{/session.is_logged}}
View
8 modules/app/views/partials/messages.html
@@ -0,0 +1,8 @@
+<div id="messages">
+{{#messages}}
+ <div class="alert alert-{{type}}" data-alert="alert">
+ <a class="close" href="#" data-dismiss="alert">×</a>
+ {{message}}
+ </div>
+{{/messages}}
+</div>
View
19 modules/app/views/partials/navigation.html
@@ -0,0 +1,19 @@
+{{#with session}}
+ <ul class="nav">
+ <li class="home"><a href="/">Home</a></li>
+ {{#if is_logged}}
+ <li class="projects">
+ <a href="/projects">Projects</a>
+ </li>
+ {{/if}}
+ </ul>
+
+ <p class="navbar-text pull-right">
+ {{#if is_logged}}
+ Logged in as <a href="#">{{username}}</a>.
+ <a href="/users/logout">Logout</a>
+ {{else}}
+ Not logged yet, <a href="/">login now</a>.
+ {{/if}}
+ </p>
+{{/with}}
View
15 modules/app/views/projects/edit.html
@@ -0,0 +1,15 @@
+{{> header}}
+
+<form action="/projects/edit", method="post">
+ <input type="hidden" name="project[_id]" value="{{#if project}}{{project._id}}{{/if}}" />
+ <input type="hidden" name="project[code]" value="{{#if project}}{{project.code}}{{/if}}" />
+
+ <label for="project[name]">Name</label>
+ <input type="text" name="project[name]" value="{{#if project}}{{project.name}}{{/if}}" />
+
+ <br />
+
+ <button class="btn btn-primary">Save</button>
+</form>
+
+{{> footer}}
View
35 modules/app/views/projects/list.html
@@ -0,0 +1,35 @@
+{{> header}}
+
+{{#if projects}}
+ <table class="table table-bordered table-striped">
+ <tr>
+ <th>Name</th>
+ <th>Actions</th>
+ </tr>
+ {{#each projects}}
+ <tr>
+ <td>
+ {{name}}
+ </td>
+ <td style="width:20%;text-align:center">
+ <a class="btn btn-primary" href="/projects/edit/{{code}}">
+ <i class="icon-edit icon-white"></i>
+ Edit
+ </a>
+
+ <a class="btn btn-danger" href="/projects/delete/{{code}}" onclick="return confirm('Do you really want to delete {{name}}?');">
+ <i class="icon-trash icon-white"></i>
+ Delete
+ </a>
+ </td>
+ </tr>
+ {{/each}}
+ </table>
+{{/if}}
+
+<a class="btn" href="/projects/new">
+ <i class="icon-file icon-black"></i>
+ Create a new project
+</a>
+
+{{> footer}}
View
16 modules/dependency.json
@@ -0,0 +1,16 @@
+{
+ "./libs/server.js": {
+ "app": "./libs/app.js"
+ },
+ "./libs/app.js": {
+ "configure": "./libs/configure.js",
+ "routes": "./app/routes.js",
+ "partials": "./libs/partials.js"
+ },
+ "./app/routes.js": {
+ "controllers": ["./app/controllers/"]
+ },
+ "./app/controllers/": {
+ "repositories": ["./app/repositories/"]
+ }
+}
View
19 modules/libs/app.js
@@ -0,0 +1,19 @@
+var express = require('express'),
+ hbs = require('handlebars'),
+ helpers = require('./helpers');
+
+module.exports = {
+ start: function start(server) {
+ var app = express();
+
+ this.configure.start(app);
+
+ this.routes.registerRoutes(app);
+
+ this.partials.registerPartials(hbs);
+
+ helpers.registerHandlebarsHelpers(hbs);
+
+ server.on('request', app);
+ }
+};
View
31 modules/libs/configure.js
@@ -0,0 +1,31 @@
+var express = require('express'),
+ cons = require('consolidate'),
+ helpers = require('./helpers');
+
+module.exports = {
+ start: function(app) {
+ app.locals.use(function(req, res) {
+ res.locals.session = req.session;
+ res.locals.messages = helpers.get_flash(req);
+ });
+
+ app.configure(function() {
+ app.engine('html', cons.handlebars);
+ app.set('view engine', 'html');
+ app.set('views', __dirname + '/../app/views');
+
+ app.use(express.favicon());
+ app.use(express.logger('dev'));
+ app.use(express.static(__dirname + '/../../public'));
+ app.use(express.bodyParser());
+ app.use(express.methodOverride());
+ app.use(express.cookieParser('secret'));
+ app.use(express.session({ secret: 'keyboard cat' }));
+ app.use(app.router);
+ });
+
+ app.configure('development', function() {
+ app.use(express.errorHandler());
+ });
+ }
+};
View
72 modules/libs/helpers.js
@@ -0,0 +1,72 @@
+var Helpers = {
+ check_if_authorized: function(req, res) {
+ if (req.session.is_logged) {
+ return true;
+ } else {
+ this.flash(req, 'error', 'You need to be logged in to access this page.');
+ res.redirect('/');
+ }
+ },
+
+ is_get: function(req) {
+ return (req.route.method == 'get') ? true : false;
+ },
+
+ is_post: function(req) {
+ return (req.route.method == 'post') ? true : false;
+ },
+
+ slugify: function(str) {
+ str = str.replace(/^\s+|\s+$/g, '');
+ str = str.toLowerCase();
+
+ var from = 'àáäâèéëêìíïîòóöôùúüûñç·/_,:;';
+ var to = 'aaaaeeeeiiiioooouuuunc------';
+
+ for (var i = 0, l = from.length; i < l; i++) {
+ str = str.replace(new RegExp(from.charAt(i), 'g'), to.charAt(i));
+ }
+
+ str = str.replace(/[^a-z0-9 -]/g, '').replace(/\s+/g, '-').replace(/-+/g, '-');
+
+ return str;
+ },
+
+ flash: function(req, type, message) {
+ if (req.session.messages === undefined) {
+ req.session.messages = [];
+ }
+
+ if ((type !== undefined) && (message !== undefined)) {
+ var messageObject = {
+ type: type,
+ message: message
+ };
+ req.session.messages.push(messageObject);
+ }
+
+ return req.session.messages;
+ },
+
+ get_flash: function(req) {
+ if (req.session.messages !== undefined) {
+
+ var messages = req.session.messages;
+
+ // cleaning messages
+ req.session.messages = [];
+
+ return messages;
+ }
+ },
+
+ // todo: it would be cool to eventually do something with this
+ registerHandlebarsHelpers: function(hbs) {
+ // hbs.registerHelper('fullName', function(person) {
+ // return person.firstName + " " + person.lastName;
+ // });
+ }
+
+};
+
+module.exports = Helpers;
View
18 modules/libs/partials.js
@@ -0,0 +1,18 @@
+var fs = require('fs');
+
+var Partials = {
+ registerPartials: function(hbs) {
+ fs.readdir(__dirname + '/../app/views/partials', readPartials);
+
+ function readPartials(err, files) {
+ files.forEach(loadPartial);
+ }
+
+ function loadPartial(file) {
+ var partialName = file.replace('.html', '');
+ hbs.registerPartial(partialName, fs.readFileSync(__dirname + '/../app/views/partials/' + file, 'UTF-8'));
+ }
+ }
+};
+
+module.exports = Partials;
View
12 modules/libs/server.js
@@ -0,0 +1,12 @@
+var http = require('http');
+
+module.exports = {
+ init: function init() {
+ process.env.PORT = 3000;
+
+ var server = http.createServer().listen(process.env.PORT);
+ this.app.start(server);
+
+ console.log('Express server listening on port ' + process.env.PORT);
+ }
+};
View
28 package.json
@@ -1,28 +0,0 @@
-{
- "author": "Tommy Bergeron <t.bergeron@gmail.com>",
- "name": "ThinAir",
- "description": "Web Development Framework based on Node.js and Express.js",
- "version": "0.0.1",
- "homepage": "https://github.com/tbergeron/ThinAir",
- "repository": {
- "type": "git",
- "url": "git://github.com/tbergeron/ThinAir.git"
- },
- "dependencies": {
- "ncore": "1.3.10",
- "handlebars": "1.0.5beta",
- "mongojs": "0.3.2",
- "pd": "0.6.3",
- "mongo-col": "0.1.7",
- "path": "0.4.9",
- "consolidate": "0.2.0"
- },
- "devDependencies": {
- "mocha": "1.0.1",
- "express": "git://github.com/visionmedia/express.git"
- },
- "optionalDependencies": {},
- "engines": {
- "node": "0.6.x"
- }
-}

0 comments on commit 52fa62f

Please sign in to comment.
Something went wrong with that request. Please try again.