diff --git a/lib/entry-state.js b/lib/entry-state.js new file mode 100644 index 0000000..1d81a1c --- /dev/null +++ b/lib/entry-state.js @@ -0,0 +1,25 @@ +const { getEntry } = require('./../services/contentful') + +async function getPublishedEntry (entry) { + try { + return await getEntry(entry.sys.id) + } catch (err) { + return null + } +} + +module.exports = async function attachEntryState (entry) { + const publishedEntry = await getPublishedEntry(entry) + entry.draft = false + entry.pendingChanges = false + + if (!publishedEntry) { + entry.draft = true + } + + if (entry && publishedEntry && (entry.sys.updatedAt !== publishedEntry.sys.updatedAt)) { + entry.pendingChanges = true + } + + return entry +} diff --git a/public b/public index 1a87426..4dcf29f 160000 --- a/public +++ b/public @@ -1 +1 @@ -Subproject commit 1a87426e8ceb7ab8af1009ee87e7f4ea35e03439 +Subproject commit 4dcf29f69f5f62fed9d33b021d1bc90a3e9cb738 diff --git a/routes/courses.js b/routes/courses.js index b40d50b..1e35c7e 100644 --- a/routes/courses.js +++ b/routes/courses.js @@ -1,10 +1,17 @@ const {getCourses, getCourse, getCategories, getCoursesByCategory} = require('./../services/contentful') +const attachEntryState = require('./../lib/entry-state') exports.getCourses = async (req, res, next) => { // we get all the entries with the content type `course` let courses = [] let categories = [] courses = await getCourses(res.locals.currentLocale.code, res.locals.currentApi.id) + + // Attach entry state flags when using preview API + if (res.locals.settings.editorialFeatures && res.locals.currentApi.id === 'cpa') { + courses = await Promise.all(courses.map(attachEntryState)) + } + categories = await getCategories(res.locals.currentLocale.code, res.locals.currentApi.id) res.render('courses', { title: `All Courses (${courses.length})`, categories, courses }) } @@ -22,8 +29,13 @@ exports.getCourse = async (req, res, next) => { let visitedLessons = cookie || [] visitedLessons.push(course.sys.id) visitedLessons = [...new Set(visitedLessons)] - res.cookie('visitedLessons', visitedLessons, { maxAge: 900000, httpOnly: true }) + + // Attach entry state flags when using preview API + if (res.locals.settings.editorialFeatures && res.locals.currentApi.id === 'cpa') { + course = await attachEntryState(course) + } + res.render('course', {title: course.fields.title, course, lesson, lessons, lessonIndex, visitedLessons}) } @@ -47,13 +59,21 @@ exports.getLesson = async (req, res, next) => { let course = await getCourse(req.params.cslug, res.locals.currentLocale.code, res.locals.currentApi.id) const lessons = course.fields.lessons const lessonIndex = lessons.findIndex((lesson) => lesson.fields.slug === req.params.lslug) - const lesson = lessons[lessonIndex] + let lesson = lessons[lessonIndex] const nextLesson = lessons[lessonIndex + 1] || null + + // save visited lessons const cookie = req.cookies.visitedLessons let visitedLessons = cookie || [] visitedLessons.push(lesson.sys.id) visitedLessons = [...new Set(visitedLessons)] res.cookie('visitedLessons', visitedLessons, { maxAge: 900000, httpOnly: true }) + + // Attach entry state flags when using preview API + if (res.locals.settings.editorialFeatures && res.locals.currentApi.id === 'cpa') { + lesson = await attachEntryState(lesson) + } + res.render('course', { title: `${course.fields.title} | ${lesson.fields.title}`, course, diff --git a/routes/landingPage.js b/routes/landingPage.js index d30319d..9940acb 100644 --- a/routes/landingPage.js +++ b/routes/landingPage.js @@ -1,14 +1,21 @@ const { getLandingPage } = require('../services/contentful') +const attachEntryState = require('./../lib/entry-state') const url = require('url') exports.getLandingPage = async (req, res, next) => { let pathname = url.parse(req.url).pathname.split('/').filter(Boolean)[0] pathname = pathname || 'home' - const landingPage = await getLandingPage( + let landingPage = await getLandingPage( pathname, res.locals.currentLocale.code, res.locals.currentApi.id ) + + // Attach entry state flags when using preview APIgs + if (res.locals.settings.editorialFeatures && res.locals.currentApi.id === 'cpa') { + landingPage = await attachEntryState(landingPage) + } + res.render('landingPage', { title: pathname, landingPage }) } diff --git a/services/contentful.js b/services/contentful.js index b794c40..23573f3 100644 --- a/services/contentful.js +++ b/services/contentful.js @@ -26,11 +26,18 @@ exports.initClient = (options) => { }) } +// Get the Space the app is connected to. Used for the settings form and to get all available locales. exports.getSpace = assert((api = `cda`) => { const client = api === 'cda' ? cdaClient : cpaClient return client.getSpace() }, 'Space') +// Get a single entry. Used to detect the `Draft` or `Pending Changes` state. +exports.getEntry = assert((entryId, api = `cda`) => { + const client = api === 'cda' ? cdaClient : cpaClient + return client.getEntry(entryId) +}, 'Entry') + // to get all the courses we request all the entries // with the content_type `course` from Contentful exports.getCourses = assert((locale = 'en-US', api = `cda`) => { diff --git a/views/mixins/_courseCard.pug b/views/mixins/_courseCard.pug index 429e4d2..6f31919 100644 --- a/views/mixins/_courseCard.pug +++ b/views/mixins/_courseCard.pug @@ -1,3 +1,5 @@ +include _entryState + mixin courseCard(course = {fields: {title: '', description: '', categories: [], slug: ''}}) .course-card .course-card__categories @@ -7,6 +9,8 @@ mixin courseCard(course = {fields: {title: '', description: '', categories: [], a.course-card__category-link(href=`/courses/categories/${category.fields.slug}${queryString}`) #{category.fields.title} h2.course-card__title a(href=`/courses/${course.fields.slug}${queryString}`)= course.fields.title + if currentApi.id === 'cpa' && (entry.draft || entry.pendingChanges) + +entryState(course) p.course-card__description= course.fields.shortDescription .course-card__link-wrapper a.course-card__link(href=`/courses/${course.fields.slug}${queryString}`) view course diff --git a/views/mixins/_editorialFeatures.pug b/views/mixins/_editorialFeatures.pug index 2129206..62cba29 100644 --- a/views/mixins/_editorialFeatures.pug +++ b/views/mixins/_editorialFeatures.pug @@ -1,6 +1,11 @@ +include _entryState + mixin editorialFeatures(entry) if settings.editorialFeatures .editorial-features + if currentApi.id === 'cpa' && (entry.draft || entry.pendingChanges) + .editorial-features__item + +entryState(entry) .editorial-features__item a.editorial-features__text( href=`https://app.contentful.com/spaces/${settings.space}/entries/${entry.sys.id}` diff --git a/views/mixins/_entryState.pug b/views/mixins/_entryState.pug new file mode 100644 index 0000000..54b67a5 --- /dev/null +++ b/views/mixins/_entryState.pug @@ -0,0 +1,5 @@ +mixin entryState(entry) + if entry.draft + .pill.pill--draft draft + if entry.pendingChanges + .pill.pill--pending-changes pending changes