lists.coffee 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. templates = require('duality/templates')
  2. dutils = require('duality/utils')
  3. settings = require('settings/root')
  4. Showdown = require('showdown')
  5. _ = require('underscore')._
  6. utils = require('lib/utils')
  7. moment = require('lib/moment')
  8. exports.home = (head, req) ->
  9. # no need for double render on first hit
  10. return if req.client and req.initial_hit
  11. start code: 200, headers: {'Content-Type': 'text/html'}
  12. md = new Showdown.converter()
  13. collections = []
  14. blocks = {}
  15. site = {}
  16. while row = getRow()
  17. doc = row.value
  18. if doc
  19. collections.push(doc) if doc.type is 'collection'
  20. blocks[doc.code] = doc if doc.type is 'block'
  21. site = doc if doc.type is 'site'
  22. collections = _.map collections, (doc) ->
  23. if doc.intro?
  24. doc.intro_html = md.makeHtml(
  25. doc.intro.replace(/\{\{?baseURL\}?\}/g, dutils.getBaseURL(req))
  26. )
  27. doc.updated_at_html = utils.prettyDate(doc.updated_at)
  28. doc.updated_at_half = utils.halfDate(doc.updated_at)
  29. doc.fresh = utils.isItFresh(doc.updated_at)
  30. doc.type_tc = utils.capitalize(doc.type)
  31. return doc
  32. return {
  33. on_dev: utils.isDev(req)
  34. area: 'home'
  35. site: site
  36. type: 'home'
  37. title: "#{site.name}"
  38. content: templates.render "home.html", req,
  39. collections: collections
  40. blocks: blocks
  41. og:
  42. site_name: site.name
  43. title: site.name
  44. description: site.seo_description
  45. type: 'website'
  46. url: site.link
  47. image: "#{site.link}/file/#{blocks.site_intro._id}/#{blocks.site_intro.photo}" if blocks.site_intro?.photo
  48. }
  49. exports.collection = (head, req) ->
  50. # no need for double render on first hit
  51. return if req.client and req.initial_hit
  52. start code: 200, headers: {'Content-Type': 'text/html'}
  53. md = new Showdown.converter()
  54. docs = []
  55. collection = null
  56. blocks = {}
  57. sponsor = null
  58. site = {}
  59. while row = getRow()
  60. doc = row.doc
  61. if doc
  62. docs.push(doc) if doc.type in settings.app.content_types
  63. collection ?= doc if doc.type is 'collection'
  64. blocks[doc.code] = doc if doc.type is 'block'
  65. sponsor ?= doc if doc.type is 'sponsor'
  66. site = doc if doc.type is 'site'
  67. if collection
  68. if collection.intro?
  69. collection.intro_html = md.makeHtml(
  70. collection.intro.replace(/\{\{?baseURL\}?\}/g, dutils.getBaseURL(req))
  71. )
  72. collection.fresh = utils.isItFresh(collection.updated_at)
  73. collection.type_tc = utils.capitalize(collection.type)
  74. docs = _.map docs, (doc) ->
  75. if doc.intro?
  76. doc.intro_html = md.makeHtml(
  77. doc.intro.replace(/\{\{?baseURL\}?\}/g, dutils.getBaseURL(req))
  78. )
  79. doc.published_at_html = utils.prettyDate(doc.published_at)
  80. doc.fresh = utils.isItFresh(doc.published_at)
  81. doc.type_tc = utils.capitalize(doc.type)
  82. if doc.type is 'scene'
  83. doc.list_item_template = 'partials/list-item-scene.html'
  84. else
  85. doc.list_item_template = 'partials/list-item-default.html'
  86. return doc
  87. if sponsor
  88. # Check for strat/end dates of sponsorship
  89. sponsor_start = moment.utc(collection.sponsor_start)
  90. sponsor_end = moment.utc(collection.sponsor_end)
  91. now = moment.utc()
  92. if sponsor_start.diff(now) <= 0 and sponsor_end.diff(now) >= 0
  93. # let's continue on
  94. sponsor.text_format = sponsor.format is 'text'
  95. sponsor.image_format = sponsor.format is 'image'
  96. sponsor.video_format = sponsor.format is 'video'
  97. sponsor.embed_format = sponsor.format is 'embed'
  98. sponsor.for_type = collection.type
  99. sponsor.for_type_tc = collection.type_tc
  100. # Let's also pass the site's default ad unit if asked for it
  101. if site and site.default_ad_unit and site.default_ad_enabled and sponsor.include_default_ad_unit
  102. sponsor.content = site.default_ad_unit + sponsor.content
  103. else
  104. # let's remove the sponsor
  105. sponsor = null
  106. if collection
  107. if not sponsor and site and site.default_ad_unit and site.default_ad_enabled
  108. # In this case create a new sponsor object and use
  109. # the site's default ad unit if enabled
  110. sponsor = {}
  111. sponsor.content = site.default_ad_unit
  112. sponsor.embed_format = true
  113. sponsor.for_type = collection.type
  114. sponsor.for_type_tc = collection.type_tc
  115. return {
  116. on_dev: utils.isDev(req)
  117. area: 'collection'
  118. site: site
  119. type: 'collection'
  120. title: collection.name
  121. content: templates.render 'collection.html', req,
  122. collection: collection
  123. docs: docs
  124. sponsor: sponsor
  125. blocks: blocks
  126. og:
  127. site_name: site.name
  128. title: collection.name
  129. description: collection.intro
  130. type: 'website'
  131. url: "#{site.link}/collection/#{collection.slug}"
  132. image: "#{site.link}/file/#{collection._id}/#{collection.photo}" if collection.photo
  133. }
  134. else
  135. return {
  136. code: 404
  137. title: '404 Not Found'
  138. content: templates.render '404.html', req, { host: req.headers.Host }
  139. on_dev: utils.isDev(req)
  140. area: '404'
  141. }
  142. exports.docs = (head, req) ->
  143. # no need for double render on first hit
  144. return if req.client and req.initial_hit
  145. start code: 200, headers: {'Content-Type': 'text/html'}
  146. md = new Showdown.converter()
  147. docs = []
  148. site = {}
  149. while row = getRow()
  150. doc = row.doc
  151. if doc
  152. if doc.type in settings.app.content_types
  153. doc.collection_docs = []
  154. docs.push(doc)
  155. else if doc.type is 'collection'
  156. # Add the collection doc to the last doc pushed
  157. docs[docs.length-1].collection_docs.push(doc)
  158. site = doc if doc.type is 'site'
  159. docs = _.map docs, (doc) ->
  160. if doc.intro?
  161. doc.intro_html = md.makeHtml(
  162. doc.intro.replace(/\{\{?baseURL\}?\}/g, dutils.getBaseURL(req))
  163. )
  164. doc.published_at_html = utils.prettyDate(doc.published_at)
  165. doc.updated_at_html = utils.prettyDate(doc.updated_at)
  166. doc.fresh = utils.isItFresh(doc.published_at)
  167. doc.type_tc = utils.capitalize(doc.type)
  168. if doc.type is 'scene'
  169. doc.list_item_template = 'partials/list-item-scene.html'
  170. else
  171. doc.list_item_template = 'partials/list-item-default.html'
  172. return doc
  173. return {
  174. on_dev: utils.isDev(req)
  175. area: 'docs'
  176. site: site
  177. type: 'docs'
  178. title: 'Docs List'
  179. content: templates.render 'docs.html', req,
  180. docs: docs
  181. og:
  182. site_name: site.name
  183. title: site.name
  184. description: site.seo_description
  185. type: 'website'
  186. url: site.link
  187. }
  188. exports.doc = (head, req) ->
  189. ###
  190. This will render the content doc along with a list of its
  191. associated collections.
  192. ###
  193. # no need for double render on first hit
  194. return if req.client and req.initial_hit
  195. start code: 200, headers: {'Content-Type': 'text/html'}
  196. md = new Showdown.converter()
  197. theDoc = null
  198. collections = []
  199. blocks = []
  200. author = null
  201. sponsor = null
  202. site = {}
  203. while row = getRow()
  204. doc = row.doc
  205. if doc
  206. theDoc ?= doc if doc.type in settings.app.content_types
  207. collections.push(doc) if doc.type is 'collection'
  208. blocks.push(doc) if doc.type is 'block'
  209. sponsor ?= doc if doc.type is 'sponsor'
  210. author ?= doc if doc.type is 'author'
  211. site = doc if doc.type is 'site'
  212. # Let's just go back and use `doc` as the variable instead
  213. doc = theDoc
  214. transformDoc = (doc) ->
  215. doc.intro_html = md.makeHtml(replaceTokens(doc.intro)) if doc.intro?
  216. doc.body_html = md.makeHtml(replaceTokens(doc.body))
  217. doc.published_at_html = utils.prettyDate(doc.published_at)
  218. doc.updated_at_html = utils.prettyDate(doc.updated_at)
  219. doc.fresh = utils.isItFresh(doc.published_at)
  220. doc.type_tc = utils.capitalize(doc.type)
  221. return doc
  222. replaceTokens = (content) ->
  223. # Replace the {baseURL} or {{baseURL}} token
  224. content = content.replace(/\{\{?baseURL\}?\}/g, dutils.getBaseURL(req))
  225. # Replace any references to the extra doc's blocks
  226. # within the doc e.g. "<!-- block: some_code_or_id -->" (optionally without spaces)
  227. for block in blocks
  228. if block.enabled
  229. re = new RegExp('<!--\\s*block:\\s*(' + block._id + '|' + block.code + ')\\s*-->', 'gi')
  230. content = content.replace(re, block.content)
  231. return content
  232. doc = transformDoc(doc) if doc
  233. collections = _.map collections, (doc) ->
  234. if doc.intro?
  235. doc.intro_html = md.makeHtml(
  236. doc.intro.replace(/\{\{?baseURL\}?\}/g, dutils.getBaseURL(req))
  237. )
  238. doc.updated_at_html = utils.prettyDate(doc.updated_at)
  239. doc.fresh = utils.isItFresh(doc.updated_at)
  240. return doc
  241. collection = collections?[0] # primary one
  242. if sponsor
  243. # Check for strat/end dates of sponsorship
  244. sponsor_start = moment.utc(doc.sponsor_start)
  245. sponsor_end = moment.utc(doc.sponsor_end)
  246. now = moment.utc()
  247. if sponsor_start.diff(now) <= 0 and sponsor_end.diff(now) >= 0
  248. # let's continue on
  249. sponsor.text_format = sponsor.format is 'text'
  250. sponsor.image_format = sponsor.format is 'image'
  251. sponsor.video_format = sponsor.format is 'video'
  252. sponsor.embed_format = sponsor.format is 'embed'
  253. sponsor.for_type = doc.type
  254. sponsor.for_type_tc = doc.type_tc
  255. # Let's also pass the site's default ad unit if asked for it
  256. if site and site.default_ad_unit and site.default_ad_enabled and sponsor.include_default_ad_unit
  257. sponsor.content = site.default_ad_unit + sponsor.content
  258. else
  259. # let's remove the sponsor
  260. sponsor = null
  261. # Let's use the collection's sponsor if there was no doc sponsor
  262. # and the sponsor was setup to propogate to entire collection's docs
  263. if not sponsor and collection and collection.sponsor_id and collection.sponsor_propagate
  264. # Check for strat/end dates of sponsorship
  265. sponsor_start = moment.utc(collection.sponsor_start)
  266. sponsor_end = moment.utc(collection.sponsor_end)
  267. now = moment.utc()
  268. if sponsor_start.diff(now) <= 0 and sponsor_end.diff(now) >= 0
  269. sponsor =
  270. load_on_client: true
  271. collection_id: collection._id
  272. sponsor_id: collection.sponsor_id
  273. # Let's also pass the site's default ad unit in case we like to use it
  274. if site and site.default_ad_unit and site.default_ad_enabled
  275. sponsor.default_ad_unit = site.default_ad_unit
  276. if doc
  277. if not sponsor and site and site.default_ad_unit and site.default_ad_enabled
  278. # In this case create a new sponsor object and use
  279. # the site's default ad unit if enabled
  280. sponsor = {}
  281. sponsor.content = site.default_ad_unit
  282. sponsor.embed_format = true
  283. sponsor.for_type = doc.type
  284. sponsor.for_type_tc = doc.type_tc
  285. return {
  286. on_dev: utils.isDev(req)
  287. area: 'doc'
  288. site: site
  289. type: doc.type
  290. title: doc.title
  291. content: templates.render 'doc.html', req,
  292. doc: doc
  293. collections: collections
  294. collection: collection
  295. author: author
  296. sponsor: sponsor
  297. blocks: blocks
  298. og:
  299. site_name: site.name
  300. title: doc.title
  301. description: doc.intro
  302. type: 'article'
  303. url: "#{site.link}/#{doc.type}/#{doc.slug}"
  304. image: "#{site.link}/file/#{doc._id}/#{doc.photo}" if doc.photo
  305. first_name: author?.name.split(' ')[0]
  306. last_name: author?.name.split(' ')[1]
  307. published: doc.published_at
  308. }
  309. else
  310. return {
  311. code: 404
  312. title: '404 Not Found'
  313. content: templates.render '404.html', req, { host: req.headers.Host }
  314. on_dev: utils.isDev(req)
  315. area: '404'
  316. }
  317. exports.rssfeed = (head, req) ->
  318. start code: 200, headers: {'Content-Type': 'application/xml'}
  319. # Output as plain text for troubleshooting
  320. # start code: 200, headers: {'Content-Type': 'text/plain'}
  321. md = new Showdown.converter()
  322. docs = []
  323. site = {}
  324. while row = getRow()
  325. doc = row.doc
  326. if doc
  327. docs.push(doc) if doc.type in settings.app.content_types
  328. site = doc if doc.type is 'site'
  329. docs = _.map docs, (doc) ->
  330. doc.intro_html = ''
  331. if doc.intro?
  332. doc.intro_html = md.makeHtml(
  333. doc.intro.replace(/\{\{?baseURL\}?\}/g, dutils.getBaseURL(req))
  334. )
  335. doc.intro_html = "<p><img src=\"#{site.link}/file/#{doc._id}/#{doc.photo}\" style=\"display: block; max-width: 100%;\"></p>" + doc.intro_html if doc.photo
  336. doc.intro_html = doc.intro_html + doc.video if doc.video
  337. doc.body_html = md.makeHtml(
  338. doc.body.replace(/\{\{?baseURL\}?\}/g, dutils.getBaseURL(req))
  339. )
  340. doc.published_at = moment.utc(doc.published_at).toDate().toGMTString()
  341. doc.full_url = "#{site.link}/#{doc.type}/#{doc.slug}"
  342. doc.full_html = "#{doc.intro_html} #{doc.body_html}"
  343. return doc
  344. return templates.render 'feed.xml', req,
  345. site: site
  346. docs: docs
  347. build_date: moment.utc().toDate().toGMTString()
  348. exports.sitemap = (head, req) ->
  349. start code: 200, headers: {'Content-Type': 'application/xml'}
  350. docs = []
  351. siteLink = ''
  352. while row = getRow()
  353. key = row.key
  354. date = key[1]
  355. type = key[2]
  356. slug = key[3]
  357. log key
  358. if type is 'site'
  359. siteLink = slug if not siteLink
  360. else
  361. docs.push
  362. url: "#{siteLink}/#{type}/#{slug}"
  363. date: date
  364. return templates.render 'sitemap.xml', req,
  365. docs: docs