Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mimir 898 show all upcoming releases #1264

Merged
merged 13 commits into from
Sep 23, 2021
Merged
2 changes: 1 addition & 1 deletion docs/Caching.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ if (isNotInEditMode) {
- [ ] Move menuCache to seperate file
### Parts to cache
- [x] KPI calculator
- [ ] Upcoming releases part ~300ms
- [x] Upcoming releases part ~300ms
- [x] OmStatistikken part ~70ms
- [ ] RelatedArticles part ~25-100ms
- [ ] Default page ~10-60ms
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/lib/ssb/cache/partCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ export function clearPartCache(content: Content, branch: string): void {
partCache.remove(`${content._id}-publicationArchive`)
cacheLog(`try to clear ${content._id}-attachmentTablesFigures from part cache (${branch})`)
partCache.remove(`${content._id}-attachmentTablesFigures`)
cacheLog(`try to clear ${content._id}-upcomingReleases from part cache (${branch})`)
partCache.remove(`${content._id}-upcomingReleases`)
}
}

Expand Down
1 change: 1 addition & 0 deletions src/main/resources/lib/ssb/cron/cron.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ export function setupCronJobs(): void {
clearPartFromPartCache('kpiCalculator')
clearPartFromPartCache('husleieCalculator')
clearPartFromPartCache('attachmentTablesFigures')
clearPartFromPartCache('upcomingReleases')
},
context: cronContext
})
Expand Down
184 changes: 154 additions & 30 deletions src/main/resources/lib/ssb/utils/variantUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,8 @@ const {
moment
} = __non_webpack_require__('/lib/vendor/moment')

export function calculatePeriod(variant: VariantInListing, language: string, nextReleasePassed: boolean = false): string {
let previousFrom: string = variant.previousFrom
let previousTo: string = variant.previousTo
if (nextReleasePassed) {
const upcomingRelease: ReleasesInListing | undefined = variant.upcomingReleases ? forceArray(variant.upcomingReleases).find((r) => {
return r && r.id === variant.nextReleaseId
}) : undefined

if (upcomingRelease) {
previousFrom = upcomingRelease.periodFrom
previousTo = upcomingRelease.periodTo
}
}

switch (variant.frekvens) {
function calculatePeriod(frequency: string, previousFrom: string, previousTo: string, language: string): string {
switch (frequency) {
case 'År':
return calculateYear(previousFrom, previousTo, language)
case 'Halvår':
Expand All @@ -64,6 +51,30 @@ export function calculatePeriod(variant: VariantInListing, language: string, nex
}
}

function calculatePeriodVariant(variant: VariantInListing, language: string, nextReleasePassed: boolean = false): string {
let previousFrom: string = variant.previousFrom
let previousTo: string = variant.previousTo
if (nextReleasePassed) {
const upcomingRelease: ReleasesInListing | undefined = variant.upcomingReleases ? forceArray(variant.upcomingReleases).find((r) => {
return r && r.id === variant.nextReleaseId
}) : undefined

if (upcomingRelease) {
previousFrom = upcomingRelease.periodFrom
previousTo = upcomingRelease.periodTo
}
}

return calculatePeriod(variant.frekvens, previousFrom, previousTo, language)
}

function calculatePeriodRelease(release: Release, language: string): string {
const periodFrom: string = release.periodFrom
const periodTo: string = release.periodTo

return calculatePeriod(release.frequency, periodFrom, periodTo, language)
}

function calculateEveryXYear(previousFrom: string, previousTo: string, language: string): string {
const dateFrom: Date = new Date(previousFrom)
const dateTo: Date = new Date(previousTo)
Expand Down Expand Up @@ -267,28 +278,70 @@ export function getReleasesForDay(
}, [])
}

export function filterOnComingReleases(stats: Array<StatisticInListing>, count: number, startDay?: string): Array<StatisticInListing> {
const releases: Array<StatisticInListing> = []
export function filterOnComingReleases(releases: Array<Release>, count: number, startDay?: string): Array<Release> {
const releaseArray: Array<Release> = []
const day: Date = startDay ? new Date(startDay) : new Date()
for (let i: number = 0; i < count && i < 20; i++) {
for (let i: number = 0; i < count + 1; i++) {
day.setDate(day.getDate() + 1)
const releasesOnThisDay: Array<StatisticInListing> = getReleasesForDay(stats, day, 'nextRelease')
if (releasesOnThisDay.length === 0) count++ // if no hits found on this day. add one day
releases.push(...releasesOnThisDay)
const releasesOnThisDay: Array<Release> = releases.filter((release: Release) => {
return checkReleaseDateToday(release, day)
})
releaseArray.push(...releasesOnThisDay)
}
return releases
return releaseArray
}

export function checkVariantReleaseDate(variant: VariantInListing, day: Date, property: keyof VariantInListing): boolean {
const dayFromVariant: string = variant[property] as string
if (property === 'previousRelease') {
return sameDay(new Date(dayFromVariant), day) || nextReleasedPassed(variant)
if (property === 'previousRelease' && nextReleasedPassed(variant)) {
return sameDay(new Date(dayFromVariant), day) || sameDay(new Date(variant.nextRelease), day)
} else {
return sameDay(new Date(dayFromVariant), day)
}
}

export function checkReleaseDateToday(release: Release, day: Date): boolean {
const releaseDate: string = release.publishTime
return sameDay(new Date(releaseDate), day)
}

export function prepareRelease(
release: Release,
language: string): PreparedStatistics | null {
if (release) {
const preparedVariant: PreparedVariant = formatRelease(release, language)

const statisticsPagesXP: Content<Statistics, object, SEO> | undefined = query({
count: 1,
query: `data.statistic LIKE "${release.statisticId}" AND language IN (${language === 'nb' ? '"nb", "nn"' : '"en"'})`,
contentTypes: [`${app.name}:statistics`]
}).hits[0] as unknown as Content<Statistics, object, SEO>
const statisticsPageUrl: string | undefined = statisticsPagesXP ? pageUrl({
path: statisticsPagesXP._path
}) : undefined
const aboutTheStatisticsContent: Content<OmStatistikken> | null = statisticsPagesXP && statisticsPagesXP.data.aboutTheStatistics ? get({
key: statisticsPagesXP.data.aboutTheStatistics
}) : null
const seoDescription: string | undefined = statisticsPagesXP ? statisticsPagesXP.x['com-enonic-app-metafields']['meta-data'].seoDescription : ''

return {
id: release.statisticId,
name: language === 'en' ? release.statisticNameEn : release.statisticName,
shortName: release.shortName,
type: localize({
key: 'statistic',
locale: language
}),
mainSubject: getMainSubject(release.shortName, language),
variant: preparedVariant,
statisticsPageUrl,
aboutTheStatisticsDescription: aboutTheStatisticsContent ? aboutTheStatisticsContent.data.ingress : seoDescription
}
}
return null
}

export function prepareStatisticRelease(
release: StatisticInListing,
language: string,
property: keyof VariantInListing = 'previousRelease'): PreparedStatistics | null {
Expand Down Expand Up @@ -332,9 +385,9 @@ function concatReleaseTimes(variants: Array<VariantInListing>, language: string,
let timePeriodes: Array<string>

if (property === 'previousRelease') {
timePeriodes = variants.map((variant: VariantInListing) => calculatePeriod(variant, language, nextReleasedPassed(variant)))
timePeriodes = variants.map((variant: VariantInListing) => calculatePeriodVariant(variant, language, nextReleasedPassed(variant)))
} else {
timePeriodes = variants.map((variant: VariantInListing) => calculatePeriod(variant, language))
timePeriodes = variants.map((variant: VariantInListing) => calculatePeriodVariant(variant, language))
}

const formatedTimePeriodes: string = timePeriodes.join(` ${localize({
Expand Down Expand Up @@ -371,20 +424,79 @@ function formatVariant(variant: VariantInListing, language: string, property: ke
monthNumber: date.getMonth(),
year: date.getFullYear(),
frequency: variant.frekvens,
period: calculatePeriod(variant, language, nextReleaseDatePassed)
period: calculatePeriodVariant(variant, language, nextReleaseDatePassed)
}
}

function formatRelease(release: Release, language: string): PreparedVariant {
const date: Date = new Date(release.publishTime)
return {
id: release.variantId,
day: date.getDate(),
monthNumber: date.getMonth(),
year: date.getFullYear(),
frequency: release.frequency,
period: calculatePeriodRelease(release, language)
}
}

export function getAllReleases(statisticList: Array<StatisticInListing>): Array<Release> {
const releases: Array<Release> = []
statisticList.forEach((statistic: StatisticInListing) => {
const variants: Array<VariantInListing> = statistic.variants ? forceArray(statistic.variants) : []
variants.forEach((variant: VariantInListing) => {
releases.push({
publishTime: variant.previousRelease,
periodFrom: variant.previousFrom,
periodTo: variant.previousTo,
frequency: variant.frekvens,
variantId: variant.id,
statisticId: statistic.id,
shortName: statistic.shortName,
statisticName: statistic.name,
statisticNameEn: statistic.nameEN
})
const upcomingRelease: Array<ReleasesInListing> = variant.upcomingReleases ? forceArray(variant.upcomingReleases) : []
upcomingRelease.forEach((upcomingRelease: ReleasesInListing) => {
releases.push({
publishTime: upcomingRelease.publishTime,
periodFrom: upcomingRelease.periodFrom,
periodTo: upcomingRelease.periodTo,
frequency: variant.frekvens,
variantId: variant.id,
statisticId: statistic.id,
shortName: statistic.shortName,
statisticName: statistic.name,
statisticNameEn: statistic.nameEN
})
})
})
})
const publicationsSorted: Array<Release> = releases.sort((a, b) => {
return new Date(a.publishTime || '01.01.3000').getTime() - new Date(b.publishTime || '01.01.3000').getTime()
})

return publicationsSorted
}

export function getUpcomingReleases(allReleases: Array<Release>): Array<Release> {
const serverOffsetInMs: number = app.config && app.config['serverOffsetInMs'] ? parseInt(app.config['serverOffsetInMs']) : 0
const serverTime: Date = new Date(new Date().getTime() + serverOffsetInMs)
return allReleases.filter((release) => moment(release.publishTime).isAfter(serverTime, 'minute'))
}
export interface VariantUtilsLib {
calculatePeriod: (variant: VariantInListing, language: string) => string;
addMonthNames: (groupedByYearMonthAndDay: GroupedBy<GroupedBy<GroupedBy<PreparedStatistics>>>, language: string) => Array<YearReleases>;
groupStatisticsByYear: (statistics: Array<PreparedStatistics>) => GroupedBy<PreparedStatistics>;
groupStatisticsByMonth: (statistics: Array<PreparedStatistics>) => GroupedBy<PreparedStatistics>;
groupStatisticsByDay: (statistics: Array<PreparedStatistics>) => GroupedBy<PreparedStatistics>;
groupStatisticsByYearMonthAndDay: (releasesPrepped: Array<PreparedStatistics>) => GroupedBy<GroupedBy<GroupedBy<PreparedStatistics>>>;
getReleasesForDay: (statisticList: Array<StatisticInListing>, day: Date, property?: keyof VariantInListing) => Array<StatisticInListing>;
prepareRelease: (release: StatisticInListing, locale: string, property?: keyof VariantInListing, statisticsPageUrl?: string) => PreparedStatistics;
filterOnComingReleases: (stats: Array<StatisticInListing>, daysInTheFuture: number, startDay?: string) => Array<StatisticInListing>;
prepareStatisticRelease: (release: StatisticInListing, locale: string, property?: keyof VariantInListing, statisticsPageUrl?: string) => PreparedStatistics;
prepareRelease: (release: Release, locale: string, statisticsPageUrl?: string) => PreparedStatistics;
filterOnComingReleases: (stats: Array<Release>, daysInTheFuture: number, startDay?: string) => Array<Release>;
getAllReleases: (statisticList: Array<StatisticInListing>) => Array<Release>;
getUpcomingReleases: (allReleases: Array<Release>) => Array<Release>;

}

export interface PreparedStatistics {
Expand All @@ -408,6 +520,18 @@ export interface PreparedVariant {
period: string;
}

export interface Release {
publishTime: string;
periodFrom: string;
periodTo: string;
frequency: string;
variantId: string;
statisticId: number;
shortName: string;
statisticName: string;
statisticNameEn: string;
}

export interface DayReleases {
day: string;
releases: Array<PreparedStatistics>;
Expand Down
14 changes: 8 additions & 6 deletions src/main/resources/services/upcomingReleases/upcomingReleases.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { Request, Response } from 'enonic-types/controller'
import { StatisticInListing } from '../../lib/ssb/dashboard/statreg/types'
import { GroupedBy, PreparedStatistics, YearReleases } from '../../lib/ssb/utils/variantUtils'
import { GroupedBy, PreparedStatistics, YearReleases, Release } from '../../lib/ssb/utils/variantUtils'

const {
addMonthNames,
groupStatisticsByYearMonthAndDay,
prepareRelease,
filterOnComingReleases
filterOnComingReleases,
getAllReleases,
getUpcomingReleases
} = __non_webpack_require__( '/lib/ssb/utils/variantUtils')
const {
getAllStatisticsFromRepo
Expand All @@ -15,16 +17,16 @@ const {
exports.get = (req: Request): Response => {
// Get statistics
const releases: Array<StatisticInListing> = getAllStatisticsFromRepo()
const allReleases: Array<Release> = getAllReleases(releases)
const upComingReleases: Array<Release> = getUpcomingReleases(allReleases)
const count: number = req.params.count ? parseInt(req.params.count) : 2

const language: string = req.params.language ? req.params.language : 'nb'
// All statistics published today, and fill up with previous releases.
const releasesFiltered: Array<StatisticInListing> = filterOnComingReleases(releases, count, req.params.start)
const releasesFiltered: Array<Release> = filterOnComingReleases(upComingReleases, count, req.params.start)

// Choose the right variant and prepare the date in a way it works with the groupBy function
const releasesPrepped: Array<PreparedStatistics> = releasesFiltered.map(
(release: StatisticInListing) => prepareRelease(release, language, 'nextRelease')
)
const releasesPrepped: Array<PreparedStatistics> = releasesFiltered.map((release: Release) => prepareRelease(release, language))

// group by year, then month, then day
const groupedByYearMonthAndDay: GroupedBy<GroupedBy<GroupedBy<PreparedStatistics>>> = groupStatisticsByYearMonthAndDay(releasesPrepped)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { React4xp, React4xpResponse } from '../../../lib/types/react4xp'
import { Content } from 'enonic-types/content'
import { PublicationArchivePartConfig } from './publicationArchive-part-config'
import { StatisticInListing } from '../../../lib/ssb/dashboard/statreg/types'
import { PreparedStatistics, prepareRelease } from '../../../lib/ssb/utils/variantUtils'
import { PreparedStatistics } from '../../../lib/ssb/utils/variantUtils'
import { getAllStatisticsFromRepo } from '../../../lib/ssb/statreg/statistics'
import { filterOnPreviousReleases } from '../releasedStatistics/releasedStatistics'
import { PublicationItem } from '../../../services/publicationArchive/publicationArchive'
Expand All @@ -20,6 +20,9 @@ const {
getContent, serviceUrl, getComponent
} = __non_webpack_require__('/lib/xp/portal')
const React4xp: React4xp = __non_webpack_require__('/lib/enonic/react4xp')
const {
prepareStatisticRelease
} = __non_webpack_require__('/lib/ssb/utils/variantUtils')

exports.get = (req: Request): React4xpResponse => {
return renderPart(req)
Expand All @@ -40,7 +43,7 @@ function renderPart(req: Request): React4xpResponse {
const releasesPrepped: Array<PreparedStatistics | null> = fromPartCache(req, `${content._id}-publicationArchive`, () => {
const releases: Array<StatisticInListing> = getAllStatisticsFromRepo()
const releasesFiltered: Array<StatisticInListing> = filterOnPreviousReleases(releases, releases.length).filter((r) => r.status === 'A')
return releasesFiltered.map((release: StatisticInListing) => prepareRelease(release, language))
return releasesFiltered.map((release: StatisticInListing) => prepareStatisticRelease(release, language))
})

const props: PartProperties = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const {
addMonthNames,
getReleasesForDay,
groupStatisticsByYearMonthAndDay,
prepareRelease
prepareStatisticRelease
} = __non_webpack_require__('/lib/ssb/utils/variantUtils')

exports.get = function(req: Request): React4xpResponse | Response {
Expand Down Expand Up @@ -65,7 +65,7 @@ export function renderPart(req: Request): React4xpResponse {
const releasesFiltered: Array<StatisticInListing> = filterOnPreviousReleases(releases, numberOfReleases)

// Choose the right variant and prepare the date in a way it works with the groupBy function
const releasesPrepped: Array<PreparedStatistics> = releasesFiltered.map((release: StatisticInListing) => prepareRelease(release, currentLanguage))
const releasesPrepped: Array<PreparedStatistics> = releasesFiltered.map((release: StatisticInListing) => prepareStatisticRelease(release, currentLanguage))

// group by year, then month, then day
const groupedByYearMonthAndDay: GroupedBy<GroupedBy<GroupedBy<PreparedStatistics>>> = groupStatisticsByYearMonthAndDay(releasesPrepped)
Expand Down
Loading