Started adding personal page support. Pages render but not well.

parent d7116634
......@@ -70,17 +70,20 @@ class PublicTimelineWeaver
personSublevel = @db.sublevel accountHandle
personSublevel.put timestamp, messageID
# Store the messages by person also so we can quickly stream them on their own pages.
personMessagesSublevel = @db.sublevel "#{accountHandle}-messages"
personMessagesSublevel.put messageID, message
#
# Everyone timeline
#
getPostsAfter: (key, limit = 20) =>
getPostsAfter: (timeline='public', key, limit = 20) =>
# console.log "Getting posts after key: #{key}…"
@getTimeline key, '\uffff', limit
@getTimeline timeline, key, '\uffff', limit
getPostsBefore: (key, limit = 20) =>
@getTimeline '\x00', key, limit
getPostsBefore: (timeline='public', key, limit = 20) =>
@getTimeline timeline, '\x00', key, limit
#
# Get one specific message
......@@ -107,7 +110,7 @@ class PublicTimelineWeaver
# Returns a promise to return the requested timeline.
# (We need to stream the timelines contents from the database.)
#
getTimeline: (from='\x00', to='\uffff', limit=20) =>
getTimeline: (timeline='public', from='\x00', to='\uffff', limit=20) =>
# console.log "Streamweaver::getTimeline: #{timeline}"
# console.log "getTimeline: from: >#{from.charCodeAt(0)}<, to: >#{to.charCodeAt(0)}<, limit: #{limit}."
......@@ -124,7 +127,7 @@ class PublicTimelineWeaver
# Get the latest posts
options.reverse = true
timelineStream = @publicTimeline.createReadStream options
timelineStream = (@db.sublevel timeline).createReadStream options
timelineStream.on 'error', (err) ->
console.error('timelineStream.on error ' + err.message)
......
......@@ -65,6 +65,8 @@ PulseProcess = Pulse.Process
PulseConfig = Pulse.Config
PulseEventHandler = require './PulseEventHandler'
TeleportationAPI = require './TeleportationAPI'
root = exports ? this
root.pulse = null
root.pulseProcess = null
......@@ -314,10 +316,34 @@ app.use(bodyParser.json())
# Public Timeline
#
# The Everyone timeline
app.get '/', require('./routes/public/public.coffee')(app)
# A specific post
app.get '/person/:accountHandle/post/:messageID', require('./routes/public/post.coffee')(app)
# A person’s feed
app.get '/person/:accountHandle', require('./routes/public/person/index.coffee')(app)
# A person’s about page
app.get '/person/:accountHandle/about', require('./routes/public/person/about.coffee')(app)
# The profile image for a person
app.get '/person/:accountHandle/about/me.jpg', (request, response) =>
accountHandle = request.param 'accountHandle'
mainFolderForPerson = (new TeleportationAPI).folderForHandle(accountHandle)
aboutPersonFolder = path.join mainFolderForPerson, 'public', 'from', 'about'
console.log "About person folder: #{aboutPersonFolder}"
photoPath = path.join aboutPersonFolder, "me.jpg"
fs.readFileAsync(photoPath)
.then (photo) ->
response.writeHead 200, {'content-type':'image/jpg'}
response.end photo, 'binary'
#
# Ajax updates
......
Promise = require 'thrush'
superagent = require 'superagent'
path = require 'path-extra'
fs = require 'fs-extra-as-promised'
TeleportationAPI = require '../../../TeleportationAPI'
module.exports = (app) ->
route = (request, response) ->
# Read the details
accountHandle = request.param 'accountHandle'
console.log "Account handle: #{accountHandle}"
mainFolderForPerson = (new TeleportationAPI).folderForHandle(accountHandle)
aboutPersonFolder = path.join mainFolderForPerson, 'public', 'from', 'about'
console.log "About person folder: #{aboutPersonFolder}"
profileDataPath = path.join(aboutPersonFolder, "me.json")
friendRequestLinkFormatter = (accountHandle) ->
return "indie://friend/#{accountHandle}"
fs.readFileAsync(profileDataPath)
.then (profileData) ->
profile = JSON.parse(profileData)
response.render 'person/about', {profile: profile, __set: {formatters: {friendRequestLinkFormatter: friendRequestLinkFormatter}}}
fs = require 'fs-extra-as-promised'
moment = require 'moment'
path = require 'path-extra'
TeleportationAPI = require '../../../TeleportationAPI'
PublicTimelineWeaver = require '../../../PublicTimelineWeaver'
module.exports = (app) ->
route = (request, response) ->
accountHandle = request.param.accountHandle
#
# Formatters
#
# Custom formatter for message body ids
messageBodyIDFormatter = (messageID) ->
return messageID + '-body'
# Custom formatter for message status ids
messageStatusIDFormatter = (messageID) ->
return messageID + '-status'
# Format the post date and make it a permanent link to the post.
postDateFormatter = (messageID) ->
#
# Parses message IDs in the following forms into separate groups for
# * timeline clock (deprecated)
# * message time (replace underscores with colons to convert to valid timestamp)
# * account handle (optional)
#
# 000000001-2015-08-10T18_49_10.467Z-laura
# 000000001-2015-08-10T18_49_10.467Z
# 2015-08-10T18_49_10.467Z-laura
# 2015-08-10T18_49_10.467Z
#
messageIDParserRegExp = /^(\d{9})?-?(\d{4}-\d{2}-\d{2}T\d{2}_\d{2}_\d{2}\.\d{3}Z)-?(.*)?/
matches = messageID.match messageIDParserRegExp
if matches != null
depracatedOptionalMessageClock = matches[1]
timestamp = matches[2]
optionalAccountHandle = matches[3]
# Desearialise the timestamp.
timestamp = timestamp.replace /_/g, ':'
console.log "Depracated message clock: #{depracatedOptionalMessageClock}" if depracatedOptionalMessageClock
console.log "Timestamp: #{timestamp}"
console.log (if depracatedOptionalMessageClock then "Account handle #{optionalAccountHandle}" else "Account handle: this is your message")
now = new Date()
timeOfPost = new Date timestamp
# to secs -> mins -> hours -> days
timeSincePostInDays = (now - timeOfPost)/1000/60/60/24
humanTime = moment(timeOfPost).fromNow()
return humanTime
else
# This should never happen and probably shows that some sort of corrupted date got through somehow.
return 'No date.'
# Permanent link formatter
permanentLinkFormatter = (messageID) ->
# Get the person handle
personHandleDelimeter = messageID.lastIndexOf('Z-')
personHandle = messageID.substr(personHandleDelimeter+2)
return "/person/#{personHandle}/post/#{messageID}"
# Format the post date
timestampFormatter = (messageID) ->
messageIDParserRegExp = /^(\d{9})?-?(\d{4}-\d{2}-\d{2}T\d{2}_\d{2}_\d{2}\.\d{3}Z)-?(.*)?/
matches = messageID.match messageIDParserRegExp
if matches != null
timestamp = matches[2]
# Desearialise the timestamp.
timestamp = timestamp.replace /_/g, ':'
return timestamp
else
# This should never happen and probably shows that some sort of corrupted ID got through somehow.
return (new Date())
# Format the person’s name
personFormatter = (messageID) ->
personHandleDelimeter = messageID.lastIndexOf('Z-')
profileImagePath = ''
if personHandleDelimeter != -1
# From someone else
personHandle = messageID.substr(personHandleDelimeter+2)
# TODO: Once public profile pages are implemented, link to them.
return " by #{personHandle}."
else
# This is the person themselves.
# TODO: Once the timestamps are in there, just return that.
return ''
addFriendLinkFormatter = (messageID) ->
personHandleDelimeter = messageID.lastIndexOf('Z-')
profileImagePath = ''
if personHandleDelimeter != -1
# From someone else
personHandle = messageID.substr(personHandleDelimeter+2)
addFriendLink = "indie://friend/#{personHandle}"
return addFriendLink
else
# This is the person themselves, no need to display a friend link.
return ''
addFriendTextFormatter = (messageID) ->
personHandleDelimeter = messageID.lastIndexOf('Z-')
profileImagePath = ''
if personHandleDelimeter != -1
return "<img class='add-friend-icon' src='/images/person_add@2x.png' alt='Send friend request'>"
else
# This is the person themselves, no need to display a friend link.
return ''
# Custom formatter for the profile image
profileImagePathFormatter = (messageID) ->
personHandle = messageID.substr(messageID.lastIndexOf('Z-')+2)
# console.log "Person handle for message: #{personHandle}"
profileImagePath = "/public/#{personHandle}/about/me.jpg"
return profileImagePath
#
# Read the person details
#
accountHandle = request.param 'accountHandle'
console.log "Account handle: #{accountHandle}"
mainFolderForPerson = (new TeleportationAPI).folderForHandle(accountHandle)
aboutPersonFolder = path.join mainFolderForPerson, 'public', 'from', 'about'
console.log "About person folder: #{aboutPersonFolder}"
profileDataPath = path.join(aboutPersonFolder, "me.json")
fs.readFileAsync(profileDataPath)
.then (profileData) ->
profile = JSON.parse(profileData)
(new PublicTimelineWeaver).getTimeline("#{accountHandle}-messages").then (messages) ->
# Reverse the message order to match that of the Cocoa client.
messages.reverse()
response.render 'person/index', {profile: profile, messages: messages, __set: { formatters: {messageBodyIDFormatter: messageBodyIDFormatter, messageStatusIDFormatter: messageStatusIDFormatter, profileImagePathFormatter: profileImagePathFormatter, personFormatter:personFormatter, addFriendLinkFormatter: addFriendLinkFormatter, addFriendTextFormatter:addFriendTextFormatter, postDateFormatter:postDateFormatter, timestampFormatter: timestampFormatter, permanentLinkFormatter: permanentLinkFormatter}}}
<!doctype html>
<html lang='en'>
<head>
<title>About Me</title>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width'>
<link rel='stylesheet' href='./css/styles.css'>
</head>
<body>
<img id='profile-image' src='/about/me.jpg'>
<h1 id='name' data-set-text='profile.displayName'></h1>
<nav>
<ul>
<li><a href='./'>Home</li>
<li><a href='./about'>About</a></li>
</ul>
</nav>
<p id='bio' data-set-text='html profile.bio'></p>
<p><a data-set-attribute='href profile.accountHandle friendRequestLinkFormatter'>Send me a friend request.</a></p>
</body>
</html>
\ No newline at end of file
<!doctype html>
<html lang='en'>
<head>
<title>Heartbeat</title>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width'>
<!-- <link rel='stylesheet' href='./css/styles.css'> -->
<link rel='stylesheet' href='/css/public.css'>
<script type='text/javascript' src='/js/superagent.js'></script>
<script type='text/javascript' src='/js/moment.js'></script>
<script src="/js/set.js"></script>
<script src="/js/public.js"></script>
<script data-set-text='meta'></script>
<style type="text/css">
.displayNone
{
display:none;
}
.progress-spinner
{
display:inline;
width:16px;
vertical-align:top;
padding-top: 2px;
padding-right:5px;
}
</style>
</head>
<body>
<img id='profile-image' src='/about/me.jpg'>
<h1 id='name' data-set-text='profile.displayName'></h1>
<nav>
<ul>
<li><a href='./'>Home</li>
<li><a href='./about'>About</a></li>
</ul>
</nav>
<div id='messages' class='messages' data-set-if='messages'>
<!-- Repeater -->
<div class='message' data-set-repeat='message messages' data-set-attribute='id message.key' >
<div class='messageBody' data-set-attribute='id message.key messageBodyIDFormatter'>
<!-- <p class="timestamp" data-set-text='message.key'>Message timestamp</p> -->
<div class="image-and-body">
<img class="profileImage" data-set-attribute='src message.key profileImagePathFormatter'>
<div class="bodyText" data-set-text='html message.value'>Message body HTML</div>
<div class="meta"><a data-set-attribute='href message.key permanentLinkFormatter'><span class='postDate' data-set-attribute='data-timestamp message.key timestampFormatter' data-set-text='message.key postDateFormatter'></span></a> <span data-set-text='message.key personFormatter'></span> <a data-set-attribute='href message.key addFriendLinkFormatter' data-set-text='html message.key addFriendTextFormatter'></a></div>
</div>
</div>
<!-- <div class='messageStatus' data-set-attribute='id message.key messageStatusIDFormatter'></div>-->
</div>
</div>
<div id='loadProgress' class='displayNone'>
<p style='text-align:center;'><img class='progress-spinner' src='/images/progress-spinner@2x.gif'></p>
</div>
</body>
</html>
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment