ActivityList.coffee 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. class ActivityList extends Class
  2. constructor: ->
  3. @activities = null
  4. @directories = []
  5. @need_update = true
  6. @limit = 10
  7. @found = 0
  8. @loading = true
  9. @update_timer = null
  10. queryActivities: (cb) ->
  11. if @directories == "all"
  12. where = "WHERE date_added > #{Time.timestamp()-60*60*24*2} AND date_added < #{Time.timestamp()+120} "
  13. else
  14. where = "WHERE json.directory IN #{Text.sqlIn(@directories)} AND date_added < #{Time.timestamp()+120} "
  15. query = """
  16. SELECT
  17. 'comment' AS type, json.*,
  18. json.site || "/" || post_uri AS subject, body, date_added,
  19. NULL AS subject_auth_address, NULL AS subject_hub, NULL AS subject_user_name
  20. FROM
  21. json
  22. LEFT JOIN comment USING (json_id)
  23. #{where}
  24. UNION ALL
  25. SELECT
  26. 'post_like' AS type, json.*,
  27. json.site || "/" || post_uri AS subject, '' AS body, date_added,
  28. NULL AS subject_auth_address, NULL AS subject_hub, NULL AS subject_user_name
  29. FROM
  30. json
  31. LEFT JOIN post_like USING (json_id)
  32. #{where}
  33. """
  34. if @directories != "all" # Dont show follows in all users activity feed
  35. query += """
  36. UNION ALL
  37. SELECT
  38. 'follow' AS type, json.*,
  39. follow.hub || "/" || follow.auth_address AS subject, '' AS body, date_added,
  40. follow.auth_address AS subject_auth_address, follow.hub AS subject_hub, follow.user_name AS subject_user_name
  41. FROM
  42. json
  43. LEFT JOIN follow USING (json_id)
  44. #{where}
  45. """
  46. query += """
  47. ORDER BY date_added DESC
  48. LIMIT #{@limit+1}
  49. """
  50. @logStart("Update")
  51. Page.cmd "dbQuery", [query, {directories: @directories}], (rows) =>
  52. # Resolve subject's name
  53. directories = []
  54. rows = (row for row in rows when row.subject) # Remove deleted users activities
  55. for row in rows
  56. row.auth_address = row.directory.replace("data/users/", "")
  57. subject_address = row.subject.replace(/_.*/, "").replace(/.*\//, "") # Only keep user's address
  58. row.post_id = row.subject.replace(/.*_/, "").replace(/.*\//, "")
  59. row.subject_address = subject_address
  60. directory = "data/users/#{subject_address}"
  61. if directory not in directories
  62. directories.push directory
  63. Page.cmd "dbQuery", ["SELECT * FROM json WHERE ?", {directory: directories}], (subject_rows) =>
  64. # Add subject node to rows
  65. subject_db = {}
  66. for subject_row in subject_rows
  67. subject_row.auth_address = subject_row.directory.replace("data/users/", "")
  68. subject_db[subject_row.auth_address] = subject_row
  69. for row in rows
  70. row.subject = subject_db[row.subject_address]
  71. row.subject ?= {}
  72. row.subject.auth_address ?= row.subject_auth_address
  73. row.subject.hub ?= row.subject_hub
  74. row.subject.user_name ?= row.subject_user_name
  75. # Merge same activities from same user to one line
  76. last_row = null
  77. row_group = []
  78. row_groups = []
  79. for row in rows
  80. if not last_row or (row.auth_address == last_row?.auth_address and row.type == last_row?.type and row.type in ["post_like", "follow"])
  81. row_group.push row
  82. else
  83. row_groups.push row_group
  84. row_group = [row]
  85. last_row = row
  86. if row_group.length
  87. row_groups.push row_group
  88. @found = rows.length
  89. @logEnd("Update")
  90. cb(row_groups)
  91. handleMoreClick: =>
  92. @limit += 20
  93. @update(0)
  94. return false
  95. renderActivity: (activity_group) ->
  96. back = []
  97. now = Time.timestamp()
  98. activity = activity_group[0]
  99. if not activity.subject.user_name
  100. return back
  101. activity_user_link = "?Profile/#{activity.hub}/#{activity.auth_address}/#{activity.cert_user_id}"
  102. subject_user_link = "?Profile/#{activity.subject.hub}/#{activity.subject.auth_address}/#{activity.subject.cert_user_id or ''}"
  103. subject_post_link = "?Post/#{activity.subject.hub}/#{activity.subject.auth_address}/#{activity.post_id}"
  104. if activity.type == "post_like"
  105. body = [
  106. h("a.link", {href: activity_user_link, onclick: @Page.handleLinkClick}, activity.user_name), " liked ",
  107. h("a.link", {href: subject_user_link, onclick: @Page.handleLinkClick}, activity.subject.user_name), "'s ",
  108. h("a.link", {href: subject_post_link, onclick: @Page.handleLinkClick}, _("post", "like post"))
  109. ]
  110. # Add more target
  111. if activity_group.length > 1
  112. for activity_more in activity_group[1..10]
  113. subject_user_link = "?Profile/#{activity_more.subject.hub}/#{activity_more.subject.auth_address}/#{activity_more.subject.cert_user_id or ''}"
  114. subject_post_link = "?Post/#{activity_more.subject.hub}/#{activity_more.subject.auth_address}/#{activity_more.post_id}"
  115. body.push ", "
  116. body.push h("a.link", {href: subject_user_link, onclick: @Page.handleLinkClick}, activity_more.subject.user_name)
  117. body.push "'s "
  118. body.push h("a.link", {href: subject_post_link, onclick: @Page.handleLinkClick}, _("post", "like post"))
  119. else if activity.type == "comment"
  120. body = [
  121. h("a.link", {href: activity_user_link, onclick: @Page.handleLinkClick}, activity.user_name), " commented on ",
  122. h("a.link", {href: subject_user_link, onclick: @Page.handleLinkClick}, activity.subject.user_name), "'s ",
  123. h("a.link", {href: subject_post_link, onclick: @Page.handleLinkClick}, _("post", "comment post")), ": #{activity.body[0..100]}"
  124. ]
  125. else if activity.type == "follow"
  126. body = [
  127. h("a.link", {href: activity_user_link, onclick: @Page.handleLinkClick}, activity.user_name), " started following ",
  128. h("a.link", {href: subject_user_link, onclick: @Page.handleLinkClick}, activity.subject.user_name)
  129. ]
  130. # Add more target
  131. if activity_group.length > 1
  132. for activity_more in activity_group[1..10]
  133. subject_user_link = "?Profile/#{activity_more.subject.hub}/#{activity_more.subject.auth_address}/#{activity_more.subject.cert_user_id or ''}"
  134. body.push ", "
  135. body.push h("a.link", {href: subject_user_link, onclick: @Page.handleLinkClick}, activity_more.subject.user_name)
  136. else
  137. body = activity.body
  138. # opacity = Math.max(0.5, 1 - (now - activity.date_added) / 10000)
  139. if activity.body
  140. title = Time.since(activity.date_added) + " - " + if activity.body.length > 500 then activity.body[0..500] + "..." else activity.body
  141. else
  142. title = Time.since(activity.date_added)
  143. back.push h("div.activity", {key: "#{activity.cert_user_id}_#{activity.date_added}_#{activity_group.length}", title: title, classes: {latest: now - activity.date_added < 600}, enterAnimation: Animation.slideDown, exitAnimation: Animation.slideUp}, [
  144. h("div.circle"),
  145. h("div.body", body)
  146. ])
  147. return back
  148. render: =>
  149. if @need_update
  150. @need_update = false
  151. @queryActivities (res) =>
  152. @activities = res
  153. Page.projector.scheduleRender()
  154. if @activities == null # Not loaded yet
  155. return null
  156. h("div.activity-list", [
  157. if @activities.length > 0
  158. h("h2", {enterAnimation: Animation.slideDown, exitAnimation: Animation.slideUp}, "Activity feed")
  159. h("div.items", [
  160. h("div.bg-line"),
  161. @activities[0..@limit-1].map(@renderActivity)
  162. ]),
  163. if @found > @limit
  164. h("a.more.small", {href: "#More", onclick: @handleMoreClick, enterAnimation: Animation.slideDown, exitAnimation: Animation.slideUp}, "Show more...")
  165. # if @loading
  166. # h("span.more.small", {enterAnimation: Animation.slideDown, exitAnimation: Animation.slideUp}, "Loading...", )
  167. ])
  168. update: (delay=600) =>
  169. clearInterval @update_timer
  170. if not @need_update
  171. @update_timer = setTimeout ( =>
  172. @need_update = true
  173. Page.projector.scheduleRender()
  174. ), delay
  175. window.ActivityList = ActivityList