diff --git a/app.js b/app.js index 63f21d0b58..d6459bee35 100644 --- a/app.js +++ b/app.js @@ -243,6 +243,10 @@ app.get( '/challenges/:challengeNumber', challengesController.returnChallenge ); +app.get( + '/users/:username', + userController.returnUser +); app.all('/account', passportConf.isAuthenticated); app.get('/account', userController.getAccount); app.post('/account/profile', userController.postUpdateProfile); diff --git a/controllers/user.js b/controllers/user.js index 1e7cda9948..c95d68669c 100644 --- a/controllers/user.js +++ b/controllers/user.js @@ -1,14 +1,16 @@ -var _ = require('lodash'); -var async = require('async'); -var crypto = require('crypto'); -var nodemailer = require('nodemailer'); -var passport = require('passport'); -var User = require('../models/User'); -var secrets = require('../config/secrets'); -var moment = require('moment'); -var Challenge = require('./../models/Challenge'); +var _ = require('lodash'), + async = require('async'), + crypto = require('crypto'), + nodemailer = require('nodemailer'), + passport = require('passport'), + User = require('../models/User'), + secrets = require('../config/secrets'), + moment = require('moment'), + Challenge = require('./../models/Challenge'), + debug = require('debug')('freecc:cntr:challenges'); //TODO(Berks): Refactor to use module.exports = {} pattern. + /** * GET /login * Login page. @@ -148,6 +150,50 @@ exports.getAccount = function(req, res) { }); }; +/** + * GET /users/:username + * Public Profile page. + */ + +exports.returnUser = function(req, res, next) { + User.find({'profile.username': req.params.username}, function(err, user) { + if (err) { debug('Username err: ', err); next(err); } + if (user[0]) { + var user = user[0]; + Challenge.find({}, null, {sort: {challengeNumber: 1}}, function (err, c) { + res.render('account/show', { + title: 'Code Camper: ', + username: user.profile.username, + name: user.profile.name, + location: user.profile.location, + coderbyteProfile: user.profile.linkedinProfile, + githubProfile: user.profile.githubProfile, + linkedinProfile: user.profile.linkedinProfile, + website1: user.portfolio.website1Link, + website1Title: user.portfolio.website1Title, + website1Image: user.portfolio.website1Image, + website2: user.portfolio.website2Link, + website2Title: user.portfolio.website2Title, + website2Image: user.portfolio.website2Image, + website3: user.portfolio.website3Link, + website3Title: user.portfolio.website3Title, + website3Image: user.portfolio.website3Image, + picture: user.profile.picture, + challenges: c, + ch: user.challengesHash, + moment: moment + }); + }); + } else { + req.flash('errors', { + msg: "We couldn't find a Code Camper with that username." + }); + return res.redirect('/'); + } + }); +}; + + /** * POST /update-progress * Update profile information. @@ -217,6 +263,16 @@ exports.postUpdateProfile = function(req, res, next) { user.profile.username = req.body.username || ''; user.profile.location = req.body.location || ''; user.profile.website = req.body.website || ''; + user.portfolio.website1Title = req.body.website1Title || ''; + user.portfolio.website1Link = req.body.website1Link || ''; + user.portfolio.website1Image = req.body.website1Image || ''; + user.portfolio.website2Title = req.body.website2Title || ''; + user.portfolio.website2Link = req.body.website2Link || ''; + user.portfolio.website2Image = req.body.website2Image || ''; + user.portfolio.website3Title = req.body.website3Title || ''; + user.portfolio.website3Link = req.body.website3Link || ''; + user.portfolio.website3Image = req.body.website3Image || ''; + user.save(function (err) { if (err) return next(err); diff --git a/models/User.js b/models/User.js index 121d26bccc..4c54cd336c 100644 --- a/models/User.js +++ b/models/User.js @@ -6,6 +6,7 @@ var userSchema = new mongoose.Schema({ email: { type: String, lowercase: true, + unique: true, trim: true }, password: String, @@ -13,7 +14,6 @@ var userSchema = new mongoose.Schema({ twitter: String, google: String, github: String, - instagram: String, linkedin: String, tokens: Array, points: { @@ -264,6 +264,13 @@ var userSchema = new mongoose.Schema({ } }, profile: { + username: { + type: String, + default: '', + unique: true, + lowercase: true, + trim: true + }, name: { type: String, default: '' }, @@ -273,23 +280,59 @@ var userSchema = new mongoose.Schema({ location: { type: String, default: '' }, - website: { - type: String, - default: '' - }, picture: { type: String, default: '' }, - username: { + linkedinProfile: { + type: String, default: '' + }, + githubProfile: { + type: String, default: '' + }, + coderbyteProfile: { type: String, - default: '', - //unique: true, - lowercase: true, - trim: true + default: '' + } + }, + portfolio: { + website1Link: { + type: String, + default: '' + }, + website1Title: { + type: String, + default: '' + }, + website1Image: { + type: String, + default: '' + }, + website2Link: { + type: String, + default: '' + }, + website2Title: { + type: String, + default: '' + }, + website2Image: { + type: String, + default: '' + }, + website3Link: { + type: String, + default: '' + }, + website3Title: { + type: String, + default: '' + }, + website3Image: { + type: String, + default: '' } }, - resetPasswordToken: String, resetPasswordExpires: Date }); diff --git a/public/css/main.less b/public/css/main.less index 1bb54700c6..c439dbb6cf 100644 --- a/public/css/main.less +++ b/public/css/main.less @@ -380,4 +380,9 @@ thead { margin-top:-2px !important; padding-top: 10px !important; padding-bottom: 10px !important; +} + +.nameline { + margin-top: -5px; + font-size: 40px; } \ No newline at end of file diff --git a/views/account/profile.jade b/views/account/profile.jade index 811dd70c33..0221bcaaf1 100644 --- a/views/account/profile.jade +++ b/views/account/profile.jade @@ -2,36 +2,70 @@ extends ../layout block content .panel - .container.text-center - h1 Update your profile here: - .animated.flipInX - form.form-horizontal(action='/account/profile', method='POST') - input(type='hidden', name='_csrf', value=_csrf) - .form-group - label.col-sm-3.col-sm-offset-2.control-label(for='name') Name - .col-sm-4 - input.form-control(type='text', name='name', id='name', value='#{user.profile.name}') - .form-group - label.col-sm-3.col-sm-offset-2.control-label(for='username') Username (use letters, numbers, underscore) * - .col-sm-4 - input.form-control(type='text', name='username', id='username', value='#{user.profile.username}') - .form-group - label.col-sm-3.col-sm-offset-2.control-label(for='email') Email * - .col-sm-4 - input.form-control(type='email', name='email', id='email', value='#{user.email}') - .form-group - label.col-sm-3.col-sm-offset-2.control-label(for='location') Location - .col-sm-4 - input.form-control(type='text', name='location', id='location', value='#{user.profile.location}') - .form-group - label.col-sm-3.col-sm-offset-2.control-label(for='website') Website - .col-sm-4 - input.form-control(type='text', name='website', id='website', value='#{user.profile.website}') - .form-group - .col-sm-offset-2.col-sm-4 - button.btn.btn.btn-primary(type='submit') - span.ion-edit - | Update my profile + .container.text-center + h1 Update your profile here: + form.form-horizontal(action='/account/profile', method='POST') + input(type='hidden', name='_csrf', value=_csrf) + .form-group + label.col-sm-3.col-sm-offset-2.control-label(for='name') Name + .col-sm-4 + input.form-control(type='text', name='name', id='name', value='#{user.profile.name}') + .form-group + label.col-sm-3.col-sm-offset-2.control-label(for='username') Username (use letters, numbers, underscore) * + .col-sm-4 + input.form-control(type='text', name='username', id='username', value='#{user.profile.username}') + .form-group + label.col-sm-3.col-sm-offset-2.control-label(for='email') Email * + .col-sm-4 + input.form-control(type='email', name='email', id='email', value='#{user.email}') + .form-group + label.col-sm-3.col-sm-offset-2.control-label(for='location') Location + .col-sm-4 + input.form-control(type='text', name='location', id='location', value='#{user.profile.location}') + + + + .form-group + label.col-sm-3.col-sm-offset-2.control-label(for='website1Title') 1st Portfolio Website Title + .col-sm-4 + input.form-control(type='text', name='website1Title', id='website1Title', value='#{user.portfolio.website1Title}') + .form-group + label.col-sm-3.col-sm-offset-2.control-label(for='website1Link') 1st Portfolio Website Link + .col-sm-4 + input.form-control(type='text', name='website1Link', id='website1Link', value='#{user.portfolio.website1Link}') + .form-group + label.col-sm-3.col-sm-offset-2.control-label(for='website1Image') 1st Portfolio Website Image Link + .col-sm-4 + input.form-control(type='text', name='website1Image', id='website1Image', value='#{user.portfolio.website1Image}') + .form-group + label.col-sm-3.col-sm-offset-2.control-label(for='website2Title') 2nd Portfolio Website Title + .col-sm-4 + input.form-control(type='text', name='website2Title', id='website2Title', value='#{user.portfolio.website2Title}') + .form-group + label.col-sm-3.col-sm-offset-2.control-label(for='website2Link') 2nd Portfolio Website Link + .col-sm-4 + input.form-control(type='text', name='website2Link', id='website2Link', value='#{user.portfolio.website2Link}') + .form-group + label.col-sm-3.col-sm-offset-2.control-label(for='website2Image') 2nd Portfolio Website Image Link + .col-sm-4 + input.form-control(type='text', name='website2Image', id='website2Image', value='#{user.portfolio.website2Image}') + .form-group + label.col-sm-3.col-sm-offset-2.control-label(for='website3Title') 3rd Portfolio Website Title + .col-sm-4 + input.form-control(type='text', name='website3Title', id='website3Title', value='#{user.portfolio.website3Title}') + .form-group + label.col-sm-3.col-sm-offset-2.control-label(for='website3Link') 3rd Portfolio Website Link + .col-sm-4 + input.form-control(type='text', name='website3Link', id='website3Link', value='#{user.portfolio.website3Link}') + .form-group + label.col-sm-3.col-sm-offset-2.control-label(for='website3Image') 3rd Portfolio Website Image Link + .col-sm-4 + input.form-control(type='text', name='website3Image', id='website3Image', value='#{user.portfolio.website3Image}') + .form-group + .col-sm-offset-2.col-sm-4 + button.btn.btn.btn-primary(type='submit') + span.ion-edit + | Update my profile .panel .big-break .container.text-center diff --git a/views/account/show.jade b/views/account/show.jade new file mode 100644 index 0000000000..40c3d149b3 --- /dev/null +++ b/views/account/show.jade @@ -0,0 +1,32 @@ +extends ../layout +block content + .panel.panel-primary + .panel-heading.text-center @#{username} + .panel-body + .row + .col-xs-2.col-sm-1.col-md-1 + img(src="#{picture}") + .col-xs-4.col-sm-2.col-md-2 + h2.nameline + = "[ " + user.points + " ]" + .col-xs-6.col-sm-9.col-md-9 + h2.nameline + = name + h4= location + a(href="#{coderbyteProfile") + | Coderbyte Profile + - if (ch[0] > 0) + .container + h1 Completed Challenges + .col-xs-12 + table.table.table-striped + thead + tr + th Challenge + th Date Finished + for challenge in challenges + if ch[challenge.challengeNumber] > 0 + tr + td= challenges[challenge.challengeNumber].name + td= moment(ch[challenge.challengeNumber], 'X').format("MMM DD, YYYY") + br \ No newline at end of file