Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

DRY and improve profile display info

Link emails, githubs, twitters, etc.
  • Loading branch information...
commit 0e51f15a8f46ea72b86190ab0b0bc8fce5b7cf1f 1 parent fbaabc9
@isaacs isaacs authored
View
26 config.js
@@ -32,17 +32,29 @@ exports.errorPage = { debug: true }
exports.debug = true
-// probably don't need to change these.
+// probably don't need to change these too often.
// extra fields we hang on the profile.
+// format: [title, display template, url test]
+// if it doesn't have a url test, then urls are not allowed.
+// The actual value is escaped, so no markup is allowed ever.
exports.profileFields =
-{ fullname: "Full Name"
-, email: "Email"
-, github: "Github Username"
-, twitter: "Twitter Username"
-, homepage: "Homepage URL"
-, freenode: "IRC Handle"
+{ fullname: [ 'Full Name', '%s' ]
+, email: [ 'Email', '<a href="mailto:%s">%s</a>', function (u) {
+ return u.protocol === 'mailto:'
+ } ]
+, github: [ 'Github', '<a href="https://github.com/%s">%s</a>',
+ hostmatch(/^github.com$/) ]
+, twitter: [ 'Twitter', '<a href="https://twitter.com/%s">@%s</a>',
+ hostmatch(/^twitter.com$/) ]
+, homepage: [ 'Homepage', '<a href="%s">%s</a>',
+ hostmatch(/[^\.]+\.[^\.]+$/) ]
+, freenode: [ 'IRC Handle', '%s' ]
}
+function hostmatch (m) { return function (u) {
+ return u.host && u.host.match(m)
+} }
+
exports.emailFrom = '"The npm Website Robot" <webmaster@npmjs.org>'
// For development only!
View
16 models/profile.js
@@ -1,17 +1,11 @@
module.exports = profile
-
-var gravatar = require('gravatar').url
+var transform = require('./showprofile.js').transform
function profile (req, required, cb) {
if (typeof required === 'function') cb = required, required = false
req.session.get('profile', function (er, data) {
if (!required && er) er = null
- if (data) {
- var gr = data.email ? 'retro' : 'mm'
- data.avatar = gravatar(data.email || '', {s:50, d:gr}, true)
- data.avatarLarge = gravatar(data.email || '', {s:496, d:gr}, true)
- }
-
+ if (data) transform(data)
if (er || data) return cb(er, req.profile = data)
// if we're logged in, try to see if we can get it
@@ -25,11 +19,7 @@ function profile (req, required, cb) {
// Oh well. Probably the login expired.
return cb(er)
}
-
- var gr = data.email ? 'retro' : 'mm'
- data.avatar = gravatar(data.email || '', {s:50, d:gr}, true)
- data.avatarLarge = gravatar(data.email || '', {s:496, d:gr}, true)
-
+ transform(data)
req.session.set('profile', data)
return cb(null, req.profile = data)
})
View
42 models/showprofile.js
@@ -1,19 +1,49 @@
module.exports = showprofile
+module.exports.transform = transform
var gravatar = require('gravatar').url
-, npm = require('npm')
+var npm = require('npm')
+var gravatar = require('gravatar').url
+var sanitizer = require('sanitizer')
+var config = require('../config.js')
+var util = require('util')
+var url = require('url')
+
function showprofile (name, cb) {
// get the most recent data for this req.
npm.registry.get('/-/user/org.couchdb.user:' + name, 0, function (er, data) {
-
if (er || !data) return cb(er, data)
-
- var gr = data.email ? 'retro' : 'mm'
- data.avatar = gravatar(data.email || '', {s:50, d:gr}, true)
- data.avatarLarge = gravatar(data.email || '', {s:496, d:gr}, true)
+ cb(er, transform(data))
cb(er, data)
})
}
+function transform (data) {
+ var gr = data.email ? 'retro' : 'mm'
+ data.avatar = gravatar(data.email || '', {s:50, d:gr}, true)
+ data.avatarLarge = gravatar(data.email || '', {s:496, d:gr}, true)
+
+ data.fields = loadFields(data)
+}
+
+function loadFields (profile) {
+ return Object.keys(config.profileFields).map(function (f) {
+ var val = sanitizer.escape(profile[f] || '')
+ var title = config.profileFields[f][0] || f
+ var tpl = config.profileFields[f][1] || '%s'
+ var show = val ? tpl.replace(/%s/g, val) : ''
+ var urlTest = config.profileFields[f][2]
+ show = show && sanitizer.sanitize(show, function (u) {
+ u = url.parse(u)
+ return (!u || !u.href || !urlTest || !urlTest(u)) ? '' : u.href
+ }) || ''
+ return {
+ name: f,
+ value: val,
+ title: title,
+ show: show
+ }
+ })
+}
View
3  routes/profile-edit.js
@@ -95,7 +95,8 @@ function show (req, res) {
}
var locals = {
profile: profile,
- fields: config.profileFields,
+ fields: profile.fields,
+
title: 'Edit profile'
}
res.template("profile-edit.ejs", locals)
View
6 routes/profile.js
@@ -1,7 +1,5 @@
module.exports = profile
-var config = require('../config.js')
-
// thing for editing bits of your profile.
// gets saved back to couchdb.
function profile (req, res) {
@@ -48,9 +46,11 @@ function showProfile (req, res, showprofile) {
return res.redirect('/login')
}
+ var profile = req.model.profile
+
var td = { showprofile: showprofile
, profile: req.model.profile
- , fields: config.profileFields
+ , fields: showprofile.fields
, title: showprofile.name
, packages: req.model.packages
, starred: req.model.starred
View
7 templates/profile-edit.ejs
@@ -7,11 +7,12 @@
<input type=hidden name=_id value="<%= profile._id %>">
<input type=hidden name=name value="<%= profile.name %>">
<%
-Object.keys(fields).forEach(function (f) {
+fields.forEach(function (field) {
%>
<fieldset>
- <label for="<%= f %>"><%= fields[f] %></label>
- <input id="<%= f %>" name="<%= f %>" value="<%= profile[f] || '' %>">
+ <label for="<%= field.name %>"><%= field.title %></label>
+ <input id="<%= field.name %>" name="<%= field.name %>"
+ value="<%= field.value %>">
</fieldset>
<%
})
View
6 templates/profile.ejs
@@ -26,11 +26,11 @@
<table width="100%">
<%
-Object.keys(fields).forEach(function (f) {
+fields.forEach(function (field) {
%>
<tr>
- <th><%= fields[f] %></th>
- <td><%= showprofile[f] || '' %></td>
+ <th><%= field.title %></th>
+ <td><%- field.show || '' %></td>
</tr>
<%
})
Please sign in to comment.
Something went wrong with that request. Please try again.