-
Notifications
You must be signed in to change notification settings - Fork 1
07. User profiles and publishes
In 1batch, there are two URLs for profiles:
/profile - your own profile / editing space
/profile/mapmeld - the profile for another user ("mapmeld"). If you go to your own profile with this URL, you should be redirected back to /profile
These are two separate router.get() calls in app.js. The simpler one is another user's profile, because we only request public information, and we don't require you to be logged in at all:
// someone else's profile
router.get('/profile/:username', async function (ctx) {
var requser = ctx.req.user;
if (requser && ctx.params.username.toLowerCase() === requser.name) {
// redirect to your own profile
return ctx.redirect('/profile');
}
if (ctx.params.username.indexOf('@') > -1) {
// usernames which are still emails are anonymous
return printNoExist(ctx);
}
// we're looking for the one user with this name (there should only be one)
// the only public information that's interesting to us is their _id, username, and whether they publicly posted yet
// your app may need more fields to be public
var user = await User.findOne({ name: req.params.username.toLowerCase() }, '_id username posted').exec();
if (!user) { throw 'user does not exist'; }
// request all images which are published by this user, get source urls
var images = await Image.find({ published: true, hidden: false, user_id: user.name }).select('_id src').exec();
// there's a function called responsiveImg which returns proper URLs from Cloudinary
// we'll talk about it later
images = images.map(responsiveImg);
ctx.render('profile', {
user: user, // the user who created this profile
images: images, // the user's images
posted: user.posted, // the user's post date (if they posted)
forUser: (requser || null), // whether the browsing user is signed in or not
csrfToken: ctx.csrf
});
});responsiveImg is going to be used several times. It takes in an array of Image objects, and asks Cloudinary to return formatted URLs for that image. It also requests the image in multiple sizes, which we can use to show people this page on desktop, mobile, or retina screens. responsiveImg looks like this:
function responsiveImg(img, makeBig) {
var baseSize = 300;
if (makeBig) {
baseSize *= 2;
}
var geturl = cloudinary.url;
var out = {
_id: img._id,
src: {
mini: geturl(img.src, { format: "jpg", width: baseSize * 2/3, height: baseSize * 2/3, crop: "fill" }).replace('http:', ''),
main: geturl(img.src, { format: "jpg", width: baseSize, height: baseSize, crop: "fill" }).replace('http:', ''),
retina: geturl(img.src, { format: "jpg", width: baseSize * 2, height: baseSize * 2, crop: "fill" }).replace('http:', '')
}
};
return out;
}Another detail is we remove 'http:' from the Cloudinary URL. Browsers can throw errors when an HTTPS page has an HTTP resource, and vice versa. Using // means to keep the same protocol as the current page.
Now we can design the view of the profile page itself, using Jade templating:
extends ./layout.jade
block content
.row
.col-sm-12.underbar
if forUser
a.btn.btn-info.pull-right(href="/logout") Log Out
else
a.btn.btn-primary.pull-right(href="/profile") Log In
h2
a(href="/feed") 1batch
small an app for sharing 8 photos
.row
.col-sm-12.col-md-6
h1= user.name
if posted
h4 posted #{posted}
else
h4 hasn't posted yet!
if posted
.row.profilephotos
for index in [0, 1, 2, 3]
if index < images.length
.col-sm-6.col-lg-3
img(src=images[index].src.main, srcset="#{images[index].src.main} 1x, #{images[index].src.retina} 2x")
.row.profilephotos
for index in [4, 5, 6, 7]
if index < images.length
.col-sm-6.col-lg-3
img(src=images[index].src.main, srcset="#{images[index].src.main} 1x, #{images[index].src.retina} 2x")