aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/app
diff options
context:
space:
mode:
authorDennis Eriksen <dennis.se@gmail.com>2013-05-25 11:17:42 +0200
committerDennis Eriksen <dennis.se@gmail.com>2013-05-25 11:17:42 +0200
commite582c3b84c6090b08f33d599c354968fcd868d14 (patch)
treeb6de1b7b1f708bf9126ccb709d5129e91a67c7d5 /app
parentchanged what gets collected (diff)
downloadDivid-e582c3b84c6090b08f33d599c354968fcd868d14.tar.gz
moved and renamed files to match the filesetup we want.
havebeen using a dev-setup till now.
Diffstat (limited to 'app')
-rw-r--r--app/controllers/system.js329
-rw-r--r--app/controllers/users.js282
-rw-r--r--app/models/Access.js129
-rw-r--r--app/models/Project.js75
-rw-r--r--app/models/User.js182
-rw-r--r--app/models/pPost.js78
-rw-r--r--app/views/contact.ejs17
-rw-r--r--app/views/dashboard.ejs154
-rw-r--r--app/views/error.ejs9
-rw-r--r--app/views/faq.ejs115
-rw-r--r--app/views/home.ejs164
-rw-r--r--app/views/index.ejs131
-rw-r--r--app/views/project/newProject.ejs79
-rw-r--r--app/views/project/participants.ejs55
-rw-r--r--app/views/project/post.ejs103
-rw-r--r--app/views/project/project.ejs220
-rw-r--r--app/views/template.ejs18
-rw-r--r--app/views/templates/footer.ejs20
-rw-r--r--app/views/templates/header.ejs16
-rw-r--r--app/views/templates/navbar.ejs73
-rw-r--r--app/views/test.ejs46
-rw-r--r--app/views/users/registerEmail.ejs43
-rw-r--r--app/views/users/signup.ejs86
23 files changed, 2424 insertions, 0 deletions
diff --git a/app/controllers/system.js b/app/controllers/system.js
new file mode 100644
index 0000000..0e63083
--- /dev/null
+++ b/app/controllers/system.js
@@ -0,0 +1,329 @@
+
+/**
+ * Module dependencies
+ */
+var mongoose = require('mongoose')
+ , env = process.env.NODE_ENV || 'development'
+ , config = require('../../config/config.js')[env]
+ , Project = mongoose.model('Project')
+ , Access = mongoose.model('Access')
+ , User = mongoose.model('User')
+ , pPost = mongoose.model('pPost')
+ , Validator = require('validator').Validator
+ , v = new Validator()
+ , sanitize = require('validator').sanitize;
+
+
+// validation error handling. This collects all errors before pushing them out in getErrors()
+Validator.prototype.error = function(msg) {
+ this._errors.push(msg);
+ return this;
+}
+Validator.prototype.getErrors = function() {
+ var returnThis = this._errors;
+ this._errors = ''; // need to reset errors between sessions because of object model
+ return returnThis;
+}
+
+/**
+ * Before the user log in
+ * ===============================================================
+*/
+
+exports.index = function(req, res) {
+ if (req.user !== undefined) { return res.redirect('/dashboard'); }
+ res.render('index', { title: 'DERS', user: req.user });
+ };
+
+
+exports.faq = function(req, res) {
+ res.render('faq', {
+ title: 'faq',
+ user: req.user
+ });
+}
+
+
+exports.contact = function(req, res) {
+ res.render('contact', {
+ title: 'contact',
+ user: req.user
+ });
+}
+
+
+/**
+ * After the user has logged in
+ * ===============================================================
+*/
+
+
+
+exports.dashboard = function(req, res) {
+
+/*
+ Access.find({ user: req.user._id }, function(err, accesses) {
+ if (err) return res.status(500).render('error', { title: '500', text: 'En serverfeil oppstod', error: err.stack });
+ console.log('accesses ' + accesses);
+ accesses.forEach(function(access) {
+ Project.load(access.project, function(err, project) {
+ if (err) return res.status(500).render('error', { title: '500', text: 'En serverfeil oppstod', error: err.stack });
+ projectList.push(project);
+ console.log(project.user.username);
+ });
+ });
+ });
+*/
+ if (req.user.status < 3) {
+ if (req.header('Referer') === undefined) { return res.status(403).render('error', { title: 403, text: 'Du har ikke tilgang til denne siden. Du må registrere deg først. Sjekk mailen din for å se invitekode.' }); }
+ else { return res.redirect('back'); }
+ }
+
+ Access.loadUser(req.user._id, function(err, projects) {
+ if (err) return res.status(500).render('error', { title: '500', text: 'En serverfeil oppstod', error: err.stack });
+ var projectIDs = [];
+ var pro = { project: [] };
+ projects.forEach(function(project) {
+ projectIDs.push(project.project._id);
+ pro.project[project.project._id] = {
+ total: 0 // total for project
+ , user: 0 // what req-user has spent on project
+ , users: 0 // number of users on project
+ };
+ });
+ Access.loadProjects(projectIDs, function(err, participants) {
+ if (err) return res.status(500).render('error', { title: '500', text: 'En serverfeil oppstod', error: err.stack });
+ participants.forEach(function(p) {
+ pro.project[p.project].users++;
+ });
+ pPost.loadByProjects(projectIDs, function(err, posts) {
+ if (err) return res.status(500).render('error', { title: '500', text: 'En serverfeil oppstod', error: err.stack });
+ Access.loadProjects(projectIDs, function(err, participants) {
+ if (err) return res.status(500).render('error', { title: '500', text: 'En serverfeil oppstod', error: err.stack });
+
+ // FUN FUN FUN CALCULATIONS
+
+ posts.forEach(function(p) {
+ if (String(p.user._id) === String(req.user._id)) pro.project[p.project._id].user += p.value;
+ pro.project[p.project._id].total += p.value;
+ });
+
+ res.render('dashboard', {
+ title: 'Dashboard'
+ , user: req.user
+ , projects: projects
+ , posts: posts
+ , participants: participants
+ , pro: pro
+ });
+ });
+ });
+ /* res.render('dashboard', {
+ title: 'Dashboard',
+ user: req.user,
+ projects: projects
+ });
+*/
+ });
+ });
+
+/*
+ Project.find(function(err, projects) {
+ if (err) return res.status(500).render('error', { title: '500', text: 'En serverfeil oppstod', error: err.stack });
+ res.render('dashboard', {
+ title: 'Dashboad',
+ user: req.user,
+ projects: projects
+ });
+ });*/
+}
+
+
+
+exports.project = function(req, res) {
+ Project.loadShort(req.params.short, function(err, project) {
+ if (err || !project) return res.status(500).render('error', { title: '500', text: 'En serverfeil oppstod', error: err });
+ Access.loadProject(project._id, function(err, access) {
+ if (err) return res.status(500).render('error', { title: '500', text: 'En serverfeil oppstod', error: err.stack });
+ pPost.loadProject(project._id, function(err, posts) {
+ if (err) return res.status(500).render('error', { title: '500', text: 'En serverfeil oppstod', error: err.stack });
+
+ // ALRIGHT! This is where the FUN starts!
+
+ // first we create an object that will hold all the calculational data
+ var pro = {
+ users: 0 // number of users
+ , user: [] // this array will contain every user. Every user will then have it's own object inside this.
+ , total: 0 // the overall total.
+ , each: 0 // what each person has to pay
+ , otot: 0 // how much is owned in total!
+ };
+
+ // then we calculate how many users we have, and initiate objects foreach user
+ access.forEach(function(a) {
+ if (String(a.user._id) === String(req.user._id)) req.user.permissions = a.permissions; //sets YOUR permissions in this project
+
+ pro.users++;
+ pro.user[a.user._id] = {
+ total: 0
+ , diff: 0
+ , coeff: 0 // the coefficient of hom much you are owned
+ , name: a.user.name
+ };
+ });
+
+ // now we must collect all the money!
+ posts.forEach(function(p) {
+ pro.total += parseFloat(p.value);
+ pro.user[p.user._id].total += parseFloat(p.value);
+ });
+
+ // then calculate how much each user must pay in total
+ pro.each = pro.total / pro.users;
+
+ // then calculate how much each person owe and is owned
+ for(var i in pro.user) {
+ pro.user[i].diff = parseFloat(pro.user[i].total - pro.each).toFixed(2);
+ if (pro.user[i].diff > 0) pro.otot += parseFloat(pro.user[i].diff);
+ }
+ for (var i in pro.user) {
+ if (pro.user[i].diff > 0) pro.user[i].coeff = pro.user[i].diff / pro.otot;
+ }
+ console.log(pro);
+ res.render('project/project', {
+ title: project.name
+ , user: req.user
+ , req: req
+ , project: project
+ , access: access
+ , posts: posts
+ , pro: pro
+ });
+ });
+ });
+
+ });
+}
+
+
+exports.projectParticipants = function(req, res) {
+ if (req.user.status < 3) {
+ if (req.header('Referer') === undefined) { return res.status(403).render('error', { title: 403, text: 'Du har ikke tilgang til denne siden. Du må registrere deg først. Sjekk mailen din for å se invitekode.' }); }
+ else { return res.redirect('back'); }
+ }
+ res.render('project/participants', { title: 'Prosjektdeltakere', user: req.user });
+
+}
+
+
+exports.projectPost = function(req, res) {
+
+ /** ###################################
+ * Need to check if user has access to this project!!
+ */
+ Project.loadShort(req.params.short, function(err, project) {
+ if (err) return res.status(500).render('error', { title: '500', text: 'En serverfeil oppstod', error: err.stack });
+ req.project = project;
+ res.render('project/post', { title: 'Legg til utgift', user: req.user, req: req, project: project });
+ });
+
+
+
+}
+
+exports.postProjectPost = function(req, res) {
+
+ // Validation
+ v.check(req.body.project, 'The project was lost').notEmpty();
+ v.check(req.body.what, 'You need to fill in the what-field').notEmpty();
+ v.check(req.body.value, 'The value must be a positive number').notEmpty().isInt().min(0);
+
+ // error when validation fails
+ var errors = v.getErrors();
+ if (errors.length !== 0) return res.status(500).render('error', { title: '500', text: 'Det oppstod en valideringsfeil ' + errors, error: errors });
+
+ Project.loadShort(req.params.short, function(err, project) {
+ if (err) return res.status(500).render('error', { title: '500', text: 'En serverfeil oppstod', error: err.stack });
+
+ // check if access
+ Access.checkAccess(req.user._id, project._id, 0, function(err, access) {
+ if (err || !access) return res.status(403).render('error', { title: '403', text: 'no sir.' });
+
+ // Time to fill in the model!
+ var ppost = new pPost();
+
+ ppost.user = req.user._id;
+ ppost.for = req.user._id;
+ ppost.project = project._id;
+ ppost.what = sanitize(req.body.what).escape();
+ ppost.comment = sanitize(req.body.comment).xss(); // xss will remove cross-site-scripting in the textfield.
+ ppost.participants = sanitize(req.body.participants).escape();
+ ppost.value = sanitize(req.body.value).toInt(); // this will remove leading zeroes. '0123' => '123'
+ ppost.when = new Date(sanitize(req.body.date).escape() + ' ' + sanitize(req.body.time).escape() + ':00');
+ ppost.save(function(err) {
+ if (err) return res.render('project/post', { title: 'Legg til utgift - en feil oppstod', user: req.user, req: req, project: project });
+ return res.redirect('/project/' + project.shortURL);
+ });
+ });
+ });
+}
+exports.newProject = function(req, res) {
+ if (req.user.status < 3) {
+ if (req.header('Referer') === undefined) { return res.status(403).render('error', { title: 403, text: 'Du har ikke tilgang til denne siden. Du må registrere deg først. Sjekk mailen din for å se invitekode.' }); }
+ else { return res.redirect('back'); }
+ }
+
+ res.render('project/newProject', { title: 'Nytt prosjekt', user: req.user });
+}
+
+exports.postNewProject = function(req, res) {
+ if (req.user.status < 3) {
+ if (req.header('Referer') === undefined) { return res.status(403).render('error', { title: 403, text: 'Du har ikke tilgang til denne siden. Du må registrere deg først. Sjekk mailen din for å se invitekode.' }); }
+ else { return res.redirect('back'); }
+ }
+
+ var project = new Project(req.body);
+ project.user = req.user._id;
+ project.save(function(err) {
+ if (err) {
+ console.log(err.errors);
+ return res.render('project/newProject', { title: 'Nytt prosjekt - en feil oppstod', user: req.user, errors: err.errors, project: project });
+ }
+ var access = new Access();
+ access.user = req.user._id;
+ access.creator = req.user._id;
+ access.project = project._id;
+ access.permissions = 9;
+ access.save(function(err) {
+ if (err) {
+ console.log(err.errors);
+ return res.render('project/newProject', { title: 'Nytt prosjekt - en feil oppstod', user: req.user });
+ }
+ return res.redirect('/dashboard');
+ });
+ });
+
+}
+
+
+exports.deleteProjectPost = function(req, res) {
+ Project.findOne({ shortURL: req.params.short }).select('_id').exec(function(err, project) {
+ if (err) return res.status(500).render('error', { title: '500', text: 'En serverfeil oppstod', error: err.stack });
+ Access.findOne({project: project._id, user: req.user._id}, function(err, access) {
+ if (err) return res.status(500).render('error', { title: '500', text: 'En serverfeil oppstod', error: err.stack });
+ if (!access) return res.status(403).render('error', { title: '403', text: 'Du har ikke tilgang til å gjøre dette' });
+ pPost.load(req.params.post, function(err, post) {
+ if (err || !post) return res.status(500).render('error', { title: '500', text: 'En serverfeil oppstod', error: err });
+ if (post.user._id === req.user._id || access.permissions >= 6) {
+ pPost.remove({ _id: post._id }, function(err) {
+ if (err) return res.status(500).render('error', { title: '500', text: 'En serverfeil oppstod', error: err.stack });
+ console.log('deleted post ' + post._id);
+ return res.redirect('back');
+ })
+ } else { return res.status(403).render('error', { title: '403', text: 'Du har ikke tilgang til å gjøre dette' }); }
+ })
+ })
+ });
+}
+
+
diff --git a/app/controllers/users.js b/app/controllers/users.js
new file mode 100644
index 0000000..725fa3e
--- /dev/null
+++ b/app/controllers/users.js
@@ -0,0 +1,282 @@
+
+/**
+ * Module dependencies
+ */
+
+var mongoose = require('mongoose')
+ , User = mongoose.model('User')
+ , Project = mongoose.model('Project')
+ , Access = mongoose.model('Access')
+ , env = process.env.NODE_ENV || 'development'
+ , config = require('../../config/config')[env]
+ , Validator = require('validator').Validator
+ , v = new Validator()
+ , sanitize = require('validator').sanitize;
+
+// validation error handling. This collects all errors before pushing them out in getErrors()
+Validator.prototype.error = function(msg) {
+ this._errors.push(msg);
+ return this;
+}
+Validator.prototype.getErrors = function() {
+ var returnThis = this._errors;
+ this._errors = ''; // need to reset errors between sessions because of object model
+ return returnThis;
+}
+
+
+/**
+ * Logout
+ */
+exports.logout = function(req, res) {
+ req.logout();
+ res.redirect('/');
+}
+
+
+/**
+ * Signin
+ * This is triggered when the user post to /login
+ */
+exports.signin = function(req, res) {
+ res.redirect('/dashboard');
+}
+
+exports.randomLogin = function(req, res) {
+ Access.findOne({ randomToken: req.params.hash }).populate('project', 'shortURL').exec(function(err, access) {
+ if (err) return res.status(500).render('error', { title: '500', text: 'En serverfeil oppstod', error: err.stack });
+ return res.redirect('/project/' + access.project.shortURL);
+
+ });
+}
+
+
+/**
+ * Signup
+ */
+exports.signup = function(req, res) {
+ res.render('users/signup', { title: 'Registrer deg', invite: false });
+}
+
+/**
+ * Create users
+ */
+exports.create = function(req, res) {
+ var user = new User(req.body);
+ user.provider = 'local';
+ user.save(function(err) {
+ if (err) return res.render('users/signup', { errors: err.errors, user: user });
+ req.logIn(user, function(err) {
+ if (err) return next(err);
+ return res.redirect('/dashboard');
+ });
+ });
+}
+
+
+/**
+ * AuthCallback
+ * This is what happends when a user has signed in using facebook/twitter
+ */
+
+exports.authCallback = function(req, res, next) {
+ // if the user hasn't registered an email, we need to do so
+ if (!req.user.email || req.user.email === undefined) return res.redirect('/registerEmail');
+
+ res.redirect('/dashboard');
+}
+
+
+/**
+ * registerEmail
+ * Will register the users email if they don't have already
+ */
+
+exports.registerEmail = function(req, res) {
+ // in case some user who has alreadu registered an email gets on this page
+ if (req.user.email !== undefined) return res.redirect('/dashboard');
+ res.render('users/registerEmail', { title: 'Registrer din e-post' });
+}
+
+
+/**
+ * postRegisterEmail
+ */
+
+exports.postRegisterEmail = function(req, res) {
+
+ v.check(req.body.email, 'You need to supply a proper email').isEmail();
+ var errors = v.getErrors();
+ if (errors.length !== 0) return res.status(500).render('error', { title: '500', text: 'Det oppstod en valideringsfeil<br>' + errors, error: errors });
+
+ // first we need to check if the email is already in use
+ User.findOne({ email: req.body.email }, function(err, user) {
+ if (err) return res.status(500).render('error', { title: '500', text: 'En serverfeil oppstod', error: err.stack });
+
+ // if mail is in use..
+ if (user) return res.render('users/registerEmail', { title: 'Den e-posten er allerede i bruk. Vennligs registrer en annen.' });
+
+ User.update({ _id: req.user._id }, { email: req.body.email, status: 3 }, function(err) {
+ if (err) return res.status(500).render('error', { title: '500', text: 'En serverfeil oppstod', error: err.stack });
+ return res.redirect('/dashboard');
+ });
+ });
+}
+
+
+/**
+ * postProjectParticipants
+ * This callback is in this file because it treats users.
+ */
+exports.postProjectParticipants = function(req, res) {
+ Project.loadShort(req.params.short, function(err, project) {
+ if (err || !project) return res.status(500).render('error', { title: '500', text: 'En serverfeil oppstod', error: err.stack });
+
+ Access.checkAccess(req.user._id, project._id, 3, function(err, access) {
+ if (err || !access) return res.status(403).render('error', { title: '403', text: 'No sir! NO ACCESS FOR YOU', error: err });
+
+ // validate
+ var emails = sanitize(req.body.emails).xss();
+ v.check(emails, 'You need to enter some emails to invite someone').notEmpty();
+ //var emails = sanitize(req.body.emails).xss();
+ emails = emails.split('\r\n');
+ emails.forEach(function(m) { // m = each mailaddress
+ if (m) {
+ v.check(m, m + ' is not a valid email').isEmail();
+ }
+ });
+
+ // error when validation fails
+ var errors = v.getErrors();
+ if (errors.length !== 0) return res.status(500).render('error', { title: '500', text: 'Det oppstod en valideringsfeil<br>' + errors, error: errors });
+
+ // EMAIL
+ // Require dependencies. We require them here so that they're not fetched until they're actually needed.
+ var email = require('emailjs')
+ , server = email.server.connect(config.email)
+ , message = {
+ subject: 'You were invited to use Divid',
+ text: 'VIL DU BRUK DIVID?',
+ from: 'Divid <divid@divid.no>',
+ }
+ emails.forEach(function(mailAddress) { // loops through all the emails and sets up each user
+ User.loadUser(mailAddress, function(err, user) {
+ if (err) return res.status(500).render('error', { title: '500', text: 'En serverfeil oppstod', error: err.stack });
+ if (!user) { //if the user doesn't exist, create one
+ console.log('fant ingen brukere med den eposten. må invitere og stasj');
+ var newUser = new User();
+ newUser.email = mailAddress;
+ newUser.username = mailAddress;
+ newUser.name = mailAddress + ' <span class="muted">(ikke registrert)</span>';
+ newUser.status = 1;
+ newUser.password = newUser.generateRandomToken(32);
+ newUser.randomToken = newUser.generateRandomToken(10, true);
+ newUser.save(function(err) {
+ if (err) return res.render('project/participants', { title: 'Nytt prosjekt - en feil oppstod', loggedin: true });
+ console.log('made new user ' + newUser._id);
+ var access = new Access();
+ access.user = newUser._id;
+ access.creator = req.user._id;
+ access.project = project._id;
+ access.randomToken = access.generateRandomToken(15);
+ access.save(function(err) {
+ if (err) {
+ console.log(err.errors);
+ return res.render('project/participants', { title: 'Nytt prosjekt - en feil oppstod', loggedin: true });
+ }
+ console.log('made new access for user ' + newUser._id);
+ message.to = newUser.email;
+ message.text = 'Hei! Du har blitt invitert til å delta i et Divid-prosjekt! https://divid.no/invite/' + newUser.randomToken + '\n Du kan også gå direkte til prosjektet her: https://divid.no/login/' + access.randomToken;
+ server.send(message, function(err, message) { console.log(err || message);});
+ });
+ });
+
+ } else { // if the user exists, add him to the project
+ Access.checkAccess(user._id, project._id, 0, function(err, acc) {
+ if (err) return res.render('project/participants', { title: 'Nytt prosjekt - en feil oppstod', loggedin: true });
+ if (acc) { // if the user already has access to the project.. do nothing
+ console.log('user ' + user.email + ' already has access to project ' + project.name);
+ } else {
+ console.log('fant en bruker. må lage ny access til han og si i fra.');
+ var access = new Access();
+ access.user = user._id;
+ access.creator = req.user._id;
+ access.project = project._id;
+ message.text = 'Du ble lagt til projektet "' + project.name + '"';
+ if (Number(user.status) < 3) {
+ access.randomToken = access.generateRandomToken(15);
+ message.text += '.\nDu kan få direkte tilgang til dette prosjektet her: https://divid.no/login/' + access.randomToken + ' \nDu kan bruke denne linken for å registrere deg, for å få tilgang til flere funksjoner: https://divid.no/invite/' + user.randomToken;
+ }
+ access.save(function(err) {
+ if (err) {
+ console.log(err.errors);
+ return res.render('project/participants', { title: 'Nytt prosjekt - en feil oppstod', loggedin: true });
+ }
+ console.log('made new access for user ' + user.username);
+ message.to = user.email;
+ server.send(message, function(err, message) { console.log(err || message);});
+ });
+ }
+ });
+ }
+ });
+ });
+
+ res.redirect('back');
+ });
+ });
+}
+
+
+/**
+ * claimInvite
+ * So users can use their inviteEmail
+ */
+
+exports.claimInvite = function(req, res) {
+
+ // first we need to check if the invite is valid!
+ User.findOne({ randomToken: sanitize(req.params.randomToken).escape(), status: 1 }, function(err, user) {
+ if (err) return res.status(500).render('error', { title: '500', text: 'En serverfeil oppstod', error: err.stack });
+ if (!user) return res.render('error', { title: 'This invite does not exist', text: 'Invitasjonen din er ugyldig' });
+
+ res.render('users/signup', {
+ invite: true,
+ title: 'Registrer deg!',
+ email: user.email }
+ );
+ });
+
+
+}
+
+
+exports.postClaimInvite = function(req, res) {
+
+ User.findOne({ randomToken: sanitize(req.params.randomToken).escape(), status: 1 }, function(err, user) {
+ if (err) return res.status(500).render('error', { title: '500', text: 'En serverfeil oppstod', error: err.stack });
+ if (!user) return res.render('error', { title: 'This invite does not exist', text: 'Invitasjonen din er ugyldig' });
+
+ v.check(req.body.password).notEmpty();
+ v.check(req.body.name).notEmpty();
+ v.check(req.body.username).notEmpty();
+
+ errors = v.getErrors();
+ if (errors.length !== 0) return res.status(500).render('error', { title: '500', text: 'Det oppstod en valideringsfeil<br>' + errors, error: errors });
+
+ user.name = sanitize(req.body.name).escape();
+ user.username = sanitize(req.body.username).escape();
+ user.password = req.body.password;
+ user.provider = 'local';
+ user.status = 3;
+ user.randomToken = '';
+ user.save(function(err) {
+ if (err) return res.render('signup', { errors: err.errors, user: user });
+ req.logIn(user, function(err) {
+ if (err) return next(err);
+ return res.redirect('/dashboard');
+ });
+ });
+ });
+}
+
diff --git a/app/models/Access.js b/app/models/Access.js
new file mode 100644
index 0000000..b9570e6
--- /dev/null
+++ b/app/models/Access.js
@@ -0,0 +1,129 @@
+
+/**
+ * Module dependencies
+ */
+
+var mongoose = require('mongoose')
+ , Schema = mongoose.Schema;
+
+
+/**
+ * Schema
+ *
+ * Permissions:
+ * 3 = normal
+ * 6 = admin
+ * 9 = owner
+ * These permissions are set in steps of three, in case
+ * we need to add more permissions later.
+ */
+
+var AccessSchema = new Schema({
+ user: { type: Schema.ObjectId, ref: 'User' },
+ creator: { type: Schema.ObjectId, ref: 'User' },
+ project: { type: Schema.ObjectId, ref: 'Project' },
+ permissions: { type: Number, default: '3' },
+ randomToken: { type: String },
+ created: { type: Date, default: Date.now },
+ updated: { type: Date, default: Date.now }
+});
+
+
+// the four validations below only apply if you are signing up traditionally
+
+AccessSchema.methods = {
+
+ /**
+ * Generate random access token for Remember Me function
+ *
+ * @param {Number} length
+ * @return {String}
+ * @api public
+ */
+
+ generateRandomToken: function(length) {
+ if (typeof(length) === undefined) length = 16; // default length of token
+ var chars = '_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
+ , token = '';
+ for (var i = 0; i < length; i++) {
+ var x = Math.floor(Math.random() * chars.length);
+ token += chars.charAt(x);
+ }
+ console.log('token ' + token);
+ return token;
+ }
+
+}
+
+AccessSchema.statics = {
+
+ /**
+ * Load ALL accesses for a single user
+ *
+ * @param {ObjectId} id
+ * @param {Function} callback
+ * @api private
+ */
+
+ loadUser: function(id, callback) {
+ this.find({ user: id })
+ .populate('project')
+ .sort({ 'created': -1 }) // sort by date
+ .exec(callback);
+ },
+
+
+ /**
+ * Load all users associated with a project
+ *
+ * @param {ObjectId} project
+ * @param {Function} callback
+ * @api private
+ */
+
+ loadProject: function(project, callback) {
+ this.find({ project: project })
+ .populate({path: 'user', select: '_id name'})
+ .sort({ 'created': 1 }) // sort by date
+ .exec(callback);
+ },
+
+
+ /**
+ * Load all users associated with several projects
+ *
+ * @param {Arrau[ObjectId]} projects
+ * @param {Function} callback
+ * @api private
+ */
+
+ loadProjects: function(projects, callback) {
+ this.find({ project: { $in: projects } })
+ .populate({ path: 'user', select: '_id name' })
+ .sort({ 'created': -1 })
+ .exec(callback);
+ },
+
+
+ /**
+ * Check to see if user has access to a particular project
+ *
+ * @param {ObjectId} user
+ * @param {ObjectId} project
+ * @param {Number} permissisons
+ * @param {Function} callback
+ * @api private
+ */
+
+ checkAccess: function(user, project, permissions, callback) {
+ if (typeof(permissions) === 'undefined') permissions = 0;
+ console.log('inni checkPermissions!')
+ this.findOne({ user: user })
+ .where('project').equals(project)
+ .where('permissions').gte(permissions)
+ .exec(callback);
+ }
+
+}
+
+mongoose.model('Access', AccessSchema);
diff --git a/app/models/Project.js b/app/models/Project.js
new file mode 100644
index 0000000..ba0e8e7
--- /dev/null
+++ b/app/models/Project.js
@@ -0,0 +1,75 @@
+
+/**
+ * Module dependencies
+ */
+
+var mongoose = require('mongoose')
+ , Schema = mongoose.Schema;
+
+var ProjectSchema = new Schema({
+ user: { type: Schema.ObjectId, ref: 'User' },
+ name: { type: String, default: '', trim: true },
+ description: {type: String, default: '', trim: true },
+ currency: { type: String, default: 'kr', trim: true },
+ public: { type: String, default: 'invite-only' },
+ created: { type: Date, default: Date.now },
+ updated: { type: Date, default: Date.now },
+ shortURL: { type: String, unique: true }
+});
+
+// the four validations below only apply if you are signing up traditionally
+
+ProjectSchema.path('name').validate(function(name) {
+ // if you're authenticated by any of the oauth strategies (facebook, twitter), don't validate
+ return name.length;
+}, 'Project name cannot be blank');
+
+
+ProjectSchema.pre('save', function(next) {
+ if (this.shortURL !== undefined) return next();
+ var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
+ this.shortURL = '';
+ for (var i = 0; i < 6; i++) {
+ var x = Math.floor(Math.random() * chars.length);
+ this.shortURL += chars.charAt(x);
+ }
+ console.log('SHORT: ' + this.shortURL);
+ next();
+});
+
+
+
+ProjectSchema.statics = {
+
+ /**
+ * Find project by id
+ *
+ * @param {ObjectId} id
+ * @param {Function} callback
+ * @api private
+ */
+
+ load: function(id, callback) {
+ this.findOne({ _id: id })
+ .populate('user')
+ .exec(callback);
+ },
+
+
+ /**
+ * Find project my shortURL
+ *
+ * @param {shortURL} shortURL
+ * @param {Function} callback
+ * @api private
+ */
+
+ loadShort : function(shortURL, callback) {
+ this.findOne({ shortURL: shortURL })
+ .populate('user')
+ .exec(callback);
+ }
+
+}
+
+mongoose.model('Project', ProjectSchema);
diff --git a/app/models/User.js b/app/models/User.js
new file mode 100644
index 0000000..0dc38f3
--- /dev/null
+++ b/app/models/User.js
@@ -0,0 +1,182 @@
+
+/**
+ * Module dependencies
+ */
+
+var mongoose = require('mongoose')
+ , Schema = mongoose.Schema
+ , crypto = require('crypto')
+ , authTypes = ['facebook', 'twitter'];
+
+
+/**
+ * User schema
+ *
+ * statuscodes:
+ * 1: invited
+ * 2: unconfirmed
+ * 3: active
+ * 4: paying user
+ */
+
+var UserSchema = new Schema({
+ name: String,
+ email: { type: String, unique: true },
+ username: String,
+ provider: String,
+ hashed_password: String,
+ salt: String,
+ accessToken: String,
+ facebook: {},
+ twitter: {},
+ status: { type: Number, default: 2 },
+ randomToken: String,
+ created: { type: Date, default: Date.now },
+ updated: { type: Date, default: Date.now }
+});
+
+
+/**
+ * Virtuals
+ */
+
+UserSchema
+ .virtual('password')
+ .set(function(password) {
+ this._password = password
+ this.salt = this.makeSalt()
+ this.hashed_password = this.encryptPassword(password)
+ }).get(function() { return this._password });
+
+
+/**
+ * Validations
+ */
+
+var validatePrecenceOf = function(value) {
+ return value && value.length;
+}
+
+// the four validations below only apply if you are signing up traditionally
+
+UserSchema.path('name').validate(function(name) {
+ // if you're authenticated by any of the oauth strategies (facebook, twitter), don't validate
+ if(authTypes.indexOf(this.provider) !== -1 || this.status === 1) return true;
+ return name.length;
+}, 'Name cannot be blank');
+
+UserSchema.path('email').validate(function(email) {
+ if(authTypes.indexOf(this.provider) !== -1) return true;
+ return email.length;
+}, 'Email cannot be blank');
+
+UserSchema.path('username').validate(function(username) {
+ if(authTypes.indexOf(this.provider) !== -1 || this.status === 1) return true;
+ return username.length;
+}, 'Username cannot be blank');
+
+UserSchema.path('hashed_password').validate(function(hashed_password) {
+ if(authTypes.indexOf(this.provider) !== -1) return true;
+ return hashed_password.length;
+}, 'Password cannot be blank');
+
+
+/**
+ * Pre-save hook
+ */
+
+UserSchema.pre('save', function(next) {
+ if (!this.isNew || this.status === 1) return next();
+
+ this.updated = Date.now();
+ next();
+
+});
+
+
+/**
+ * Methods
+ */
+
+UserSchema.methods = {
+
+ /**
+ * Authenticate - check if passwords are the same
+ *
+ * @param {String} plainText
+ * @return {Bolean}
+ * @api public
+ */
+
+ authenticate: function(plainText) {
+ return this.encryptPassword(plainText) === this.hashed_password;
+ },
+
+
+ /**
+ * Make salt
+ *
+ * @return {String}
+ * @api public
+ */
+
+ makeSalt: function() {
+ return Math.round((new Date().valueOf() * Math.random())) + '';
+ },
+
+
+ /**
+ * Encrypt password
+ *
+ * @param {String} password
+ * @return {String}
+ * @api public
+ */
+
+ encryptPassword: function(password) {
+ if (!password) return '';
+ return crypto.createHmac('sha1', this.salt).update(password).digest('hex');
+ },
+
+
+ /**
+ * Generate random access token for Remember Me function
+ *
+ * @param {Number} length
+ * @param {Boolean} noDate
+ * @return {String}
+ * @api public
+ */
+
+ generateRandomToken: function(length, noDate) {
+ if (typeof(length) === undefined) length = 16; // default length of token
+ var chars = '_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
+ , token = noDate ? '' : new Date().getTime() + '_';
+ for (var i = 0; i < length; i++) {
+ var x = Math.floor(Math.random() * chars.length);
+ token += chars.charAt(x);
+ }
+ return token;
+ }
+}
+
+UserSchema.statics = {
+
+ /**
+ * Load user from their email address
+ *
+ * @param {String} email
+ * @param {Function} callback
+ * @api private
+ */
+
+ loadUser: function(email, callback) {
+ this.findOne({ email: email })
+ .exec(callback);
+ }
+
+}
+
+mongoose.model('User', UserSchema);
+
+
diff --git a/app/models/pPost.js b/app/models/pPost.js
new file mode 100644
index 0000000..1f53984
--- /dev/null
+++ b/app/models/pPost.js
@@ -0,0 +1,78 @@
+
+/**
+ * Module dependencies
+ */
+
+var mongoose = require('mongoose')
+ , Schema = mongoose.Schema;
+
+var pPostSchema = new Schema({
+ user: { type: Schema.ObjectId, ref: 'User' },
+ for: { type: Schema.ObjectId, ref: 'User' },
+ project: { type: Schema.ObjectId, ref: 'Project' },
+ what: { type: String, default: '', trim: true },
+ comment: { type: String, default: '', trim: true },
+ participants: [],
+ value: { type: Number, defailt: 0 },
+ file: { type: String, default: '', trim: true },
+ currency: { type: String, default: 'kr', trim: true },
+ created: { type: Date, default: Date.now },
+ updated: { type: Date, default: Date.now },
+ when: { type: Date, default: Date.now }
+});
+
+
+
+
+pPostSchema.statics = {
+
+ /**
+ * Find post by id
+ *
+ * @param {ObjectId} id
+ * @param {Function} callback
+ * @api private
+ */
+
+ load: function(id, callback) {
+ this.findOne({ _id: id })
+ .populate({ path: 'user', select: '_id, name'})
+ .exec(callback);
+ },
+
+
+ /**
+ * Find all posts that belong to a project, by project id
+ *
+ * @param {ObjectId} project
+ * @param {Function} callback
+ * @api private
+ */
+
+ loadProject: function(project, callback) {
+ this.find({ project: project })
+ .populate('user')
+ .sort({ 'when': -1, 'created': -1 })
+ .exec(callback);
+ },
+
+
+ /**
+ * Find last ten posts belonging projects a user is part of, by project ids
+ *
+ * @param {Array[ObjectId]} projects
+ * @param {Function} callback
+ * @api private
+ */
+
+ loadByProjects: function(projects, callback) {
+ this.find({ project: { $in: projects } })
+ .populate({ path: 'user', select: '_id name' })
+ .populate({ path: 'project', select: 'name shortURL' })
+ .sort({ 'when': -1, 'created': -1 })
+ .exec(callback);
+ }
+
+}
+
+mongoose.model('pPost', pPostSchema);
diff --git a/app/views/contact.ejs b/app/views/contact.ejs
new file mode 100644
index 0000000..72268cb
--- /dev/null
+++ b/app/views/contact.ejs
@@ -0,0 +1,17 @@
+<% include templates/header %>
+</head>
+<body>
+
+ <% include templates/navbar %>
+
+ <!-- Wrapper
+ ================================================== -->
+<div class="container" id="wrapper">
+ <h1>Kontakt oss</h1>
+ <h3>Support</h3>
+ <p>Se gjerne igjennom vår <a href="https://divid.no/faq">faq</a> - ofte stilte spørsmål - før dere sender mail på support(at)divid.no.</p>
+ <h3>Business</h3>
+ <p>Ønsker du å kontakte oss for kjøp av annonseplass, forretninger og lignende ta kontakt på hallo(at)divid.no.</p>
+<% include templates/footer %>
+</body>
+</html>
diff --git a/app/views/dashboard.ejs b/app/views/dashboard.ejs
new file mode 100644
index 0000000..f2979b3
--- /dev/null
+++ b/app/views/dashboard.ejs
@@ -0,0 +1,154 @@
+<% include templates/header %>
+
+</head>
+<body>
+ <% include templates/navbar %>
+
+ <!-- Wrapper
+ ================================================== -->
+ <div class="container" id="wrapper">
+ <div class="row-fluid">
+
+ <div class="smallfullwidth span5">
+ <h1>Prosjekter</h1>
+ <section class="projects">
+ <% if (projects.length === 0) { %>
+ <p>Du har ingen aktive prosjekt. Du kan starte et prosjekt ved å klikke <a href="/project/new">her</a>.</p>
+ <% } else { projects.forEach(function(projects) { %>
+ <section class="project">
+ <div class="row-fluid">
+ <div class="span11">
+ <h1><a href="/project/<%= projects.project.shortURL %>"><strong><%= projects.project.name %></strong></a></h1>
+ <div class="row-fluid">
+ <div class="span8">
+ <small>
+ <% var ppl = 'Meg';
+ participants.forEach(function(participant) {
+ if (String(participant.project) === String(projects.project._id) && String(participant.user._id) !== String(user._id)) {
+ ppl += ', ' + participant.user.name;
+ }
+ }); %>
+ <%- ppl %>
+ </small>
+ </div>
+ <div class="span4">
+ <% s = (pro.project[projects.project._id].user - (pro.project[projects.project._id].total / pro.project[projects.project._id].users)).toFixed(2); %>
+ <small>Oppgjør: <%- s >= 0 ? '<span class="text-success">' + s : '<span class="text-error">' + s %></span> <%= projects.project.currency %></small>
+ </div>
+ </div>
+ </div>
+ <div class="span1">
+ <p class="flip"><a href="/project/<%= projects.project.shortURL %>/post">Før utgift</a></p>
+ </div>
+ </div>
+ </section>
+ <% }); } %>
+ <a href="/project/new" class="btn btn-large btn-block" type="button">+</a>
+ </section>
+ </div><!-- /div.span5 -->
+
+
+
+
+
+
+
+
+ <div class="smallfullwidth span7">
+ <section class="status">
+ <h1>Status total</h1>
+ <canvas id="myChart" width="530" height="200"></canvas>
+ </section>
+ <section class="overview">
+ <h1>Siste aktivitet</h1>
+ <div class="lastactivity">
+ <% posts.forEach(function(post) { %>
+ <div class="row-fluid post-<%= post._id %> activity">
+ <div class="row-fluid">
+ <div class="span1 date">
+ <%
+ var d = new Date(post.when);
+ var month = ['JAN', 'FEB', 'MAR', 'APR', 'MAI', 'JUN', 'JUL', 'AUG', 'SEP', 'OKT', 'NOV', 'DES'];
+ %>
+ <div class="row-fluid"><%= d.getDate() %></div>
+ <div class="row-fluid info"><%= month[d.getMonth()] %></div>
+ <div class="row-fluid"><a href="#details-<%= post._id %>" data-toggle="collapse" class="no-text-decoration" data-parent="#lastactivity">&#9660;</a></div>
+ </div>
+ <div class="span8">
+ <div class="row-fluid">
+ <div class="span2 info text-right smallfullwidth">prosjekt</div>
+ <div class="span10 smallfullwidth"><a href="/project/<%= post.project.shortURL %>"><%= post.project.name %></a></div>
+ </div>
+ <div class="row-fluid">
+ <div class="span2 info text-right smallfullwidth">av</div>
+ <div class="span10 smallfullwidth"><%= post.user.name === undefined ? post.user.email + ' <span class="muted">(ikke registrert)</span>' : post.user.name %></div>
+ </div>
+ <div class="row-fluid">
+ <div class="span2 info text-right smallfullwidth">hva</div>
+ <div class="span10 smallfullwidth"><%= post.what %></div>
+ </div>
+ </div>
+ <div class="span2">
+ <div class="row-fluid text-right">
+ <span class="info">sum</span>
+ <strong><%= post.value %> <%= post.currency %></strong>
+ </div>
+ <div class="row-fluid text-right">
+ <i class="icon-picture"></i>
+ </div>
+ </div>
+ </div>
+ <div class="fluid-row collapse details" id="details-<%= post._id %>">
+ <div class="span7">
+ <div class="row-fluid">
+ <div class="span2 info text-right smallfullwidth">kommentar</div>
+ <div class="span10">
+ <%= post.comment %>
+ </div>
+ </div>
+ </div>
+ <div class="span2">
+ <div class="row-fluid info">
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <% }); %>
+ </div>
+ </section>
+ </div><!-- /div.span7 -->
+
+
+ </div><!-- /div.row -->
+ </div><!-- /div.#wrapper -->
+
+
+<% include templates/footer %>
+ <script src="/js/Chart.min.js"></script>
+ <script>
+ var data = {
+ labels : ["January","February","March","April","May","June","July"],
+ datasets : [
+ {
+ fillColor : "rgba(220,220,220,0.5)",
+ strokeColor : "rgba(220,220,220,1)",
+ pointColor : "rgba(220,220,220,1)",
+ pointStrokeColor : "#fff",
+ data : [65,59,90,81,56,55,40]
+ },
+ {
+ fillColor : "rgba(151,187,205,0.5)",
+ strokeColor : "rgba(151,187,205,1)",
+ pointColor : "rgba(151,187,205,1)",
+ pointStrokeColor : "#fff",
+ data : [0,25,10,100,10,25,0]
+ }
+ ]
+ }
+ //var myLine = new Chart(document.getElementById("myChart").getContext("2d")).Line(data);
+ var ctx = $("#myChart").get(0).getContext("2d");
+ var myNewChart = new Chart(ctx).Line(data);
+ </script>
+</body>
+</html>
diff --git a/app/views/error.ejs b/app/views/error.ejs
new file mode 100644
index 0000000..47cc546
--- /dev/null
+++ b/app/views/error.ejs
@@ -0,0 +1,9 @@
+<% include header %>
+
+</head>
+<body>
+ <h1><%= title %></h1>
+ <p><%= text %></p>
+
+
+<% include footer %>
diff --git a/app/views/faq.ejs b/app/views/faq.ejs
new file mode 100644
index 0000000..d3473eb
--- /dev/null
+++ b/app/views/faq.ejs
@@ -0,0 +1,115 @@
+<% include templates/header %>
+</head>
+<body>
+
+ <% include templates/navbar %>
+
+ <!-- Wrapper
+ ================================================== -->
+<div class="container" id="wrapper">
+ <h1>Ofte stilte spørsmål</h1>
+
+ <ul class="unstyled">
+ <li><i class="icon-question-sign"></i> <a href="#faq1">Hvor kan jeg få tak i appen?</a></li>
+ <li><i class="icon-question-sign"></i> <a href="#faq2">Hvilke mobiltelefoner støtter Divid?</a></li>
+ <li><i class="icon-question-sign"></i> <a href="#faq3">Hvem eier dataene min?</a></li>
+ <li><i class="icon-question-sign"></i> <a href="#faq4">Hvor sikkert er Divid? Kan uvedkommede få tak i dataene mine?</a></li>
+ <li><i class="icon-question-sign"></i> <a href="#faq5">Kan jeg invitere folk som ikke er registrert?</a></li>
+ <li><i class="icon-question-sign"></i> <a href="#faq6">Savner muligheten til å eksportere prosjektene til excel, pdf eller csv.</a></li>
+ <li><i class="icon-question-sign"></i> <a href="#faq7">Deltakerene vil ikke betale tilbake det de skylder!</a></li>
+ <li><i class="icon-question-sign"></i> <a href="#faq8">Jeg delegerte ut administratorroller til andre deltakere, men det er full uenighet og prosjektet blir redigert - ingen vet hvem som skylder hvem hva</a></li>
+ <li><i class="icon-question-sign"></i> <a href="#faq9">Jeg får ikke varslinger fra Divid</a></li>
+ <li><i class="icon-question-sign"></i> <a href="#faq10">Jeg har lastet ned gratisversjonen, men vil ikke ha reklame - på app eller nettside?! Hva kan jeg gjøre?</a></li>
+ <li><i class="icon-question-sign"></i> <a href="#faq11">Jeg har alt kjøpt premiumversjonen, men slettet applikasjonen. Må jeg betale på nytt?</a></li>
+ <li><i class="icon-question-sign"></i> <a href="#faq12">Jeg har andre spørsmål enn det som står her. Hvor henvender jeg meg?</a></li>
+ <li><i class="icon-question-sign"></i> <a href="#faq13">Jeg representerer interesser som ønsker å investere eller kjøpe tjenesten Divid. Hvor henvender jeg meg?</a></li>
+ <li><i class="icon-question-sign"></i> <a href="#faq14">jeg vil ikke at mine data skal være lagret på serveren lengre. Kan jeg slette selv eller gjør dere det?</a></li>
+ <li><i class="icon-question-sign"></i> <a href="#faq15">Jeg vil ha tilbake pengene mine</a></li>
+ </ul>
+
+ <p>
+ <strong><a class="disabled" id="faq1">Hvor kan jeg få tak i appen?</a></strong><br>
+ <i class="icon-info-sign"></i> Applikasjonen er tilgjengelig gjennom App Store. Den blir tilgjengelig gjennom Google Play og Windows Mobile Store etterhvert.
+ </p>
+
+ <p>
+ <strong><a class="disabled" id="faq2">Hvilke mobiltelefoner støtter Divid?</a></strong><br>
+ <i class="icon-info-sign"></i> Divid støtter Iphone, Android, Windows mobile og Blackberry
+ </p>
+
+
+ <p>
+ <strong><a class="disabled" id="faq3">Hvem eier dataene min?</a></strong><br>
+ <i class="icon-info-sign"></i> Brukerenes data er brukerenes eie og de skal misbrukes. Personvernet skal opprettholdes i forhold til Norsk lov.
+ </p>
+
+ <p>
+ <strong><a class="disabled" id="faq4">Hvor sikkert er Divid? Kan uvedkommede få tak i dataene mine?</a></strong><br>
+ <i class="icon-info-sign"></i> Veldig.
+ </p>
+
+ <p>
+ <strong><a class="disabled" id="faq5">Kan jeg invitere folk som ikke er registrert?</a></strong><br>
+ <i class="icon-info-sign"></i> Ja, man kan invitere folk når prosjekt opprettes ved å fylle inn mailadressen deres. De får da en mailinvitasjon.
+ </p>
+
+ <p>
+ <strong><a class="disabled" id="faq6">Savner muligheten til å eksportere prosjektene til excel, pdf eller csv.</a></strong><br>
+ <i class="icon-info-sign"></i> Denne funksjonaliteten kommer og mer! Følg oss på Facebook for å få oppdateringer.
+ </p>
+
+ <p>
+ <strong><a class="disabled" id="faq7">Deltakerene vil ikke betale tilbake det de skylder!</a></strong><br>
+ <i class="icon-info-sign"></i> Man velger sine venner selv. Dette er en webtjeneste. Innkreving er et individuelt ansvar og her ligger tjenestens begrensning.
+ </p>
+
+ <p>
+ <strong><a class="disabled" id="faq8">Jeg delegerte ut administratorroller til andre deltakere, men det er full uenighet og prosjektet blir redigert - ingen vet hvem som skylder hvem hva</a></strong><br>
+ <i class="icon-info-sign"></i> Du er prosjektets eier og kan frata de administratorrollene i prosjektets innstillinger.
+ </p>
+
+ <p>
+ <strong><a class="disabled" id="faq9">Jeg får ikke varslinger fra Divid</a></strong><br>
+ <i class="icon-info-sign"></i> Du må sjekke prosjektets innstillinger om den funksjonaliteten er skrudd på. Er ikke det tilfelle, ta kontakt med oss gjennom Facebook likepagen vår eller på mail
+ </p>
+
+ <p>
+ <strong><a class="disabled" id="faq10">Jeg har lastet ned gratisversjonen, men vil ikke ha reklame - på app eller nettside?! Hva kan jeg gjøre?</a></strong><br>
+ <i class="icon-info-sign"></i> Kjøp premium versjonen av Divid. Da slipper du reklame for alltid og blir prioritert i servicesystemet vårt. Det er bare 35 kroner.
+ </p>
+
+ <p>
+ <strong><a class="disabled" id="faq11">Jeg har alt kjøpt premiumversjonen, men slettet applikasjonen. Må jeg betale på nytt?</a></strong><br>
+ <i class="icon-info-sign"></i> Nei, premium versjonen er til odel og eie. Den følger mailadressen din så det er bare å laste den ned igjen på nytt og logge inn med samme mailadresse.
+ </p>
+
+ <p>
+ <strong><a class="disabled" id="faq12">Jeg har andre spørsmål enn det som står her. Hvor henvender jeg meg?</a></strong><br>
+ <i class="icon-info-sign"></i> Du kan nå oss gjennom Facebook siden vår, forumet eller kontaktsiden. Disse lenkene finner du på toppen av siden.
+ </p>
+
+ <p>
+ <strong><a class="disabled" id="faq13">Jeg representerer interesser som ønsker å investere eller kjøpe tjenesten Divid. Hvor henvender jeg meg?</a></strong><br>
+ <i class="icon-info-sign"></i> Via kontaktsiden på toppen av siden her
+ </p>
+
+ <p>
+ <strong><a class="disabled" id="faq14">jeg vil ikke at mine data skal være lagret på serveren lengre. Kan jeg slette selv eller gjør dere det?</a></strong><br>
+ <i class="icon-info-sign"></i> Du har muligheten til å slette selv.
+ </p>
+
+ <p>
+ <strong><a class="disabled" id="faq15">Jeg vil ha tilbake pengene mine</a></strong><br>
+ <i class="icon-info-sign"></i> Det må du ta opp med butikken hvor du kjøpte applikasjonen.
+ </p>
+
+
+ <h4>Skulle du ha flere spørsmål sjekk forumet, se forum, Facebook like page eller kontakt oss på support(a)divid.no </h4>
+
+
+</div><!-- /div#wrapper -->
+
+
+ <% include templates/footer %>
+</body>
+</html>
diff --git a/app/views/home.ejs b/app/views/home.ejs
new file mode 100644
index 0000000..70dbb0f
--- /dev/null
+++ b/app/views/home.ejs
@@ -0,0 +1,164 @@
+<% include header %>
+<link rel="stylesheet" href="/css/use.css" />
+<link rel="stylesheet" href="/css/devanim.css">
+</head>
+<body>
+
+ <% include navbar %>
+
+ <!-- Wrapper
+ ================================================== -->
+<div class="container" id="wrapper">
+ <div class="row">
+ <!-- content
+ ================================================== -->
+ <div class="span12 content">
+ <div class="container row">
+
+ <!-- Main hero unit for a primary marketing message or call to action -->
+ <div class="span12 showcase row">
+ <div class="span5 pitch">
+ <div class="span12 row">
+ <h1>Samarbeid om utgifter</h1>
+ <p>Divid er en delingstjeneste som regner ut hva folk skylder hverandre</p>
+ <ul class="blue">
+ </li><h3><i class="icon-pencil"></i> Registrer deg gratis</h3></li>
+ </li><h3><i class="icon-play"></i> Opprett prosjekt</h3></li>
+ </li><h3><i class="icon-user"></i> Inviter deltakere</h3></li>
+ </li><h3><i class="icon-barcode"></i> Før inn utgiftene</h3></li>
+ </li><h3><i class="icon-ok"></i> Ta et oppgjør</h3></li>
+ </ul>
+ </div>
+ <div class="span12 row">
+ <p>Perfekt for venner, familie og bekjente</p>
+ <a href="#" class="btn btn-large register">Registrer »</a>
+ </div>
+ </div>
+ <div class="span7 dash">
+ <img src="/img/dashboard.png">
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="span12 content">
+ <div class="container">
+ <!-- Example row of columns -->
+ <div class="row">
+ <div class="span3 infobox" id="first">
+ <img class="infoimg" src="/img/laptop.png">
+ <h4>Bruk mobil eller nettleser</h4>
+ <p>Divid er en webapplikasjon og kan brukes på pc, nettbrett og mobil. Uansett hva du bruker er Divid tilgjengelig.</p>
+ </div>
+ <div class="span3 infobox" id="second">
+ <img class="infoimg" src="/img/addpeople.png">
+ <h4>Inviter de du vil</h4>
+ <p>Inviter deltakere til prosjekt ved å legge til epost-adressen deres eller send dem en link!</p>
+ </div>
+ <div class="span3 infobox" id="third">
+ <img class="infoimg" src="/img/overwatch.png">
+ <h4>Få oversikt</h4>
+ <p>Ikke la delte utgifter gå i glemmeboken. Send påminnelser og få varsel når deltakere betaler.</p>
+ </div>
+ </div>
+ <div id="hva" class="span12 content">
+ <div class="container last">
+ <div class="span12">
+ <h1>Hva kan Divid brukes til</h1>
+ </div>
+ <div class="span2 scenario">
+ <img src="/img/student.png">
+ <h4>Studentkollektiv</h4>
+ <p>Fellesutgifter, fester, bøter, bursdager, øl, mat, strøm</p>
+ </div>
+ <div class="span2 scenario">
+ <img src="/img/fest.png">
+ <h4>Singelliv</h4>
+ <p>Ute på farten, stelle i stand aktiviter med andre, sydentur osv</p>
+ </div>
+ <div class="span2 scenario">
+ <img src="/img/par.png">
+ <h4>Parforhold</h4>
+ <p>I etableringsfasen som ønsker å ha ordnet økonomi fra starten av</p>
+ </div>
+ <div class="span2 scenario">
+ <img src="/img/omsorg.png">
+ <h4>Delt omsorg</h4>
+ <p>Klær, mat, medisiner og aktiviteter. Hvem betaler hva for barnet?</p>
+ <!--<p>klær, mat, reiser, aktiviteter, sport, skolebøker, tannlege, medisiner</p>--!>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div id="hvor" class="span12 content">
+ <div class="container last">
+ <div class="span6 sectionleft">
+ <h1>Hvordan bruke Divid</h1>
+ </div>
+ <div class="span6 sectionright">
+ <h1>Tilgjengelig via:</h1>
+ </div>
+ <div class="span7 sectionleft">
+ <div class="span5 sectionleft tutorial">
+ <iframe src="http://player.vimeo.com/video/41974181" width="500" height="281" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>
+ </div>
+ </div>
+ <div class="span5 sectionright">
+ <a href="https://itunes.apple.com/us/genre/ios-finance/id6015?mt=8"><img src="/img/iph.png" onmouseover="this.src='/img/iphoneA.png'" onmouseout="this.src='/img/iph.png'"></a>
+ <a href="https://play.google.com/store"><img src="/img/android.png" onmouseover="this.src='/img/androidA.png'" onmouseout="this.src='/img/android.png'"></a>
+ <a href="http://www.windowsphone.com/nb-no/store"><img src="/img/win.png" onmouseover="this.src='/img/winA.png'" onmouseout="this.src='/img/win.png'"></a>
+ </div>
+ </div>
+ </div>
+ <div id="hvordan" class="span12 content">
+ <div class="container last">
+ <input type="hidden" id="userId">
+ <div id="account-form-container">
+ <form method="post" id="account-form" class="form-horizontal well span6">
+ <h1></h1>
+ <h1>Registrering</h1>
+ <hr>
+ <fieldset>
+ <div id="name-cg" class="control-group">
+ <label for="name-tf" class="control-label">Name</label>
+ <div class="controls">
+ <input id="name-tf" type="text" name="name" class="input-xlarge">
+ </div>
+ </div>
+ <div id="email-cg" class="control-group">
+ <label for="email-tf" class="control-label">Email</label>
+ <div class="controls">
+ <input id="email-tf" type="text" name="email" class="input-xlarge">
+ </div>
+ </div>
+ <hr>
+ <p id="sub2" class="subheading"></p>
+ <div id="user-cg" class="control-group">
+ <label for="user-tf" class="control-label">Username</label>
+ <div class="controls">
+ <input id="user-tf" type="text" name="username" class="input-xlarge disabled">
+ </div>
+ </div>
+ <div id="pass-cg" class="control-group">
+ <label for="pass-tf" class="control-label">Password</label>
+ <div class="controls">
+ <input id="pass-tf" type="password" name="password" value="" class="input-xlarge">
+ </div>
+ </div>
+ <div class="form-actions cut">
+ <button type="button" id="account-form-btn1" class="btn">Avbryt</button>
+ <button type="submit" id="account-form-btn2" class="btn">Registrer</button>
+ </div>
+ </fieldset>
+ </form>
+ </div>
+ </div>
+ </div><!-- /div.row -->
+ </div><!-- /div#wrapper -->
+ <!--<div id="footer">
+ <div class="container">
+ <p>!!!!!!!!!!!!!!!!!!!!</p>
+ </div>
+ </div>-->
+<% include footer %>
+</body>
+</html>
diff --git a/app/views/index.ejs b/app/views/index.ejs
new file mode 100644
index 0000000..0768773
--- /dev/null
+++ b/app/views/index.ejs
@@ -0,0 +1,131 @@
+<% include templates/header %>
+
+</head>
+<body>
+
+ <% include templates/navbar %>
+ <div class="indexwrapper" id="index1">
+ <div class="container">
+ <div class="row-fluid">
+ <div class="span5">
+ <h1><%= title %></h1>
+ <p>Velkommen til <%= title %></p>
+ <p>Her kommer det <em>kanskje</em> mer senere.</p>
+ <ul class="blue">
+ </li><h3><i class="icon-pencil"></i> Registrer deg gratis</h3></li>
+ </li><h3><i class="icon-play"></i> Opprett prosjekt</h3></li>
+ </li><h3><i class="icon-user"></i> Inviter deltakere</h3></li>
+ </li><h3><i class="icon-barcode"></i> Før inn utgiftene</h3></li>
+ </li><h3><i class="icon-ok"></i> Ta et oppgjør</h3></li>
+ </ul>
+ <p>Perfekt for venner, familie og bekjente!</p>
+ <a href="#register" class="btn btn-large btn-warning">Registrer deg!</a>
+ </div>
+ <div class="span7">
+ <img src="/img/dashboard.png">
+ </div>
+ </div>
+ <div class="row-fluid">
+ <div class="span4 infobox">
+ <img class="infoimg" src="/img/laptop.png">
+ <h4>Bruk mobil eller nettleser</h4>
+ <p>Divid er en webapplikasjon og kan brukes på pc, nettbrett og mobil. Uansett hva du bruker er Divid tilgjengelig.</p>
+ </div>
+ <div class="span4 infobox">
+ <img class="infoimg" src="/img/addpeople.png">
+ <h4>Inviter de du vil</h4>
+ <p>Inviter deltakere til prosjekt ved å legge til epost-adressen deres eller send dem en link!</p>
+ </div>
+ <div class="span4 infobox">
+ <img class="infoimg" src="/img/overwatch.png">
+ <h4>Få oversikt</h4>
+ <p>Ikke la delte utgifter gå i glemmeboken. Send påminnelser og få varsel når deltakere betaler.</p>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="indexwrapper" id="index2">
+ <div class="container">
+ <h1>Hva kan Divid brukes til</h1>
+ <div class="row-fluid">
+ <div class="span3 infobox">
+ <img src="/img/student.png">
+ <h4>Studentkollektiv</h4>
+ <p>Fellesutgifter, fester, bøter, bursdager, øl, mat, strøm</p>
+ </div>
+ <div class="span3 infobox">
+ <img src="/img/fest.png">
+ <h4>Singelliv</h4>
+ <p>Ute på farten, stelle i stand aktiviter med andre, sydentur osv</p>
+ </div>
+ <div class="span3 infobox">
+ <img src="/img/par.png">
+ <h4>Parforhold</h4>
+ <p>I etableringsfasen som ønsker å ha ordnet økonomi fra starten av</p>
+ </div>
+ <div class="span3 infobox">
+ <img src="/img/omsorg.png">
+ <h4>Delt omsorg</h4>
+ <p>Klær, mat, medisiner og aktiviteter. Hvem betaler hva for barnet?</p>
+ <!--<p>klær, mat, reiser, aktiviteter, sport, skolebøker, tannlege, medisiner</p>--!>
+ </div>
+ </div>
+ </div>
+ </div>
+
+
+ <div class="indexwrapper" id="index3">
+ <div class="container">
+ <h1>Hvordan bruke Divid</h1>
+
+ <a href="https://itunes.apple.com/us/genre/ios-finance/id6015?mt=8"><img src="/img/iph.png" onmouseover="this.src='/img/iphoneA.png'" onmouseout="this.src='/img/iph.png'"></a>
+ <a href="https://play.google.com/store"><img src="/img/android.png" onmouseover="this.src='/img/androidA.png'" onmouseout="this.src='/img/android.png'"></a>
+ <a href="http://www.windowsphone.com/nb-no/store"><img src="/img/win.png" onmouseover="this.src='/img/winA.png'" onmouseout="this.src='/img/win.png'"></a>
+ </div>
+ </div>
+
+
+ <div class="indexwrapper" id="index4">
+ <div class="container">
+ <h1>Registrer deg i dag!</h1>
+ <p>Du kan enten bruke <a href="/auth/facebook">Facebook</a> eller <a href="/auth/twitter">Twitter</a>, eller registrere deg med epost under!</p>
+ <div class="control-group">
+ <label class="control-label" for="name">Navn</label>
+ <div class="controls">
+ <input type="text" id="reg_name" name="name" required>
+ </div>
+ </div>
+ <div class="control-group">
+ <label class="control-label" for="email">E-post</label>
+ <div class="controls">
+ <input type="email" id="reg_email" name="email" required>
+ </div>
+ </div>
+ <div class="control-group">
+ <label class="control-label" for="username">Brukernavn</label>
+ <div class="controls">
+ <input type="text" id="reg_username" name="username" required>
+ </div>
+ </div>
+ <div class="control-group">
+ <label class="control-label" for="password">Passord</label>
+ <div class="controls">
+ <input type="password" id="reg_password" name="password" required>
+ </div>
+ </div>
+ <div class="control-group">
+ <div class="form-actions"><a id="register" class="hidden">a</a>
+ <input type="submit" class="btn btn-primary" value="Registrer!">
+ </div>
+ </div>
+
+ </div>
+ </div>
+
+
+
+
+<% include templates/footer %>
+</body>
+</html>
diff --git a/app/views/project/newProject.ejs b/app/views/project/newProject.ejs
new file mode 100644
index 0000000..2101138
--- /dev/null
+++ b/app/views/project/newProject.ejs
@@ -0,0 +1,79 @@
+<% include ../templates/header %>
+
+</head>
+<body>
+ <% include ../templates/navbar %>
+
+ <!-- Wrapper
+ ================================================== -->
+ <div class="container" id="wrapper">
+ <div class="row-fluid">
+
+
+ <form class="form-horizontal" action="/project/new" method="post">
+ <fieldset>
+
+ <h1><legend><%= title %></legend></h1>
+
+ <div class="control-group">
+ <label class="control-label">Prosjektnavn</label>
+ <div class="controls">
+ <input id="projectname" name="name" placeholder="" type="text" required="" maxlength="25">
+ <p class="help-block">Navnet på prosjektet du vil lage</p>
+ </div>
+ </div>
+
+ <div class="control-group">
+ <label class="control-label">Beskrivelse</label>
+ <div class="controls">
+ <textarea id="description" name="description" class="span6"></textarea>
+ </div>
+ </div>
+
+ <div class="control-group">
+ <label class="control-label">Valuta</label>
+ <div class="controls">
+ <span class="input-small uneditable-input">kr</span>
+ <!-- <input id="currency" name="currency" type="text" placeholder="kr" class="span2" required=""> -->
+ </div>
+ </div>
+
+<!-- <div class="control-group">
+ <label class="control-label">Invite only eller offentlig?</label>
+ <div class="controls">
+ <label class="radio">
+ <input type="radio" name="public" value="Invite only" checked="checked">
+ Invite only
+ </label>
+ <label class="radio">
+ <input type="radio" name="public" value="Offentlig">
+ Offentlig
+ </label>
+ </div>
+ </div>-->
+
+
+ <div class="control-group">
+ <label class="control-label">Double Button</label>
+ <div class="controls">
+ <button type="submit" id="button1id" name="button1id" class="btn btn-primary">Opprett prosjekt</button>
+ <button type="reset" id="button2id" name="button2id" class="btn">Nullstill</button>
+ </div>
+ </div>
+
+ </fieldset>
+ </form>
+
+
+
+
+
+
+
+ </div><!-- /div.row -->
+ </div><!-- /div.#wrapper -->
+
+
+<% include ../templates/footer %>
+</body>
+</html>
diff --git a/app/views/project/participants.ejs b/app/views/project/participants.ejs
new file mode 100644
index 0000000..4341a4f
--- /dev/null
+++ b/app/views/project/participants.ejs
@@ -0,0 +1,55 @@
+<% include ../templates/header %>
+
+</head>
+<body>
+ <% include ../templates/navbar %>
+
+ <!-- Wrapper
+ ================================================== -->
+ <div class="container" id="wrapper">
+ <div class="row-fluid">
+
+
+ <form class="form-horizontal" method="post">
+ <fieldset>
+
+ <h1><legend><%= title %></legend></h1>
+ <p>Her kan du invitere venner til å delta i prosjektet ditt. Skriv inn eposadressene deres, en på hver linje, i tekstboksen under.</p>
+ <div class="control-group">
+ <label class="control-label">Epostadresser</label>
+ <div class="controls">
+ <textarea id="emails" name="emails" class="span6"></textarea>
+ </div>
+ </div>
+
+ <div class="control-group">
+ <label class="control-label">Beskrivelse</label>
+ <div class="controls">
+ <textarea id="description" name="description" class="span6">Hei! Jeg har oppdaget et nytt og kult program... Bla bla bla. Stian og Erling fixes.</textarea>
+ </div>
+ </div>
+
+ <div class="control-group">
+ <label class="control-label"></label>
+ <div class="controls">
+ <button type="submit" id="button1id" name="button1id" class="btn btn-primary">Inviter</button>
+ <button type="reset" id="button2id" name="button2id" class="btn">Nullstill</button>
+ </div>
+ </div>
+
+ </fieldset>
+ </form>
+
+
+
+
+
+
+
+ </div><!-- /div.row -->
+ </div><!-- /div.#wrapper -->
+
+
+<% include ../templates/footer %>
+</body>
+</html>
diff --git a/app/views/project/post.ejs b/app/views/project/post.ejs
new file mode 100644
index 0000000..5e8f283
--- /dev/null
+++ b/app/views/project/post.ejs
@@ -0,0 +1,103 @@
+<% include ../templates/header %>
+
+</head>
+<body>
+ <% include ../templates/navbar %>
+
+ <!-- Wrapper
+ ================================================== -->
+ <div class="container" id="wrapper">
+ <div class="row-fluid">
+
+
+ <form class="form-horizontal" method="post">
+ <input type="hidden" name="project" value="<%= project._id %>">
+ <fieldset>
+
+ <h1><legend><%= title %></legend></h1>
+ <div class="control-group">
+ <label for="username" class="control-label">Av</label>
+ <div class="controls">
+ <span class="input-medium uneditable-input"><%= req.user.username %></span>
+ </div>
+ </div>
+ <div class="control-group">
+ <label for="what" class="control-label">Hva <strong class="text-error">*</strong></label>
+ <div class="controls">
+ <input type="text" name="what" id="what" placeholder="Hva ble kjøpt" required maxlength="40">
+ </div>
+ </div>
+ <%
+ // we need to populate the date- and timefield with the current time and date
+ var d = new Date();
+ var n = d.getFullYear() + '-' + ('0' + (d.getMonth()+1)).slice(-2) + '-' + ('0' + d.getDate()).slice(-2);
+ var t = d.toLocaleTimeString().slice(0, 5);
+ %>
+ <!-- <%= d %> -->
+ <div class="control-group">
+ <label for="date" class="control-label">Når</label>
+ <div class="controls">
+ <input type="date" name="date" value="<%= n %>" class="input-medium">
+ <input type="time" name="time" value="<%= t %>" class="input-medium">
+ </div>
+ </div>
+ <div class="control-group">
+ <label for="cost" class="control-label">Hvor mye <strong class="text-error">*</strong></label>
+ <div class="controls">
+ <input type="number" name="value" id="value" class="input-small" placeholder="0" required>
+ </div>
+ </div>
+<!-- <div class="control-group">
+ <label for="split_between" class="control-label">Delt på</label>
+ <div class="controls">
+
+ <span class="selectAll">Select all</span>
+ <select name="participants[]" id="participants" multiple="multiple">
+ <option value="5180e11b0074a8b029000001" selected="selected">Dennis</option>
+ <option value="51814b792c94cc5346000001" selected="selected">Kurt</option>
+ </select>
+ </div>
+ </div>
+ <div class="control-group">
+ <label for="file" class="control-label">Kvittering</label>
+ <div class="controls">
+ <input type="file" name="file" id="file">
+ </div>
+ </div>-->
+ <div class="control-group">
+ <label for="comment" class="control-label">Kommentar</label>
+ <div class="controls">
+ <textarea id="comment" name="comment" class="span6"></textarea>
+ </div>
+ </div>
+
+ <div class="control-group">
+ <div class="form-actions">
+ <button type="submit" id="button1id" name="button1id" class="btn btn-primary">Post</button>
+ <button type="reset" id="button2id" name="button2id" class="btn">Nullstill</button>
+ </div>
+ </div>
+
+ </fieldset>
+ </form>
+
+
+
+
+
+
+
+ </div><!-- /div.row -->
+ </div><!-- /div.#wrapper -->
+
+
+<% include ../templates/footer %>
+<!-- <script>
+ $(".selectAll").click(function() {
+ $('#participants').children().attr('selected','selected');
+ //$(this).parent().find('option').attr('selected','selected');
+ });
+</script>-->
+
+</body>
+</html>
diff --git a/app/views/project/project.ejs b/app/views/project/project.ejs
new file mode 100644
index 0000000..7e06dad
--- /dev/null
+++ b/app/views/project/project.ejs
@@ -0,0 +1,220 @@
+<% include ../templates/header %>
+
+</head>
+<body>
+ <% include ../templates/navbar %>
+
+ <!-- Wrapper
+ ================================================== -->
+ <div class="container" id="wrapper">
+ <div class="row-fluid">
+ <div class="span6 smallfullwidth">
+ <div class="row-fluid">
+ <div class="span2 info text-right">
+ prosjekt
+ </div>
+ <div class="span10">
+ <h1><%= project.name %></h1>
+ </div>
+ </div>
+ <div class="row-fluid">
+ <div class="span2 info text-right">
+ opprettet
+ </div>
+ <div class="span10">
+ <p>
+ <% var d = new Date(project.created); %>
+ <%= d.getFullYear() + '-' + ('0' + (d.getMonth()+1)).slice(-2) + '-' + ('0' + d.getDate()).slice(-2) + ' ' + d.toLocaleTimeString().slice(0, 5) %>
+ </p>
+ </div>
+ </div>
+ <div class="row-fluid">
+ <div class="span2 info text-right">
+ deltakere
+ </div>
+ <div class="span10">
+ <% access.forEach(function(participants) { %>
+ <%- participants.user.name %><% if (participants.permissions >= 6) { %> <span class="muted">(<%= participants.permissions === 9 ? 'eier' : 'admin' %>)</span><% } %><br>
+ <% }); %>
+ <small><a href="/project/<%= project.shortURL %>/participants">Legg til flere deltakere</a></small>
+ </div>
+ </div>
+ <div class="row-fluid">
+ <div class="span10 offset2">
+ <a class="btn btn-large" href="/project/<%= project.shortURL %>/post">Før utgift</a>
+ </div>
+ </div>
+ </div><!-- /div.span6 -->
+
+
+
+
+
+
+
+
+ <div class="span6 smallfullwidth" id="accordion">
+ <section class="status">
+ <div class="row-fluid">
+ <div class="span6 smallfullwidth">
+ <h2>Status total</h2>
+ </div>
+ <div class="span6 smallfullwidth">
+ <div class="row-fluid">
+ <table class="table table-bordered table-condensed">
+ <tr>
+ <td class="success"><%= pro.user[req.user._id].total %></td>
+ <td class="error"><%= pro.total %></td>
+ <td><%= pro.user[req.user._id].diff %></td>
+ </tr>
+ </table><a href="#table-info" class="accordion-toggle" data-toggle="collapse"><i class="icon-info-sign"></i></a>
+ </div>
+ </div>
+ </div>
+ <div class="row-fluid accordion-body collapse" id="table-info">
+ <p>Det er til sammen brukt <strong><%= (pro.total).toFixed(2) %></strong> <%= project.currency %>. Deltakerne skal altså betale <strong><%= (pro.each).toFixed(2) %></strong> <%= project.currency %> hver.</p>
+ <% for (var i in pro.user) { %>
+ <%- pro.user[i].name %> har betalt <%= pro.user[i].total %> <%= project.currency %>, og <%- pro.user[i].diff >= 0 ? 'skyldes <span class="text-success">' + pro.user[i].diff : 'skylder <span class="text-error">' + Math.abs(pro.user[i].diff) %></span> <%= project.currency %><br>
+ <% } %>
+ <p><small><a href="#example" data-toggle="collapse" class="accordion-toggle">Eksempel på hvordan oppgjøret kan gjøres</a></small></p>
+ </div>
+ <div class="row-fluid collapse" id="example">
+ <table>
+ <%
+ // FUGLY LAST-MINUTE CODE
+ var i = 1;
+ for (var u in pro.user) {
+ if (pro.user[u].coeff === 0) {
+ if (i === 1) {%>
+ <tr>
+ <td></td>
+ <% for (var p in pro.user) { %>
+ <%- pro.user[p].coeff > 0 ? '<td>' + pro.user[p].name + '</td>' : '' %>
+ <% } %>
+ </tr>
+ <% } %>
+ <tr>
+ <td><%- pro.user[u].name %></td>
+ <% for (var p in pro.user) { %>
+ <%- pro.user[p].coeff > 0 ? '<td>' + (Math.abs(pro.user[u].diff) * pro.user[p].coeff).toFixed(2) + '</td>' : '' %>
+ <% } %>
+ </tr>
+<% i++;
+ }} %>
+ </table>
+
+ </div>
+ <div class="row-fluid accordion-body in collapse" id="chart">
+ <canvas id="myChart" width="450" height="200"></canvas>
+ </div>
+ </section>
+ </div>
+ </div>
+
+
+
+
+
+
+
+
+ <div class="row-fluid">
+ <div class="span12 smallfullwidth">
+ <section class="overview">
+ <h2>Siste aktivitet</h2>
+ <div class="lastactivity" id="lastactivity">
+ <% posts.forEach(function(post) { %>
+ <div class="row-fluid post-<%= post._id %> activity">
+ <div class="row-fluid">
+ <div class="span1 date">
+ <%
+ var d = new Date(post.when);
+ var month = ['JAN', 'FEB', 'MAR', 'APR', 'MAI', 'JUN', 'JUL', 'AUG', 'SEP', 'OKT', 'NOV', 'DES'];
+ %>
+ <div class="row-fluid"><%= d.getDate() %></div>
+ <div class="row-fluid info"><%= month[d.getMonth()] %></div>
+ <div class="row-fluid"><a href="#details-<%= post._id %>" data-toggle="collapse" class="no-text-decoration" data-parent="#lastactivity">&#9660;</a></div>
+ </div>
+ <div class="span6">
+ <div class="row-fluid">
+ <div class="span2 info text-right smallfullwidth">av</div>
+ <div class="span10 smallfullwidth"><%- post.user.name %></div>
+ </div>
+ <div class="row-fluid">
+ <div class="span2 info text-right smallfullwidth">hva</div>
+ <div class="span10 smallfullwidth"><%= post.what %></div>
+ </div>
+ </div>
+ <div class="span2">
+ <div class="row-fluid">
+ &nbsp;
+ </div>
+ </div>
+ <div class="span2">
+ <div class="row-fluid text-right">
+ <span class="info">sum</span>
+ <strong><%= post.value %> <%= post.currency %></strong>
+ </div>
+ <div class="row-fluid text-right">
+ <i class="icon-picture"></i>
+ </div>
+ </div>
+ </div>
+ <div class="fluid-row collapse details" id="details-<%= post._id %>">
+ <div class="span7">
+ <div class="row-fluid">
+ <div class="span2 info text-right smallfullwidth">kommentar</div>
+ <div class="span10">
+ <%= post.comment %>
+ </div>
+ </div>
+ </div>
+ <% if (String(post.user._id) === String(req.user._id) || req.user.permissions >= 6) { %>
+ <div class="span1">
+ <small><a href="/project/<%= project.shortURL %>/edit/<%= post._id %>">[edit]</a></small>
+ </div>
+ <div class="span1">
+ <small><a href="/project/<%= project.shortURL %>/delete/<%= post._id %>">[delete]</a></small>
+ </div>
+ <% } %>
+ </div>
+ </div>
+
+ <% }); %>
+ </div>
+ </section>
+ </div><!-- /div.span7 -->
+
+
+ </div><!-- /div.row -->
+ </div><!-- /div.#wrapper -->
+
+
+<% include ../templates/footer %>
+ <script src="/js/Chart.min.js"></script>
+ <script>
+ var data = {
+ labels : ["January","February","March","April","May","June","July"],
+ datasets : [
+ {
+ fillColor : "rgba(220,220,220,0.5)",
+ strokeColor : "rgba(220,220,220,1)",
+ pointColor : "rgba(220,220,220,1)",
+ pointStrokeColor : "#fff",
+ data : [65,59,90,81,56,55,40]
+ },
+ {
+ fillColor : "rgba(151,187,205,0.5)",
+ strokeColor : "rgba(151,187,205,1)",
+ pointColor : "rgba(151,187,205,1)",
+ pointStrokeColor : "#fff",
+ data : [0,25,10,100,10,25,0]
+ }
+ ]
+ }
+ //var myLine = new Chart(document.getElementById("myChart").getContext("2d")).Line(data);
+ var ctx = $("#myChart").get(0).getContext("2d");
+ var myNewChart = new Chart(ctx).Line(data);
+ </script>
+</body>
+</html>
diff --git a/app/views/template.ejs b/app/views/template.ejs
new file mode 100644
index 0000000..6803c37
--- /dev/null
+++ b/app/views/template.ejs
@@ -0,0 +1,18 @@
+<% include templates/header %>
+
+</head>
+<body>
+ <% include templates/navbar %>
+
+ <!-- Wrapper
+ ================================================== -->
+ <div class="container" id="wrapper">
+ <div class="row-fluid">
+
+ </div><!-- /div.row -->
+ </div><!-- /div.#wrapper -->
+
+
+<% include templates/footer %>
+</body>
+</html>
diff --git a/app/views/templates/footer.ejs b/app/views/templates/footer.ejs
new file mode 100644
index 0000000..2421d82
--- /dev/null
+++ b/app/views/templates/footer.ejs
@@ -0,0 +1,20 @@
+
+
+
+ <!--
+ Le javascript
+ ==================================================
+ Placed at the end of the document so the pages load faster
+ -->
+ <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
+ <script>window.jQuery || document.write('<script src="/js/jquery-1.9.0.min.js"><\/script>')</script>
+ <script src="/js/bootstrap.min.js"></script>
+ <script src="/js/retina.js"></script>
+ <script>
+ (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+ })(window,document,'script','/js/analytics.js','ga');
+ ga('create', 'UA-39435674-1', 'divid.no');
+ ga('send', 'pageview');
+ </script>
diff --git a/app/views/templates/header.ejs b/app/views/templates/header.ejs
new file mode 100644
index 0000000..815be5c
--- /dev/null
+++ b/app/views/templates/header.ejs
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8" />
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
+
+ <title><%= title %></title>
+ <meta name="description" content="" />
+ <meta name="author" content="">
+
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <link rel="stylesheet" href="/css/bootstrap.css" />
+ <link rel="stylesheet" href="/css/bootstrap-responsive.css">
+
+ <link rel="stylesheet" href="/css/shame.css" />
+
diff --git a/app/views/templates/navbar.ejs b/app/views/templates/navbar.ejs
new file mode 100644
index 0000000..f72947d
--- /dev/null
+++ b/app/views/templates/navbar.ejs
@@ -0,0 +1,73 @@
+ <!-- Navbar
+ ================================================== -->
+
+ <div class="navbar navbar-inverse navbar-fixed-top">
+ <div class="navbar-inner" id="top-navbar">
+ <div class="container">
+ <% if (user === undefined) { %>
+ <div class="row-fluid collapse login-collapse">
+ <div class="span6">
+ <!--<img src="/img/logo_white.png">-->
+ </div>
+ <div class="span6">
+ <form action="/login" method="post" id="login-form" class="form-horizontal">
+ <div class="control-group">
+ <div class="input-prepend">
+ <span class="add-on"><i class="icon-envelope icon-white"></i></span>
+ <input type="email" name="email" id="email" placeholder="E-post" required>
+ </div>
+ </div>
+ <div class="control-group">
+ <div class="input-prepend">
+ <span class="add-on"><i class="icon-lock icon-white"></i></span>
+ <input type="password" id="password" name="password" placeholder="Passord" required>
+ </div>
+ </div>
+ <div class="row-fluid">
+ <div class="span7">
+ <label class="checkbox">
+ <input type="checkbox" name="rememberme"> Remember me
+ </label>
+ </div>
+ <div class="span5">
+ <button type="submit" class="btn btn-inverse btn-small">Logg inn</button>
+ </div>
+ </div>
+ <div class="row-fluid">
+ Eller logg inn med <a href="/auth/facebook">facebook</a> / <a href="/auth/twitter">twitter</a>
+ </div>
+ </form>
+ </div>
+ </div>
+ <% } %>
+ <div class="row-fluid">
+ <a href="/"><img class="logo" src="/img/dividlogo.png"></a>
+ <!--<a class="brand" href="#">Divid</a>--!>
+ <div class="pull-right">
+ <button type="button" 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>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ </button>
+ <div class="login">
+ <% if(user === undefined) { %><a class="login" data-toggle="collapse" data-target=".login-collapse" href="#login">Logg inn</a>
+ <% } else { %>Logget inn som <%= user.username %> <a href="/logout" class="login">Logg ut</a>
+ <% } %>
+ </div>
+ </div>
+ <div class="nav-collapse collapse">
+ <ul class="nav menu">
+ <li><a href="/faq">FAQ</a></li>
+ <li><a href="/contact">Kontakt</a></li>
+ <li><a href="/project/new">Nytt prosjekt</a></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+
+
diff --git a/app/views/test.ejs b/app/views/test.ejs
new file mode 100644
index 0000000..03a8aee
--- /dev/null
+++ b/app/views/test.ejs
@@ -0,0 +1,46 @@
+<% include templates/header %>
+</head>
+<body>
+
+ <% include templates/navbar %>
+
+ <!-- Wrapper
+ ================================================== -->
+ <div class="container" id="wrapper">
+ <div class="row">
+ <!-- docs navbar
+ ================================================== -->
+ <div class="span3 bs-docs-sidebar">
+ <ul class="nav nav-list bs-docs-sidenav affix">
+ <li><a href="#"><i class="icon-chevron-right"></i> Smurfetits</a></li>
+ <li><a href="#"><i class="icon-chevron-right"></i> Gangnam Style</a></li>
+ <li><a href="#tit"><i class="icon-chevron-right"></i> Scheiße</a></li>
+ </ul>
+ </div>
+
+
+ <!-- content
+ ================================================== -->
+ <div class="span9 content">
+ <section class="content">
+ <h1><%= title %></h1>
+ <p>Velkommen til <%= title %></p>
+ <p>Her kommer det <em>kanskje</em> mer senere.</p>
+ </section>
+ <section class="content">
+ <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam vestibulum, mauris molestie interdum venenatis, sapien diam vestibulum arcu, sit amet ultrices urna sem et ipsum. Pellentesque dapibus tellus tristique augue sollicitudin mollis. Donec consectetur scelerisque lacus sit amet ullamcorper. Maecenas lectus ante, iaculis vitae consequat quis, viverra non lacus. Vestibulum vestibulum lacinia ullamcorper. Nam facilisis blandit turpis sit amet ultricies. Nulla facilisi. Donec non quam risus. Suspendisse venenatis nisl ut dolor imperdiet in eleifend nulla sagittis. Cras facilisis tempus sapien. In dapibus sodales aliquet. Nullam blandit, elit non convallis congue, velit augue facilisis odio, vel blandit turpis purus nec eros. Donec vel ipsum tellus, id lobortis justo. Vivamus ac porta nisi. Suspendisse malesuada convallis velit, non eleifend metus vehicula vitae. Ut pretium, diam nec iaculis gravida, nunc lacus accumsan arcu, et laoreet elit justo nec libero.</p>
+ <p>Integer sit amet lacus lectus, quis laoreet nisl. Pellentesque ut augue odio, eget placerat mauris. Phasellus tortor libero, placerat at interdum id, luctus scelerisque ipsum. Maecenas auctor feugiat aliquam. Nullam eu lorem quis est euismod elementum. Integer sit amet nulla at dui semper pellentesque eget id sem. Sed bibendum nisl id eros ullamcorper ut condimentum justo tempus. Nam eget neque arcu, ac pulvinar justo. Nunc ac justo vel risus ultrices aliquam vel vehicula velit. Nullam faucibus, sapien eget volutpat commodo, erat ipsum congue ante, non facilisis lacus erat non eros. Pellentesque facilisis semper nibh ac tincidunt. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis vitae magna massa, eu laoreet libero.</p>
+ </section>
+ <section id="tit" class="content">
+ <h2>Would you?</h2>
+ <a href="https://fbcdn-sphotos-a-a.akamaihd.net/hphotos-ak-prn1/483553_10151560007790395_695693936_n.jpg"><img src="https://fbcdn-sphotos-a-a.akamaihd.net/hphotos-ak-prn1/483553_10151560007790395_695693936_n.jpg" class="img-polaroid" /></a>
+ <p>Cras ac erat arcu, condimentum posuere lectus. Suspendisse mollis volutpat ipsum, ac posuere quam rutrum vitae. Nullam dignissim, diam eu posuere blandit, diam nibh congue eros, a posuere magna diam ut metus. Sed vehicula commodo lobortis. Aliquam erat volutpat. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Etiam a purus lorem, non laoreet libero. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras bibendum, ligula non tristique consequat, erat lacus porttitor orci, eu viverra ipsum nunc nec risus.</p>
+ <p> Donec vitae felis et quam tempor vestibulum vel at diam. Donec felis mauris, euismod vel interdum ac, commodo quis nunc. Nulla nec libero diam, in tempus arcu. Cras justo neque, sodales vel rhoncus nec, placerat ut nunc. Mauris convallis urna non erat varius malesuada. Curabitur eu mauris purus, ut suscipit lorem. Ut convallis varius lacus nec sollicitudin. Fusce egestas ultricies justo, et gravida neque mollis vel. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;</p>
+ </section>
+ </div><!-- /div.span9 -->
+ </div><!-- /div.row -->
+ </div><!-- /div#wrapper -->
+
+<% include templates/footer %>
+</body>
+</html>
diff --git a/app/views/users/registerEmail.ejs b/app/views/users/registerEmail.ejs
new file mode 100644
index 0000000..bdf5b65
--- /dev/null
+++ b/app/views/users/registerEmail.ejs
@@ -0,0 +1,43 @@
+<% include ../templates/header %>
+
+</head>
+<body>
+
+ <!-- Wrapper
+ ================================================== -->
+ <div class="container" id="wrapper">
+ <div class="row-fluid">
+
+ <form class="form-horizontal" method="post">
+ <fieldset>
+
+ <h1><legend><%= title %></legend></h1>
+ <p>Vær vennlig å registrer eposten din</p>
+
+ <div class="control-group">
+ <label class="control-label">Epost-adresse</label>
+ <div class="controls">
+ <div class="input-prepend">
+ <span class="add-on"><i class="icon-envelope"></i></span>
+ <input type="email" name="email" id="email" placeholder="E-post" required>
+ </div>
+ </div>
+ </div>
+ <div class="control-group">
+ <div class="form-actions">
+ <button type="submit" id="buttonSubmit" name="submit" class="btn btn-primary">Registrer</button>
+ <button type="reset" id="buttonReset" name="reset" class="btn">Nullstill</button>
+ </div>
+ </div>
+
+
+ </fieldset>
+ </form>
+
+ </div><!-- /div.row -->
+ </div><!-- /div.#wrapper -->
+
+
+<% include ../templates/footer %>
+</body>
+</html>
diff --git a/app/views/users/signup.ejs b/app/views/users/signup.ejs
new file mode 100644
index 0000000..611c052
--- /dev/null
+++ b/app/views/users/signup.ejs
@@ -0,0 +1,86 @@
+<% include ../templates/header %>
+ <link rel="stylesheet" href="/css/login.css" />
+</head>
+<body>
+
+ <input type="hidden" id="userId">
+ <div id="account-form-container">
+ <form method="post" id="account-form" class="form-horizontal well span6">
+ <h1></h1>
+ <p id="sub1" class="subheading">Please tell us a little about yourself.</p>
+ <hr>
+ <fieldset>
+ <div id="name-cg" class="control-group">
+ <label for="name-tf" class="control-label">Name</label>
+ <div class="controls">
+ <input id="name-tf" type="text" name="name" class="input-xlarge">
+ </div>
+ </div>
+ <div id="email-cg" class="control-group">
+ <label for="email-tf" class="control-label">Email</label>
+ <div class="controls">
+ <% if (invite) { %>
+ <span class="input uneditable-input"><%= email %></span>
+ <% } else { %>
+ <input id="email-tf" type="text" name="email" class="input-xlarge">
+ <% } %>
+ </div>
+ </div>
+ <hr>
+ <p id="sub2" class="subheading"></p>
+ <div id="user-cg" class="control-group">
+ <label for="user-tf" class="control-label">Username</label>
+ <div class="controls">
+ <input id="user-tf" type="text" name="username" class="input-xlarge disabled">
+ </div>
+ </div>
+ <div id="pass-cg" class="control-group">
+ <label for="pass-tf" class="control-label">Password</label>
+ <div class="controls">
+ <input id="pass-tf" type="password" name="password" value="" class="input-xlarge">
+ </div>
+ </div>
+ <div class="form-actions">
+ <button type="button" id="account-form-btn1" class="btn">Cancel</button>
+ <button type="submit" id="account-form-btn2" class="btn">Submit</button>
+ </div>
+ </fieldset>
+ </form>
+ </div>
+ <!-- display form errors in a custom modal window //-->
+ <div class="modal-form-errors modal hide fade">
+ <div class="modal-header">
+ <button data-dismiss="modal" class="close">x</button>
+ <h3>Whoops!</h3>
+ </div>
+ <div class="modal-body">
+ <p class="subheading">It looks like there was a problem.</p>
+ <ul></ul>
+ </div>
+ <div class="modal-footer">
+ <button data-dismiss="modal" class="btn btn-warning">OK</button>
+ </div>
+ </div>
+
+
+
+
+
+ <div class="modal-alert modal hide fade">
+ <div class="modal-header">
+ <button data-dismiss="modal" class="close">x</button>
+ <h3></h3>
+ </div>
+ <div class="modal-body">
+ <p></p>
+ </div>
+ <div class="modal-footer">
+ <button data-dismiss="modal" id="ok" class="btn btn-warning">OK</button>
+ </div>
+ </div>
+ <script src="/js/views/signup.js"></script>
+ <script src="/js/form-validators/accountValidator.js"></script>
+ <script src="/js/controllers/signupController.js"></script>
+
+
+<% include ../templates/footer %>