diff --git a/app/controllers/admin/newsroom.js b/app/controllers/admin/newsroom.js index dea2a9e..d8cb8ee 100644 --- a/app/controllers/admin/newsroom.js +++ b/app/controllers/admin/newsroom.js @@ -115,7 +115,7 @@ class NewsroomAdminController extends SiteController { const { feed: feedService } = this.dtp.services; try { res.locals.feed = await feedService.create(req.body); - res.redirect(`/admin/newsroom/${res.locals.feed._id}`); + res.redirect('/admin/newsroom'); } catch (error) { this.log.error('failed to create feed', { error }); return next(error); diff --git a/app/controllers/newsroom.js b/app/controllers/newsroom.js index fb47135..265e018 100644 --- a/app/controllers/newsroom.js +++ b/app/controllers/newsroom.js @@ -69,7 +69,7 @@ class NewsroomController extends SiteController { const { feed: feedService } = this.dtp.services; try { res.locals.pagination = this.getPaginationParameters(req, 10); - res.locals.newsroom = await feedService.getFeeds(res.locals.pagination); + res.locals.newsroom = await feedService.getFeeds(res.locals.pagination, { withEntries: true }); res.render('newsroom/index'); } catch (error) { this.log.error('failed to present newsroom home', { error }); diff --git a/app/services/feed.js b/app/services/feed.js index f1b3f88..4f9a2e0 100644 --- a/app/services/feed.js +++ b/app/services/feed.js @@ -8,7 +8,7 @@ const mongoose = require('mongoose'); const Feed = mongoose.model('Feed'); const FeedEntry = mongoose.model('FeedEntry'); -const { SiteService, SiteError } = require('../../lib/site-lib'); +const { SiteService, SiteError, SiteAsync } = require('../../lib/site-lib'); const { read: feedReader } = require('feed-reader'); class FeedService extends SiteService { @@ -23,6 +23,10 @@ class FeedService extends SiteService { ]; } + async start ( ) { + this.jobQueue = this.getJobQueue('newsroom', this.dtp.config.jobQueues.newsroom); + } + async create (feedDefinition) { feedDefinition.url = feedDefinition.url.trim(); const feedContent = await this.load(feedDefinition.url); @@ -63,7 +67,8 @@ class FeedService extends SiteService { await Feed.updateOne({ _id: feed._id }, updateOp); } - async getFeeds (pagination) { + async getFeeds (pagination, options) { + options = Object.assign({ withEntries: false, entryCount: 3 }, options); pagination = Object.assign({ skip: 0, cpp: 10 }, pagination); const feeds = await Feed .find() @@ -71,7 +76,21 @@ class FeedService extends SiteService { .skip(pagination.skip) .limit(pagination.cpp) .lean(); + + if (options.withEntries) { + await SiteAsync.each(feeds, async (feed) => { + try { + feed.recent = await this.getFeedEntries(feed, { skip: 0, cpp: options.entryCount }); + this.log.debug('feed entries', { count: feed.recent.entries.length }); + } catch (error) { + this.log.error('failed to populate recent entries for feed', { feedId: feed._id, error }); + // fall through + } + }, 2); + } + const totalFeedCount = await Feed.countDocuments(); + return { feeds, totalFeedCount }; } diff --git a/app/views/admin/newsroom/editor.pug b/app/views/admin/newsroom/editor.pug index 06700b3..55c5eb2 100644 --- a/app/views/admin/newsroom/editor.pug +++ b/app/views/admin/newsroom/editor.pug @@ -33,7 +33,14 @@ block content textarea(id="description", name="description", rows="4", placeholder="Enter feed description").uk-textarea.uk-resize-vertical= feed ? feed.description : undefined .uk-card-footer - button(type="submit").uk-button.uk-button-primary.uk-border-rounded= feed ? 'Update Feed' : 'Add Feed' - - if feed - pre= JSON.stringify(feed, null, 2) \ No newline at end of file + div(uk-grid).uk-flex-right.uk-flex-middle + if feed + .uk-width-auto + button( + type="button", + data-feed-id= feed._id, + data-feed-title= feed.title, + onclick="return dtp.adminApp.removeNewsroomFeed(event);", + ).uk-button.uk-button-danger.uk-border-rounded Remove Feed + .uk-width-auto + button(type="submit").uk-button.uk-button-primary.uk-border-rounded= feed ? 'Update Feed' : 'Add Feed' \ No newline at end of file diff --git a/app/views/newsroom/index.pug b/app/views/newsroom/index.pug index 5119ff8..fe54702 100644 --- a/app/views/newsroom/index.pug +++ b/app/views/newsroom/index.pug @@ -9,11 +9,29 @@ block content div(uk-grid).uk-grid-match each feed in newsroom.feeds .uk-width-1-3 - .uk-tile.uk-tile-secondary.uk-padding-small.uk-border-rounded - .uk-text-bold - a(href=`/newsroom/${feed._id}`)= feed.title - .uk-text-small.uk-text-muted - div last update #{moment(feed.published).fromNow()} - div= feed.description + .uk-card.uk-card-secondary.uk-card-small.uk-border-rounded + .uk-card-header(style="border-bottom: solid 1px #808080;") + div(uk-grid).uk-grid-small.uk-flex-middle + .uk-width-expand + h2.uk-card-title.uk-margin-remove + a(href=`/newsroom/${feed._id}`, uk-tooltip=`See all for ${feed.title}`)= feed.title + .uk-width-auto + a(href=`/newsroom/${feed._id}`, uk-tooltip=`See all for ${feed.title}`).uk-text-small ALL + + .uk-text-small.uk-text-muted + div last update #{moment(feed.published).fromNow()} + //- div= feed.description + + .uk-card-body + if Array.isArray(feed.recent.entries) && (feed.recent.entries.length > 0) + ul.uk-list.uk-list-divider + each entry in feed.recent.entries + li + .uk-text-truncate + a(href= entry.link, uk-tooltip= entry.title, target="_blank").uk-link-reset= entry.title + .uk-article-meta= moment(entry.published).fromNow() + + else + div No recent posts else div There are no configured news feeds. \ No newline at end of file diff --git a/client/js/site-admin-app.js b/client/js/site-admin-app.js index 46c1910..a18aba2 100644 --- a/client/js/site-admin-app.js +++ b/client/js/site-admin-app.js @@ -367,6 +367,33 @@ export default class DtpSiteAdminHostStatsApp extends DtpApp { return false; } + + async removeNewsroomFeed (event) { + event.preventDefault(); + event.stopPropagation(); + + const target = event.currentTarget || event.target; + const feedId = target.getAttribute('data-feed-id'); + const feedTitle = target.getAttribute('data-feed-title'); + + try { + await UIkit.modal.confirm(`Are you sure you want to remove feed "${feedTitle}"?`); + } catch (error) { + // canceled + return false; + } + + try { + const response = await fetch(`/admin/newsroom/${feedId}`, { method: 'DELETE' }); + await this.processResponse(response); + } catch (error) { + UIkit.modal.alert(`Failed to remove feed: ${error.message}`); + } + + return false; + } + + } dtp.DtpSiteAdminHostStatsApp = DtpSiteAdminHostStatsApp; \ No newline at end of file