ghost 5.65.1 → 5.66.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/components/{tryghost-adapter-cache-memory-ttl-5.65.1.tgz → tryghost-adapter-cache-memory-ttl-5.66.0.tgz} +0 -0
  2. package/components/{tryghost-adapter-cache-redis-5.65.1.tgz → tryghost-adapter-cache-redis-5.66.0.tgz} +0 -0
  3. package/components/{tryghost-adapter-manager-5.65.1.tgz → tryghost-adapter-manager-5.66.0.tgz} +0 -0
  4. package/components/{tryghost-announcement-bar-settings-5.65.1.tgz → tryghost-announcement-bar-settings-5.66.0.tgz} +0 -0
  5. package/components/tryghost-api-framework-5.66.0.tgz +0 -0
  6. package/components/{tryghost-api-version-compatibility-service-5.65.1.tgz → tryghost-api-version-compatibility-service-5.66.0.tgz} +0 -0
  7. package/components/{tryghost-audience-feedback-5.65.1.tgz → tryghost-audience-feedback-5.66.0.tgz} +0 -0
  8. package/components/tryghost-bookshelf-repository-5.66.0.tgz +0 -0
  9. package/components/tryghost-bootstrap-socket-5.66.0.tgz +0 -0
  10. package/components/tryghost-collections-5.66.0.tgz +0 -0
  11. package/components/tryghost-constants-5.66.0.tgz +0 -0
  12. package/components/{tryghost-custom-theme-settings-service-5.65.1.tgz → tryghost-custom-theme-settings-service-5.66.0.tgz} +0 -0
  13. package/components/{tryghost-data-generator-5.65.1.tgz → tryghost-data-generator-5.66.0.tgz} +0 -0
  14. package/components/{tryghost-domain-events-5.65.1.tgz → tryghost-domain-events-5.66.0.tgz} +0 -0
  15. package/components/tryghost-donations-5.66.0.tgz +0 -0
  16. package/components/{tryghost-dynamic-routing-events-5.65.1.tgz → tryghost-dynamic-routing-events-5.66.0.tgz} +0 -0
  17. package/components/tryghost-email-analytics-provider-mailgun-5.66.0.tgz +0 -0
  18. package/components/{tryghost-email-analytics-service-5.65.1.tgz → tryghost-email-analytics-service-5.66.0.tgz} +0 -0
  19. package/components/tryghost-email-content-generator-5.66.0.tgz +0 -0
  20. package/components/tryghost-email-events-5.66.0.tgz +0 -0
  21. package/components/{tryghost-email-service-5.65.1.tgz → tryghost-email-service-5.66.0.tgz} +0 -0
  22. package/components/tryghost-email-suppression-list-5.66.0.tgz +0 -0
  23. package/components/tryghost-event-aware-cache-wrapper-5.66.0.tgz +0 -0
  24. package/components/tryghost-express-dynamic-redirects-5.66.0.tgz +0 -0
  25. package/components/tryghost-external-media-inliner-5.66.0.tgz +0 -0
  26. package/components/{tryghost-extract-api-key-5.65.1.tgz → tryghost-extract-api-key-5.66.0.tgz} +0 -0
  27. package/components/{tryghost-html-to-plaintext-5.65.1.tgz → tryghost-html-to-plaintext-5.66.0.tgz} +0 -0
  28. package/components/tryghost-i18n-5.66.0.tgz +0 -0
  29. package/components/tryghost-importer-handler-content-files-5.66.0.tgz +0 -0
  30. package/components/{tryghost-importer-revue-5.65.1.tgz → tryghost-importer-revue-5.66.0.tgz} +0 -0
  31. package/components/{tryghost-in-memory-repository-5.65.1.tgz → tryghost-in-memory-repository-5.66.0.tgz} +0 -0
  32. package/components/{tryghost-job-manager-5.65.1.tgz → tryghost-job-manager-5.66.0.tgz} +0 -0
  33. package/components/tryghost-link-redirects-5.66.0.tgz +0 -0
  34. package/components/tryghost-link-replacer-5.66.0.tgz +0 -0
  35. package/components/{tryghost-link-tracking-5.65.1.tgz → tryghost-link-tracking-5.66.0.tgz} +0 -0
  36. package/components/tryghost-magic-link-5.66.0.tgz +0 -0
  37. package/components/tryghost-mail-events-5.66.0.tgz +0 -0
  38. package/components/{tryghost-mailgun-client-5.65.1.tgz → tryghost-mailgun-client-5.66.0.tgz} +0 -0
  39. package/components/{tryghost-member-attribution-5.65.1.tgz → tryghost-member-attribution-5.66.0.tgz} +0 -0
  40. package/components/tryghost-member-events-5.66.0.tgz +0 -0
  41. package/components/tryghost-members-api-5.66.0.tgz +0 -0
  42. package/components/{tryghost-members-csv-5.65.1.tgz → tryghost-members-csv-5.66.0.tgz} +0 -0
  43. package/components/{tryghost-members-events-service-5.65.1.tgz → tryghost-members-events-service-5.66.0.tgz} +0 -0
  44. package/components/{tryghost-members-importer-5.65.1.tgz → tryghost-members-importer-5.66.0.tgz} +0 -0
  45. package/components/{tryghost-members-offers-5.65.1.tgz → tryghost-members-offers-5.66.0.tgz} +0 -0
  46. package/components/{tryghost-members-payments-5.65.1.tgz → tryghost-members-payments-5.66.0.tgz} +0 -0
  47. package/components/{tryghost-members-ssr-5.65.1.tgz → tryghost-members-ssr-5.66.0.tgz} +0 -0
  48. package/components/{tryghost-members-stripe-service-5.65.1.tgz → tryghost-members-stripe-service-5.66.0.tgz} +0 -0
  49. package/components/tryghost-mentions-email-report-5.66.0.tgz +0 -0
  50. package/components/{tryghost-milestones-5.65.1.tgz → tryghost-milestones-5.66.0.tgz} +0 -0
  51. package/components/{tryghost-minifier-5.65.1.tgz → tryghost-minifier-5.66.0.tgz} +0 -0
  52. package/components/tryghost-model-to-domain-event-interceptor-5.66.0.tgz +0 -0
  53. package/components/{tryghost-mw-api-version-mismatch-5.65.1.tgz → tryghost-mw-api-version-mismatch-5.66.0.tgz} +0 -0
  54. package/components/tryghost-mw-cache-control-5.66.0.tgz +0 -0
  55. package/components/{tryghost-mw-error-handler-5.65.1.tgz → tryghost-mw-error-handler-5.66.0.tgz} +0 -0
  56. package/components/tryghost-mw-session-from-token-5.66.0.tgz +0 -0
  57. package/components/tryghost-mw-update-user-last-seen-5.66.0.tgz +0 -0
  58. package/components/{tryghost-mw-version-match-5.65.1.tgz → tryghost-mw-version-match-5.66.0.tgz} +0 -0
  59. package/components/tryghost-mw-vhost-5.66.0.tgz +0 -0
  60. package/components/tryghost-nql-filter-expansions-5.66.0.tgz +0 -0
  61. package/components/tryghost-oembed-service-5.66.0.tgz +0 -0
  62. package/components/{tryghost-package-json-5.65.1.tgz → tryghost-package-json-5.66.0.tgz} +0 -0
  63. package/components/tryghost-post-events-5.66.0.tgz +0 -0
  64. package/components/{tryghost-post-revisions-5.65.1.tgz → tryghost-post-revisions-5.66.0.tgz} +0 -0
  65. package/components/{tryghost-posts-service-5.65.1.tgz → tryghost-posts-service-5.66.0.tgz} +0 -0
  66. package/components/tryghost-recommendations-5.66.0.tgz +0 -0
  67. package/components/tryghost-referrers-5.66.0.tgz +0 -0
  68. package/components/tryghost-security-5.66.0.tgz +0 -0
  69. package/components/tryghost-session-service-5.66.0.tgz +0 -0
  70. package/components/{tryghost-settings-path-manager-5.65.1.tgz → tryghost-settings-path-manager-5.66.0.tgz} +0 -0
  71. package/components/tryghost-slack-notifications-5.66.0.tgz +0 -0
  72. package/components/tryghost-staff-service-5.66.0.tgz +0 -0
  73. package/components/tryghost-stats-service-5.66.0.tgz +0 -0
  74. package/components/tryghost-tiers-5.66.0.tgz +0 -0
  75. package/components/tryghost-update-check-service-5.66.0.tgz +0 -0
  76. package/components/{tryghost-verification-trigger-5.65.1.tgz → tryghost-verification-trigger-5.66.0.tgz} +0 -0
  77. package/components/tryghost-version-notifications-data-service-5.66.0.tgz +0 -0
  78. package/components/tryghost-webmentions-5.66.0.tgz +0 -0
  79. package/core/built/admin/assets/admin-x-settings/{CodeEditorView-2b332315.mjs → CodeEditorView-b1c6a306.mjs} +424 -418
  80. package/core/built/admin/assets/admin-x-settings/admin-x-settings.js +2 -2
  81. package/core/built/admin/assets/admin-x-settings/index-02567620.mjs +17406 -0
  82. package/core/built/admin/assets/admin-x-settings/{limit-service-7694c0d4.mjs → limit-service-bf02ec54.mjs} +2 -2
  83. package/core/built/admin/assets/admin-x-settings/{modals-2073207d.mjs → modals-d2fd552b.mjs} +4281 -4177
  84. package/core/built/admin/assets/{chunk.143.c7348acc96d1ce431133.js → chunk.143.f2758c8aac6998f30b19.js} +5 -5
  85. package/core/built/admin/assets/{chunk.178.287163c7606fb9fd3267.js → chunk.178.1dd5d9b6741e78efa75a.js} +4 -4
  86. package/core/built/admin/assets/{chunk.518.396deed1a0c759d1f403.js → chunk.555.ba02d5a0095b4c4a7700.js} +57 -54
  87. package/core/built/admin/assets/{ghost-38746349a72536a92f4d8235a582d716.js → ghost-56045473f2cfd232419a9d27bf8225a5.js} +174 -182
  88. package/core/built/admin/assets/ghost-dark-54c925ac8f527d36132c18af7bef116e.css +1 -0
  89. package/core/built/admin/assets/ghost-f1a535bfec933b08a7a45f607cc245b1.css +1 -0
  90. package/core/built/admin/assets/{vendor-240cd1dbd84a2e07709b867442c41840.js → vendor-5aa07b661eeb443bf7dd2c1de3b3f387.js} +22 -20
  91. package/core/built/admin/index.html +6 -6
  92. package/core/frontend/helpers/recommendations.js +116 -0
  93. package/core/frontend/helpers/tpl/recommendations.hbs +15 -0
  94. package/core/server/adapters/scheduling/scheduling-default.js +8 -8
  95. package/core/server/api/endpoints/recommendations-public.js +2 -1
  96. package/core/server/api/endpoints/utils/serializers/output/utils/clean.js +1 -0
  97. package/core/server/data/migrations/versions/5.66/2023-09-22-14-15-add-recommendation-notifications-column.js +7 -0
  98. package/core/server/data/schema/schema.js +1 -0
  99. package/core/server/lib/image/Gravatar.js +1 -1
  100. package/core/server/lib/image/ImageSize.js +7 -3
  101. package/core/server/lib/request-external.js +9 -0
  102. package/core/server/models/post.js +46 -0
  103. package/core/server/models/user.js +3 -0
  104. package/core/server/services/collections/PostsRepository.js +7 -2
  105. package/core/server/services/comments/CommentsServiceEmails.js +1 -1
  106. package/core/server/services/mentions/BookshelfMentionRepository.js +2 -1
  107. package/core/server/services/mentions/service.js +4 -0
  108. package/core/server/services/recommendations/RecommendationEnablerService.js +1 -1
  109. package/core/server/services/recommendations/RecommendationServiceWrapper.js +68 -8
  110. package/core/server/services/themes/installer.js +1 -1
  111. package/core/server/services/webhooks/WebhookTrigger.js +6 -2
  112. package/core/server/services/xmlrpc.js +3 -1
  113. package/core/shared/labs.js +5 -0
  114. package/package.json +149 -149
  115. package/yarn.lock +283 -158
  116. package/components/tryghost-api-framework-5.65.1.tgz +0 -0
  117. package/components/tryghost-bookshelf-repository-5.65.1.tgz +0 -0
  118. package/components/tryghost-bootstrap-socket-5.65.1.tgz +0 -0
  119. package/components/tryghost-collections-5.65.1.tgz +0 -0
  120. package/components/tryghost-constants-5.65.1.tgz +0 -0
  121. package/components/tryghost-donations-5.65.1.tgz +0 -0
  122. package/components/tryghost-email-analytics-provider-mailgun-5.65.1.tgz +0 -0
  123. package/components/tryghost-email-content-generator-5.65.1.tgz +0 -0
  124. package/components/tryghost-email-events-5.65.1.tgz +0 -0
  125. package/components/tryghost-email-suppression-list-5.65.1.tgz +0 -0
  126. package/components/tryghost-event-aware-cache-wrapper-5.65.1.tgz +0 -0
  127. package/components/tryghost-express-dynamic-redirects-5.65.1.tgz +0 -0
  128. package/components/tryghost-external-media-inliner-5.65.1.tgz +0 -0
  129. package/components/tryghost-i18n-5.65.1.tgz +0 -0
  130. package/components/tryghost-importer-handler-content-files-5.65.1.tgz +0 -0
  131. package/components/tryghost-link-redirects-5.65.1.tgz +0 -0
  132. package/components/tryghost-link-replacer-5.65.1.tgz +0 -0
  133. package/components/tryghost-magic-link-5.65.1.tgz +0 -0
  134. package/components/tryghost-mail-events-5.65.1.tgz +0 -0
  135. package/components/tryghost-member-events-5.65.1.tgz +0 -0
  136. package/components/tryghost-members-api-5.65.1.tgz +0 -0
  137. package/components/tryghost-mentions-email-report-5.65.1.tgz +0 -0
  138. package/components/tryghost-model-to-domain-event-interceptor-5.65.1.tgz +0 -0
  139. package/components/tryghost-mw-cache-control-5.65.1.tgz +0 -0
  140. package/components/tryghost-mw-session-from-token-5.65.1.tgz +0 -0
  141. package/components/tryghost-mw-update-user-last-seen-5.65.1.tgz +0 -0
  142. package/components/tryghost-mw-vhost-5.65.1.tgz +0 -0
  143. package/components/tryghost-nql-filter-expansions-5.65.1.tgz +0 -0
  144. package/components/tryghost-oembed-service-5.65.1.tgz +0 -0
  145. package/components/tryghost-post-events-5.65.1.tgz +0 -0
  146. package/components/tryghost-recommendations-5.65.1.tgz +0 -0
  147. package/components/tryghost-referrers-5.65.1.tgz +0 -0
  148. package/components/tryghost-security-5.65.1.tgz +0 -0
  149. package/components/tryghost-session-service-5.65.1.tgz +0 -0
  150. package/components/tryghost-slack-notifications-5.65.1.tgz +0 -0
  151. package/components/tryghost-staff-service-5.65.1.tgz +0 -0
  152. package/components/tryghost-stats-service-5.65.1.tgz +0 -0
  153. package/components/tryghost-tiers-5.65.1.tgz +0 -0
  154. package/components/tryghost-update-check-service-5.65.1.tgz +0 -0
  155. package/components/tryghost-version-notifications-data-service-5.65.1.tgz +0 -0
  156. package/components/tryghost-webmentions-5.65.1.tgz +0 -0
  157. package/core/built/admin/assets/admin-x-settings/index-4a560e9e.mjs +0 -19693
  158. package/core/built/admin/assets/ghost-761b67711827277b7095ebc7acc5c49f.css +0 -1
  159. package/core/built/admin/assets/ghost-dark-d3f636c30e80bdd7f21d3fb4770073c9.css +0 -1
  160. /package/core/built/admin/assets/{chunk.518.396deed1a0c759d1f403.js.LICENSE.txt → chunk.555.ba02d5a0095b4c4a7700.js.LICENSE.txt} +0 -0
@@ -3546,14 +3546,14 @@ n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Obj
3546
3546
  for(var r=new Array(t),n=0;n<t;n++)r[n]=e[n]
3547
3547
  return r}})),e("ember/index",["exports","require","@ember/-internals/environment","node-module","@ember/-internals/utils","@ember/-internals/container","@ember/instrumentation","@ember/-internals/meta","@ember/-internals/metal","@ember/canary-features","@ember/debug","backburner","@ember/-internals/console","@ember/controller","@ember/controller/lib/controller_mixin","@ember/string","@ember/service","@ember/object","@ember/object/compat","@ember/object/computed","@ember/-internals/runtime","@ember/-internals/glimmer","ember/version","@ember/-internals/views","@ember/-internals/routing","@ember/-internals/extension-support","@ember/error","@ember/runloop","@ember/-internals/error-handling","@ember/-internals/owner","@ember/application","@ember/application/globals-resolver","@ember/application/instance","@ember/engine","@ember/engine/instance","@ember/polyfills","@ember/deprecated-features","@ember/component/template-only","@glimmer/runtime","@ember/destroyable"],(function(e,t,r,n,i,o,a,s,l,u,c,d,h,p,f,m,g,b,v,y,_,k,E,w,x,O,C,T,S,P,M,A,R,j,D,I,N,L,F,z){"use strict"
3548
3548
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
3549
- var B="object"==typeof r.context.imports.Ember&&r.context.imports.Ember||{}
3550
- B.isNamespace=!0,B.toString=function(){return"Ember"},Object.defineProperty(B,"ENV",{get:r.getENV,enumerable:!1}),Object.defineProperty(B,"lookup",{get:r.getLookup,set:r.setLookup,enumerable:!1}),N.EMBER_EXTEND_PROTOTYPES&&Object.defineProperty(B,"EXTEND_PROTOTYPES",{enumerable:!1,get:()=>r.ENV.EXTEND_PROTOTYPES}),B.getOwner=P.getOwner,B.setOwner=P.setOwner,B.Application=M.default,B.ApplicationInstance=R.default,Object.defineProperty(B,"Resolver",{get:()=>A.default}),Object.defineProperty(B,"DefaultResolver",{get:()=>B.Resolver}),B.Engine=j.default,B.EngineInstance=D.default,B.assign=I.assign,B.merge=I.merge,B.generateGuid=i.generateGuid,B.GUID_KEY=i.GUID_KEY,B.guidFor=i.guidFor,B.inspect=i.inspect,B.makeArray=i.makeArray,B.canInvoke=i.canInvoke,B.tryInvoke=i.tryInvoke,B.wrap=i.wrap,B.uuid=i.uuid,B.Container=o.Container,B.Registry=o.Registry,B.assert=c.assert,B.warn=c.warn,B.debug=c.debug,B.deprecate=c.deprecate
3551
- B.deprecateFunc=c.deprecateFunc,B.runInDebug=c.runInDebug,B.Error=C.default,B.Debug={registerDeprecationHandler:c.registerDeprecationHandler,registerWarnHandler:c.registerWarnHandler,isComputed:l.isComputed},B.instrument=a.instrument,B.subscribe=a.subscribe,B.Instrumentation={instrument:a.instrument,subscribe:a.subscribe,unsubscribe:a.unsubscribe,reset:a.reset},B.run=T._globalsRun,B.run.backburner=T.backburner,B.run.begin=T.begin,B.run.bind=T.bind,B.run.cancel=T.cancel,B.run.debounce=T.debounce,B.run.end=T.end,B.run.hasScheduledTimers=T.hasScheduledTimers,B.run.join=T.join,B.run.later=T.later,B.run.next=T.next,B.run.once=T.once,B.run.schedule=T.schedule,B.run.scheduleOnce=T.scheduleOnce,B.run.throttle=T.throttle,B.run.cancelTimers=T.cancelTimers,Object.defineProperty(B.run,"currentRunLoop",{get:T.getCurrentRunLoop,enumerable:!1})
3552
- var H=l._globalsComputed
3553
- if(B.computed=H,B._descriptor=l.nativeDescDecorator,B._tracked=l.tracked,H.alias=l.alias,B.cacheFor=l.getCachedValueFor,B.ComputedProperty=l.ComputedProperty,B._setClassicDecorator=l.setClassicDecorator,B.meta=s.meta,B.get=l.get,B.getWithDefault=l.getWithDefault,B._getPath=l._getPath,B.set=l.set,B.trySet=l.trySet,B.FEATURES=(0,I.assign)({isEnabled:u.isEnabled},u.FEATURES),B._Cache=i.Cache,B.on=l.on,B.addListener=l.addListener,B.removeListener=l.removeListener,B.sendEvent=l.sendEvent,B.hasListeners=l.hasListeners,B.isNone=l.isNone,B.isEmpty=l.isEmpty,B.isBlank=l.isBlank,B.isPresent=l.isPresent,B.notifyPropertyChange=l.notifyPropertyChange,B.beginPropertyChanges=l.beginPropertyChanges,B.endPropertyChanges=l.endPropertyChanges,B.changeProperties=l.changeProperties,B.platform={defineProperty:!0,hasPropertyAccessors:!0},B.defineProperty=l.defineProperty,B.destroy=z.destroy,B.libraries=l.libraries,B.getProperties=l.getProperties,B.setProperties=l.setProperties,B.expandProperties=l.expandProperties,B.addObserver=l.addObserver,B.removeObserver=l.removeObserver,B.aliasMethod=l.aliasMethod,B.observer=l.observer,B.mixin=l.mixin,B.Mixin=l.Mixin,B._createCache=l.createCache,B._cacheGetValue=l.getValue,B._cacheIsConst=l.isConst,B._registerDestructor=z.registerDestructor,B._unregisterDestructor=z.unregisterDestructor,B._associateDestroyableChild=z.associateDestroyableChild,B._assertDestroyablesDestroyed=z.assertDestroyablesDestroyed,B._enableDestroyableTracking=z.enableDestroyableTracking,B._isDestroying=z.isDestroying,B._isDestroyed=z.isDestroyed,Object.defineProperty(B,"onerror",{get:S.getOnerror,set:S.setOnerror,enumerable:!1}),Object.defineProperty(B,"testing",{get:c.isTesting,set:c.setTesting,enumerable:!1}),B._Backburner=d.default,N.LOGGER&&(B.Logger=h.default),B.A=_.A,B.String={loc:m.loc,w:m.w,dasherize:m.dasherize,decamelize:m.decamelize,camelize:m.camelize,classify:m.classify,underscore:m.underscore,capitalize:m.capitalize},B.Object=_.Object,B._RegistryProxyMixin=_.RegistryProxyMixin,B._ContainerProxyMixin=_.ContainerProxyMixin,B.compare=_.compare,B.copy=_.copy,B.isEqual=_.isEqual,B.inject=function(){},B.inject.service=g.inject,B.inject.controller=p.inject,B.Array=_.Array,B.Comparable=_.Comparable,B.Enumerable=_.Enumerable,B.ArrayProxy=_.ArrayProxy,B.ObjectProxy=_.ObjectProxy,B.ActionHandler=_.ActionHandler,B.CoreObject=_.CoreObject,B.NativeArray=_.NativeArray,B.Copyable=_.Copyable,B.MutableEnumerable=_.MutableEnumerable,B.MutableArray=_.MutableArray,B.TargetActionSupport=_.TargetActionSupport,B.Evented=_.Evented,B.PromiseProxyMixin=_.PromiseProxyMixin,B.Observable=_.Observable,B.typeOf=_.typeOf,B.isArray=_.isArray,B.Object=_.Object,B.onLoad=M.onLoad,B.runLoadHooks=M.runLoadHooks,B.Controller=p.default,B.ControllerMixin=f.default,B.Service=g.default,B._ProxyMixin=_._ProxyMixin,B.RSVP=_.RSVP,B.Namespace=_.Namespace,B._action=b.action,B._dependentKeyCompat=v.dependentKeyCompat,H.empty=y.empty,H.notEmpty=y.notEmpty,H.none=y.none,H.not=y.not,H.bool=y.bool,H.match=y.match,H.equal=y.equal,H.gt=y.gt,H.gte=y.gte,H.lt=y.lt,H.lte=y.lte,H.oneWay=y.oneWay,H.reads=y.oneWay,H.readOnly=y.readOnly,H.deprecatingAlias=y.deprecatingAlias,H.and=y.and,H.or=y.or,H.sum=y.sum,H.min=y.min,H.max=y.max,H.map=y.map,H.sort=y.sort,H.setDiff=y.setDiff,H.mapBy=y.mapBy,H.filter=y.filter,H.filterBy=y.filterBy,H.uniq=y.uniq,H.uniqBy=y.uniqBy,H.union=y.union,H.intersect=y.intersect,H.collect=y.collect,Object.defineProperty(B,"STRINGS",{configurable:!1,get:m._getStrings,set:m._setStrings}),Object.defineProperty(B,"BOOTED",{configurable:!1,enumerable:!1,get:l.isNamespaceSearchDisabled,set:l.setNamespaceSearchDisabled}),B.Component=k.Component,k.Helper.helper=k.helper,B.Helper=k.Helper,B.Checkbox=k.Checkbox,B.TextField=k.TextField,B.TextArea=k.TextArea,B.LinkComponent=k.LinkComponent,B.TextSupport=w.TextSupport,B._setComponentManager=k.setComponentManager,B._componentManagerCapabilities=k.capabilities,B._setModifierManager=F.setModifierManager,B._modifierManagerCapabilities=k.modifierCapabilities,B._getComponentTemplate=F.getComponentTemplate,B._setComponentTemplate=F.setComponentTemplate,B._templateOnlyComponent=L.default,B._helperManagerCapabilities=k.helperCapabilities,B._setHelperManager=F.setHelperManager,B._invokeHelper=k.invokeHelper,B._captureRenderTree=c.captureRenderTree,B.Handlebars={template:k.template,Utils:{escapeExpression:k.escapeExpression}},B.HTMLBars={template:k.template},r.ENV.EXTEND_PROTOTYPES.String&&(String.prototype.htmlSafe=function(){return(0,k.htmlSafe)(this)}),B.String.htmlSafe=k.htmlSafe,B.String.isHTMLSafe=k.isHTMLSafe,Object.defineProperty(B,"TEMPLATES",{get:k.getTemplates,set:k.setTemplates,configurable:!1,enumerable:!1}),B.VERSION=E.default,N.JQUERY_INTEGRATION&&!w.jQueryDisabled&&Object.defineProperty(B,"$",{get:()=>w.jQuery,configurable:!0,enumerable:!0}),B.ViewUtils={isSimpleClick:w.isSimpleClick,getElementView:w.getElementView,getViewElement:w.getViewElement,getViewBounds:w.getViewBounds,getViewClientRects:w.getViewClientRects,getViewBoundingClientRect:w.getViewBoundingClientRect,getRootViews:w.getRootViews,getChildViews:w.getChildViews,isSerializationFirstNode:k.isSerializationFirstNode},B.ComponentLookup=w.ComponentLookup,B.EventDispatcher=w.EventDispatcher,B.Location=x.Location,B.AutoLocation=x.AutoLocation,B.HashLocation=x.HashLocation,B.HistoryLocation=x.HistoryLocation,B.NoneLocation=x.NoneLocation,B.controllerFor=x.controllerFor,B.generateControllerFactory=x.generateControllerFactory,B.generateController=x.generateController,B.RouterDSL=x.RouterDSL,B.Router=x.Router,B.Route=x.Route,(0,M.runLoadHooks)("Ember.Application",M.default),B.DataAdapter=O.DataAdapter,B.ContainerDebugAdapter=O.ContainerDebugAdapter,(0,t.has)("ember-template-compiler")&&(0,t.default)("ember-template-compiler"),(0,t.has)("ember-testing")){var U=(0,t.default)("ember-testing")
3554
- B.Test=U.Test,B.Test.Adapter=U.Adapter,B.Test.QUnitAdapter=U.QUnitAdapter,B.setupForTesting=U.setupForTesting}(0,M.runLoadHooks)("Ember")
3555
- var V=B
3556
- e.default=V,n.IS_NODE?n.module.exports=B:r.context.exports.Ember=r.context.exports.Em=B})),e("ember/version",["exports"],(function(e){"use strict"
3549
+ var B=c,H="object"==typeof r.context.imports.Ember&&r.context.imports.Ember||{}
3550
+ H.isNamespace=!0,H.toString=function(){return"Ember"},Object.defineProperty(H,"ENV",{get:r.getENV,enumerable:!1}),Object.defineProperty(H,"lookup",{get:r.getLookup,set:r.setLookup,enumerable:!1}),N.EMBER_EXTEND_PROTOTYPES&&Object.defineProperty(H,"EXTEND_PROTOTYPES",{enumerable:!1,get:()=>r.ENV.EXTEND_PROTOTYPES}),H.getOwner=P.getOwner,H.setOwner=P.setOwner,H.Application=M.default,H.ApplicationInstance=R.default,Object.defineProperty(H,"Resolver",{get:()=>A.default}),Object.defineProperty(H,"DefaultResolver",{get:()=>H.Resolver}),H.Engine=j.default,H.EngineInstance=D.default,H.assign=I.assign,H.merge=I.merge,H.generateGuid=i.generateGuid,H.GUID_KEY=i.GUID_KEY,H.guidFor=i.guidFor,H.inspect=i.inspect,H.makeArray=i.makeArray,H.canInvoke=i.canInvoke,H.tryInvoke=i.tryInvoke,H.wrap=i.wrap,H.uuid=i.uuid,H.Container=o.Container,H.Registry=o.Registry,H.assert=B.assert,H.warn=B.warn,H.debug=B.debug,H.deprecate=B.deprecate
3551
+ H.deprecateFunc=B.deprecateFunc,H.runInDebug=B.runInDebug,H.Error=C.default,H.Debug={registerDeprecationHandler:B.registerDeprecationHandler,registerWarnHandler:B.registerWarnHandler,isComputed:l.isComputed},H.instrument=a.instrument,H.subscribe=a.subscribe,H.Instrumentation={instrument:a.instrument,subscribe:a.subscribe,unsubscribe:a.unsubscribe,reset:a.reset},H.run=T._globalsRun,H.run.backburner=T.backburner,H.run.begin=T.begin,H.run.bind=T.bind,H.run.cancel=T.cancel,H.run.debounce=T.debounce,H.run.end=T.end,H.run.hasScheduledTimers=T.hasScheduledTimers,H.run.join=T.join,H.run.later=T.later,H.run.next=T.next,H.run.once=T.once,H.run.schedule=T.schedule,H.run.scheduleOnce=T.scheduleOnce,H.run.throttle=T.throttle,H.run.cancelTimers=T.cancelTimers,Object.defineProperty(H.run,"currentRunLoop",{get:T.getCurrentRunLoop,enumerable:!1})
3552
+ var U=l._globalsComputed
3553
+ if(H.computed=U,H._descriptor=l.nativeDescDecorator,H._tracked=l.tracked,U.alias=l.alias,H.cacheFor=l.getCachedValueFor,H.ComputedProperty=l.ComputedProperty,H._setClassicDecorator=l.setClassicDecorator,H.meta=s.meta,H.get=l.get,H.getWithDefault=l.getWithDefault,H._getPath=l._getPath,H.set=l.set,H.trySet=l.trySet,H.FEATURES=(0,I.assign)({isEnabled:u.isEnabled},u.FEATURES),H._Cache=i.Cache,H.on=l.on,H.addListener=l.addListener,H.removeListener=l.removeListener,H.sendEvent=l.sendEvent,H.hasListeners=l.hasListeners,H.isNone=l.isNone,H.isEmpty=l.isEmpty,H.isBlank=l.isBlank,H.isPresent=l.isPresent,H.notifyPropertyChange=l.notifyPropertyChange,H.beginPropertyChanges=l.beginPropertyChanges,H.endPropertyChanges=l.endPropertyChanges,H.changeProperties=l.changeProperties,H.platform={defineProperty:!0,hasPropertyAccessors:!0},H.defineProperty=l.defineProperty,H.destroy=z.destroy,H.libraries=l.libraries,H.getProperties=l.getProperties,H.setProperties=l.setProperties,H.expandProperties=l.expandProperties,H.addObserver=l.addObserver,H.removeObserver=l.removeObserver,H.aliasMethod=l.aliasMethod,H.observer=l.observer,H.mixin=l.mixin,H.Mixin=l.Mixin,H._createCache=l.createCache,H._cacheGetValue=l.getValue,H._cacheIsConst=l.isConst,H._registerDestructor=z.registerDestructor,H._unregisterDestructor=z.unregisterDestructor,H._associateDestroyableChild=z.associateDestroyableChild,H._assertDestroyablesDestroyed=z.assertDestroyablesDestroyed,H._enableDestroyableTracking=z.enableDestroyableTracking,H._isDestroying=z.isDestroying,H._isDestroyed=z.isDestroyed,Object.defineProperty(H,"onerror",{get:S.getOnerror,set:S.setOnerror,enumerable:!1}),Object.defineProperty(H,"testing",{get:B.isTesting,set:B.setTesting,enumerable:!1}),H._Backburner=d.default,N.LOGGER&&(H.Logger=h.default),H.A=_.A,H.String={loc:m.loc,w:m.w,dasherize:m.dasherize,decamelize:m.decamelize,camelize:m.camelize,classify:m.classify,underscore:m.underscore,capitalize:m.capitalize},H.Object=_.Object,H._RegistryProxyMixin=_.RegistryProxyMixin,H._ContainerProxyMixin=_.ContainerProxyMixin,H.compare=_.compare,H.copy=_.copy,H.isEqual=_.isEqual,H.inject=function(){},H.inject.service=g.inject,H.inject.controller=p.inject,H.Array=_.Array,H.Comparable=_.Comparable,H.Enumerable=_.Enumerable,H.ArrayProxy=_.ArrayProxy,H.ObjectProxy=_.ObjectProxy,H.ActionHandler=_.ActionHandler,H.CoreObject=_.CoreObject,H.NativeArray=_.NativeArray,H.Copyable=_.Copyable,H.MutableEnumerable=_.MutableEnumerable,H.MutableArray=_.MutableArray,H.TargetActionSupport=_.TargetActionSupport,H.Evented=_.Evented,H.PromiseProxyMixin=_.PromiseProxyMixin,H.Observable=_.Observable,H.typeOf=_.typeOf,H.isArray=_.isArray,H.Object=_.Object,H.onLoad=M.onLoad,H.runLoadHooks=M.runLoadHooks,H.Controller=p.default,H.ControllerMixin=f.default,H.Service=g.default,H._ProxyMixin=_._ProxyMixin,H.RSVP=_.RSVP,H.Namespace=_.Namespace,H._action=b.action,H._dependentKeyCompat=v.dependentKeyCompat,U.empty=y.empty,U.notEmpty=y.notEmpty,U.none=y.none,U.not=y.not,U.bool=y.bool,U.match=y.match,U.equal=y.equal,U.gt=y.gt,U.gte=y.gte,U.lt=y.lt,U.lte=y.lte,U.oneWay=y.oneWay,U.reads=y.oneWay,U.readOnly=y.readOnly,U.deprecatingAlias=y.deprecatingAlias,U.and=y.and,U.or=y.or,U.sum=y.sum,U.min=y.min,U.max=y.max,U.map=y.map,U.sort=y.sort,U.setDiff=y.setDiff,U.mapBy=y.mapBy,U.filter=y.filter,U.filterBy=y.filterBy,U.uniq=y.uniq,U.uniqBy=y.uniqBy,U.union=y.union,U.intersect=y.intersect,U.collect=y.collect,Object.defineProperty(H,"STRINGS",{configurable:!1,get:m._getStrings,set:m._setStrings}),Object.defineProperty(H,"BOOTED",{configurable:!1,enumerable:!1,get:l.isNamespaceSearchDisabled,set:l.setNamespaceSearchDisabled}),H.Component=k.Component,k.Helper.helper=k.helper,H.Helper=k.Helper,H.Checkbox=k.Checkbox,H.TextField=k.TextField,H.TextArea=k.TextArea,H.LinkComponent=k.LinkComponent,H.TextSupport=w.TextSupport,H._setComponentManager=k.setComponentManager,H._componentManagerCapabilities=k.capabilities,H._setModifierManager=F.setModifierManager,H._modifierManagerCapabilities=k.modifierCapabilities,H._getComponentTemplate=F.getComponentTemplate,H._setComponentTemplate=F.setComponentTemplate,H._templateOnlyComponent=L.default,H._helperManagerCapabilities=k.helperCapabilities,H._setHelperManager=F.setHelperManager,H._invokeHelper=k.invokeHelper,H._captureRenderTree=c.captureRenderTree,H.Handlebars={template:k.template,Utils:{escapeExpression:k.escapeExpression}},H.HTMLBars={template:k.template},r.ENV.EXTEND_PROTOTYPES.String&&(String.prototype.htmlSafe=function(){return(0,k.htmlSafe)(this)}),H.String.htmlSafe=k.htmlSafe,H.String.isHTMLSafe=k.isHTMLSafe,Object.defineProperty(H,"TEMPLATES",{get:k.getTemplates,set:k.setTemplates,configurable:!1,enumerable:!1}),H.VERSION=E.default,N.JQUERY_INTEGRATION&&!w.jQueryDisabled&&Object.defineProperty(H,"$",{get:()=>w.jQuery,configurable:!0,enumerable:!0}),H.ViewUtils={isSimpleClick:w.isSimpleClick,getElementView:w.getElementView,getViewElement:w.getViewElement,getViewBounds:w.getViewBounds,getViewClientRects:w.getViewClientRects,getViewBoundingClientRect:w.getViewBoundingClientRect,getRootViews:w.getRootViews,getChildViews:w.getChildViews,isSerializationFirstNode:k.isSerializationFirstNode},H.ComponentLookup=w.ComponentLookup,H.EventDispatcher=w.EventDispatcher,H.Location=x.Location,H.AutoLocation=x.AutoLocation,H.HashLocation=x.HashLocation,H.HistoryLocation=x.HistoryLocation,H.NoneLocation=x.NoneLocation,H.controllerFor=x.controllerFor,H.generateControllerFactory=x.generateControllerFactory,H.generateController=x.generateController,H.RouterDSL=x.RouterDSL,H.Router=x.Router,H.Route=x.Route,(0,M.runLoadHooks)("Ember.Application",M.default),H.DataAdapter=O.DataAdapter,H.ContainerDebugAdapter=O.ContainerDebugAdapter,(0,t.has)("ember-template-compiler")&&(0,t.default)("ember-template-compiler"),(0,t.has)("ember-testing")){var V=(0,t.default)("ember-testing")
3554
+ H.Test=V.Test,H.Test.Adapter=V.Adapter,H.Test.QUnitAdapter=V.QUnitAdapter,H.setupForTesting=V.setupForTesting}(0,M.runLoadHooks)("Ember")
3555
+ var q=H
3556
+ e.default=q,n.IS_NODE?n.module.exports=H:r.context.exports.Ember=r.context.exports.Em=H})),e("ember/version",["exports"],(function(e){"use strict"
3557
3557
  Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
3558
3558
  e.default="3.24.0"})),e("node-module/index",["exports"],(function(e){"use strict"
3559
3559
  Object.defineProperty(e,"__esModule",{value:!0}),e.require=e.module=e.IS_NODE=void 0
@@ -8878,20 +8878,22 @@ var t=Ember.HTMLBars.template({id:"g/nau/et",block:'{"symbols":["virtualComponen
8878
8878
  e.default=t})),define("@sentry/ember/index",["exports","@sentry/browser","@sentry/utils"],(function(e,t,r){"use strict"
8879
8879
  Object.defineProperty(e,"__esModule",{value:!0})
8880
8880
  var n={InitSentryForEmber:!0,getActiveTransaction:!0,instrumentRoutePerformance:!0,init:!0}
8881
- function i(e){const n={disablePerformance:!0,sentry:{}}
8881
+ e.InitSentryForEmber=o,e.instrumentRoutePerformance=e.init=e.getActiveTransaction=void 0
8882
+ var i=t
8883
+ function o(e){const n={disablePerformance:!0,sentry:{}}
8882
8884
  n.sentry||(n.sentry={...e}),Object.assign(n.sentry,e||{})
8883
- const i=Object.assign({},n.sentry)
8884
- i._metadata=i._metadata||{},i._metadata.sdk={name:"sentry.javascript.ember",packages:[{name:"npm:@sentry/ember",version:t.SDK_VERSION}],version:t.SDK_VERSION}
8885
- const o=function(){const e=r.GLOBAL_OBJ
8885
+ const o=Object.assign({},n.sentry)
8886
+ o._metadata=o._metadata||{},o._metadata.sdk={name:"sentry.javascript.ember",packages:[{name:"npm:@sentry/ember",version:t.SDK_VERSION}],version:t.SDK_VERSION}
8887
+ const a=function(){const e=r.GLOBAL_OBJ
8886
8888
  return e.__sentryEmberConfig=e.__sentryEmberConfig??{},e.__sentryEmberConfig}()
8887
- Object.assign(o,i),t.init(i)}e.InitSentryForEmber=i,e.instrumentRoutePerformance=e.init=e.getActiveTransaction=void 0,Object.keys(t).forEach((function(r){"default"!==r&&"__esModule"!==r&&(Object.prototype.hasOwnProperty.call(n,r)||r in e&&e[r]===t[r]||Object.defineProperty(e,r,{enumerable:!0,get:function(){return t[r]}}))}))
8888
- const o=()=>t.getCurrentHub().getScope().getTransaction()
8889
- e.getActiveTransaction=o
8890
- e.instrumentRoutePerformance=e=>{const t=async(e,t,n,i)=>{const a=(0,r.timestampInSeconds)(),s=await n(...i),l=o()
8891
- return l?(l.startChild({op:e,description:t,origin:"auto.ui.ember",startTimestamp:a}).finish(),s):s},n=e.name
8889
+ Object.assign(a,o),i.init(o)}Object.keys(t).forEach((function(r){"default"!==r&&"__esModule"!==r&&(Object.prototype.hasOwnProperty.call(n,r)||r in e&&e[r]===t[r]||Object.defineProperty(e,r,{enumerable:!0,get:function(){return t[r]}}))}))
8890
+ const a=()=>i.getCurrentHub().getScope().getTransaction()
8891
+ e.getActiveTransaction=a
8892
+ e.instrumentRoutePerformance=e=>{const t=async(e,t,n,i)=>{const o=(0,r.timestampInSeconds)(),s=await n(...i),l=a()
8893
+ return l?(l.startChild({op:e,description:t,origin:"auto.ui.ember",startTimestamp:o}).finish(),s):s},n=e.name
8892
8894
  return{[n]:class extends e{beforeModel(...e){return t("ui.ember.route.before_model",this.fullRouteName,super.beforeModel.bind(this),e)}async model(...e){return t("ui.ember.route.model",this.fullRouteName,super.model.bind(this),e)}afterModel(...e){return t("ui.ember.route.after_model",this.fullRouteName,super.afterModel.bind(this),e)}setupController(...e){return t("ui.ember.route.setup_controller",this.fullRouteName,super.setupController.bind(this),e)}}}[n]}
8893
- const a=i
8894
- e.init=a})),define("@sentry/ember/instance-initializers/sentry-performance",["exports","@sentry/browser","@sentry/utils","@sentry/ember"],(function(e,t,r,n){"use strict"
8895
+ const s=o
8896
+ e.init=s})),define("@sentry/ember/instance-initializers/sentry-performance",["exports","@sentry/browser","@sentry/utils","@sentry/ember"],(function(e,t,r,n){"use strict"
8895
8897
  function i(){const e=r.GLOBAL_OBJ
8896
8898
  e.__sentryEmberConfig=e.__sentryEmberConfig??{}
8897
8899
  const t={disablePerformance:!0,sentry:{}}
@@ -13616,4 +13618,4 @@ e.default=class{constructor(e){if(this._data=new t.default,e)for(let t=0;t<e.len
13616
13618
  return this}get(e){let t=this._data[e]
13617
13619
  return t===r.UNDEFINED_KEY?void 0:t}set(e,t){return this._data[e]=t,this}delete(e){return this._data[e]=r.UNDEFINED_KEY,!0}}}))
13618
13620
 
13619
- //# sourceMappingURL=vendor-240cd1dbd84a2e07709b867442c41840.map
13621
+ //# sourceMappingURL=vendor-5aa07b661eeb443bf7dd2c1de3b3f387.map
@@ -8,7 +8,7 @@
8
8
  <title>Ghost Admin</title>
9
9
 
10
10
 
11
- <meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22cdnUrl%22%3A%22%22%2C%22rootURL%22%3A%22%22%2C%22locationType%22%3A%22trailing-hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%2C%22Array%22%3Atrue%2C%22String%22%3Atrue%2C%22Function%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_JQUERY_INTEGRATION%22%3Atrue%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22version%22%3A%225.65%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22ember-websockets%22%3A%7B%22socketIO%22%3Atrue%7D%2C%22%40sentry%2Fember%22%3A%7B%22disablePerformance%22%3Atrue%2C%22sentry%22%3A%7B%7D%7D%2C%22ember-cli-mirage%22%3A%7B%22usingProxy%22%3Afalse%2C%22useDefaultPassthroughs%22%3Atrue%7D%2C%22exportApplicationGlobal%22%3Afalse%2C%22ember-load%22%3A%7B%22loadingIndicatorClass%22%3A%22ember-load-indicator%22%7D%7D" />
11
+ <meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22cdnUrl%22%3A%22%22%2C%22rootURL%22%3A%22%22%2C%22locationType%22%3A%22trailing-hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%2C%22Array%22%3Atrue%2C%22String%22%3Atrue%2C%22Function%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_JQUERY_INTEGRATION%22%3Atrue%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22version%22%3A%225.66%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22ember-websockets%22%3A%7B%22socketIO%22%3Atrue%7D%2C%22%40sentry%2Fember%22%3A%7B%22disablePerformance%22%3Atrue%2C%22sentry%22%3A%7B%7D%7D%2C%22ember-cli-mirage%22%3A%7B%22usingProxy%22%3Afalse%2C%22useDefaultPassthroughs%22%3Atrue%7D%2C%22exportApplicationGlobal%22%3Afalse%2C%22ember-load%22%3A%7B%22loadingIndicatorClass%22%3A%22ember-load-indicator%22%7D%7D" />
12
12
 
13
13
  <meta name="HandheldFriendly" content="True" />
14
14
  <meta name="MobileOptimized" content="320" />
@@ -37,7 +37,7 @@
37
37
  </style>
38
38
 
39
39
  <link integrity="" rel="stylesheet" href="assets/vendor-3e6947aa681f0fb82b193090e520dc73.css">
40
- <link integrity="" rel="stylesheet" href="assets/ghost-761b67711827277b7095ebc7acc5c49f.css" title="light">
40
+ <link integrity="" rel="stylesheet" href="assets/ghost-f1a535bfec933b08a7a45f607cc245b1.css" title="light">
41
41
 
42
42
 
43
43
  </head>
@@ -56,9 +56,9 @@
56
56
 
57
57
  <div id="ember-basic-dropdown-wormhole"></div>
58
58
 
59
- <script src="assets/vendor-240cd1dbd84a2e07709b867442c41840.js"></script>
60
- <script src="assets/chunk.518.396deed1a0c759d1f403.js"></script>
61
- <script src="assets/chunk.143.c7348acc96d1ce431133.js"></script>
62
- <script src="assets/ghost-38746349a72536a92f4d8235a582d716.js"></script>
59
+ <script src="assets/vendor-5aa07b661eeb443bf7dd2c1de3b3f387.js"></script>
60
+ <script src="assets/chunk.555.ba02d5a0095b4c4a7700.js"></script>
61
+ <script src="assets/chunk.143.f2758c8aac6998f30b19.js"></script>
62
+ <script src="assets/ghost-56045473f2cfd232419a9d27bf8225a5.js"></script>
63
63
  </body>
64
64
  </html>
@@ -0,0 +1,116 @@
1
+ /* Recommendations helper
2
+ * Usage: `{{recommendations}}`
3
+ *
4
+ * Renders the template defined in `tpl/recommendations.hbs`
5
+ * Can be overridden by themes by uploading a partial under `partials/recommendations.hbs`
6
+ *
7
+ * Available options: limit, order, filter, page
8
+ */
9
+ const {config, api, prepareContextResource, settingsCache} = require('../services/proxy');
10
+ const {templates, hbs} = require('../services/handlebars');
11
+
12
+ const logging = require('@tryghost/logging');
13
+ const errors = require('@tryghost/errors');
14
+
15
+ const createFrame = hbs.handlebars.createFrame;
16
+
17
+ /**
18
+ * Call the Recommendation Content API's browse method
19
+ * @param {Object} apiOptions
20
+ * @returns {Promise<Object>}
21
+ */
22
+ async function fetchRecommendations(apiOptions) {
23
+ let timer;
24
+
25
+ try {
26
+ const controller = api.recommendationsPublic;
27
+ let response;
28
+
29
+ const logLevel = config.get('optimization:getHelper:timeout:level') || 'error';
30
+ const threshold = config.get('optimization:getHelper:timeout:threshold') || 5000;
31
+ const apiResponse = controller.browse(apiOptions);
32
+
33
+ const timeout = new Promise((resolve) => {
34
+ timer = setTimeout(() => {
35
+ logging[logLevel](new errors.HelperWarning({
36
+ message: `{{#recommendations}} took longer than ${threshold}ms and was aborted`,
37
+ code: 'ABORTED_RECOMMENDATIONS_HELPER',
38
+ errorDetails: {
39
+ api: 'recommendationsPublic.browse',
40
+ apiOptions
41
+ }
42
+ }));
43
+
44
+ resolve({recommendations: []});
45
+ }, threshold);
46
+ });
47
+
48
+ response = await Promise.race([apiResponse, timeout]);
49
+ clearTimeout(timer);
50
+
51
+ return response;
52
+ } catch (err) {
53
+ clearTimeout(timer);
54
+ throw err;
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Parse Options
60
+ *
61
+ * @param {Object} options
62
+ * @returns {*}
63
+ */
64
+ function parseOptions(options) {
65
+ let limit = options.limit ?? 5;
66
+ let order = options.order ?? 'createdAt desc';
67
+ let filter = options.filter ?? '';
68
+ let page = options.page ?? 1;
69
+
70
+ return {
71
+ limit,
72
+ order,
73
+ filter,
74
+ page
75
+ };
76
+ }
77
+
78
+ /**
79
+ *
80
+ * @param {object} options
81
+ * @returns {Promise<any>}
82
+ */
83
+ module.exports = async function recommendations(options) {
84
+ const recommendationsEnabled = settingsCache.get('recommendations_enabled');
85
+
86
+ if (!recommendationsEnabled) {
87
+ return;
88
+ }
89
+
90
+ options = options || {};
91
+ options.hash = options.hash || {};
92
+ options.data = options.data || {};
93
+
94
+ const data = createFrame(options.data);
95
+ let apiOptions = options.hash;
96
+ apiOptions = parseOptions(apiOptions);
97
+
98
+ try {
99
+ const response = await fetchRecommendations(apiOptions);
100
+
101
+ if (response.recommendations && response.recommendations.length) {
102
+ response.recommendations.forEach(prepareContextResource);
103
+ }
104
+
105
+ if (response.meta && response.meta.pagination) {
106
+ response.pagination = response.meta.pagination;
107
+ }
108
+
109
+ return templates.execute('recommendations', response, {data});
110
+ } catch (error) {
111
+ logging.error(error);
112
+ return null;
113
+ }
114
+ };
115
+
116
+ module.exports.async = true;
@@ -0,0 +1,15 @@
1
+ {{#if recommendations}}
2
+ <ul class="recommendations">
3
+ {{#each recommendations as |rec|}}
4
+ <li class="recommendation">
5
+ <a href="{{rec.url}}">
6
+ <img class="recommendation-favicon" src="{{rec.favicon}}" alt="{{rec.title}}">
7
+ <div class="recommendation-content">
8
+ <h5 class="recommendation-title">{{rec.title}}</h5>
9
+ <p class="recommendation-reason">{{rec.reason}}</p>
10
+ </div>
11
+ </a>
12
+ </li>
13
+ {{/each}}
14
+ </ul>
15
+ {{/if}}
@@ -274,21 +274,21 @@ SchedulingDefault.prototype._pingUrl = function (object) {
274
274
  const maxTries = 30;
275
275
 
276
276
  const options = {
277
- timeout: requestTimeout,
278
- method: httpMethod.toLowerCase(),
279
- retry: 0,
280
- headers: {
281
- 'Content-Type': 'application/json'
277
+ timeout: {
278
+ request: requestTimeout
279
+ },
280
+ method: httpMethod,
281
+ retry: {
282
+ limit: 0
282
283
  }
283
284
  };
284
285
 
285
286
  // CASE: If we detect to publish a post in the past (case blog is down), we add a force flag
286
287
  if (moment(time).isBefore(moment())) {
287
288
  if (httpMethod === 'GET') {
288
- // @TODO: rename to searchParams when updating to Got v10
289
- options.query = 'force=true';
289
+ options.searchParams = {force: true};
290
290
  } else {
291
- options.body = JSON.stringify({force: true});
291
+ options.json = {force: true};
292
292
  }
293
293
  }
294
294
 
@@ -10,7 +10,8 @@ module.exports = {
10
10
  options: [
11
11
  'limit',
12
12
  'order',
13
- 'page'
13
+ 'page',
14
+ 'filter'
14
15
  ],
15
16
  permissions: true,
16
17
  validation: {},
@@ -36,6 +36,7 @@ const author = (attrs, frame) => {
36
36
  delete attrs.paid_subscription_started_notification;
37
37
  delete attrs.paid_subscription_canceled_notification;
38
38
  delete attrs.mention_notifications;
39
+ delete attrs.recommendation_notifications;
39
40
  delete attrs.milestone_notifications;
40
41
  delete attrs.donation_notifications;
41
42
 
@@ -0,0 +1,7 @@
1
+ const {createAddColumnMigration} = require('../../utils');
2
+
3
+ module.exports = createAddColumnMigration('users', 'recommendation_notifications', {
4
+ type: 'boolean',
5
+ nullable: false,
6
+ defaultTo: true
7
+ });
@@ -163,6 +163,7 @@ module.exports = {
163
163
  paid_subscription_started_notification: {type: 'boolean', nullable: false, defaultTo: true},
164
164
  paid_subscription_canceled_notification: {type: 'boolean', nullable: false, defaultTo: false},
165
165
  mention_notifications: {type: 'boolean', nullable: false, defaultTo: true},
166
+ recommendation_notifications: {type: 'boolean', nullable: false, defaultTo: true},
166
167
  milestone_notifications: {type: 'boolean', nullable: false, defaultTo: true},
167
168
  donation_notifications: {type: 'boolean', nullable: false, defaultTo: true},
168
169
  created_at: {type: 'dateTime', nullable: false},
@@ -33,7 +33,7 @@ class Gravatar {
33
33
  const testUrl = this.url(userData.email, {default: 404, rating: 'x'});
34
34
  const imageUrl = this.url(userData.email, {default: 'mp', rating: 'x'});
35
35
 
36
- return Promise.resolve(this.request(testUrl, {timeout: timeout || 2 * 1000}))
36
+ return Promise.resolve(this.request(testUrl, {timeout: {request: timeout || 2 * 1000}}))
37
37
  .then(function () {
38
38
  return {
39
39
  image: imageUrl
@@ -30,9 +30,13 @@ class ImageSize {
30
30
  headers: {
31
31
  'User-Agent': 'Mozilla/5.0 Safari/537.36'
32
32
  },
33
- timeout: this.config.get('times:getImageSizeTimeoutInMS') || 10000,
34
- retry: 0, // for `got`, used with image-size
35
- encoding: null
33
+ timeout: {
34
+ request: this.config.get('times:getImageSizeTimeoutInMS') || 10000
35
+ },
36
+ retry: {
37
+ limit: 0 // for `got`, used with image-size
38
+ },
39
+ responseType: 'buffer'
36
40
  };
37
41
 
38
42
  this.NEEDLE_OPTIONS = {
@@ -18,6 +18,11 @@ function isPrivateIp(addr) {
18
18
  }
19
19
 
20
20
  async function errorIfHostnameResolvesToPrivateIp(options) {
21
+ // Allow all requests if we are in development mode
22
+ if (config.get('env') === 'development') {
23
+ return Promise.resolve();
24
+ }
25
+
21
26
  // allow requests through to local Ghost instance
22
27
  const siteUrl = new URL(config.get('url'));
23
28
  const requestUrl = new URL(options.url.href);
@@ -37,6 +42,10 @@ async function errorIfHostnameResolvesToPrivateIp(options) {
37
42
  }
38
43
 
39
44
  async function errorIfInvalidUrl(options) {
45
+ if (config.get('env') === 'development') {
46
+ return Promise.resolve();
47
+ }
48
+
40
49
  if (!options.url.hostname || !validator.isURL(options.url.hostname)) {
41
50
  throw new errors.InternalServerError({
42
51
  message: 'URL invalid.',
@@ -1367,6 +1367,24 @@ Post = ghostBookshelf.Model.extend({
1367
1367
  return editPost();
1368
1368
  },
1369
1369
 
1370
+ bulkEdit: async function bulkEdit(ids, tableName, options) {
1371
+ if (tableName === this.prototype.tableName) {
1372
+ const result = await ghostBookshelf.Model.bulkEdit.call(this, ids, tableName, options);
1373
+
1374
+ if (labs.isSet('collectionsCard')) {
1375
+ // reset all page HTML so collection cards can be re-rendered with updated posts
1376
+ // NOTE: we can't check for only published edits here as we don't have access to previous values
1377
+ // to see if a previously published post has been unpublished, so we just reset all pages
1378
+ const pageResetQuery = ghostBookshelf.knex.raw('UPDATE posts set html = NULL WHERE type = "page" AND lexical IS NOT NULL');
1379
+ await (options.transacting ? pageResetQuery.transacting(options.transacting) : pageResetQuery);
1380
+ }
1381
+
1382
+ return result;
1383
+ } else {
1384
+ return ghostBookshelf.Model.bulkEdit.call(this, ids, tableName, options);
1385
+ }
1386
+ },
1387
+
1370
1388
  /**
1371
1389
  * ### Add
1372
1390
  * @extends ghostBookshelf.Model.add to handle returning the full object
@@ -1413,6 +1431,34 @@ Post = ghostBookshelf.Model.extend({
1413
1431
  return destroyPost();
1414
1432
  },
1415
1433
 
1434
+ bulkDestroy: async function bulkDestroy(ids, tableName, options) {
1435
+ if (tableName === this.prototype.tableName) {
1436
+ if (labs.isSet('collectionsCard')) {
1437
+ // get count of published posts to be destroyed before they no longer exist to count
1438
+ const deletedPublishedCount = await this.query((qb) => {
1439
+ qb.where('type', 'post')
1440
+ .where('status', 'published')
1441
+ .whereIn('id', ids);
1442
+ }).count({transacting: options.transacting});
1443
+
1444
+ const result = await ghostBookshelf.Model.bulkDestroy.call(this, ids, tableName, options);
1445
+
1446
+ // if we've deleted any published posts, we need to reset the html for all pages so dynamic collection
1447
+ // card content can be re-rendered
1448
+ if (deletedPublishedCount > 0) {
1449
+ const pageResetQuery = ghostBookshelf.knex.raw('UPDATE posts set html = NULL WHERE type = "page" AND lexical IS NOT NULL');
1450
+ await (options.transacting ? pageResetQuery.transacting(options.transacting) : pageResetQuery);
1451
+ }
1452
+
1453
+ return result;
1454
+ } else {
1455
+ return ghostBookshelf.Model.bulkDestroy.call(this, ids, tableName, options);
1456
+ }
1457
+ } else {
1458
+ return ghostBookshelf.Model.bulkDestroy.call(this, ids, tableName, options);
1459
+ }
1460
+ },
1461
+
1416
1462
  // NOTE: the `authors` extension is the parent of the post model. It also has a permissible function.
1417
1463
  permissible: async function permissible(postModel, action, context, unsafeAttrs, loadedPermissions, hasUserPermission, hasApiKeyPermission) {
1418
1464
  let isContributor;
@@ -69,6 +69,7 @@ User = ghostBookshelf.Model.extend({
69
69
  paid_subscription_started_notification: true,
70
70
  paid_subscription_canceled_notification: false,
71
71
  mention_notifications: true,
72
+ recommendation_notifications: true,
72
73
  milestone_notifications: true,
73
74
  donation_notifications: true
74
75
  };
@@ -512,6 +513,8 @@ User = ghostBookshelf.Model.extend({
512
513
  filter += '+milestone_notifications:true';
513
514
  } else if (type === 'donation') {
514
515
  filter += '+donation_notifications:true';
516
+ } else if (type === 'recommendation-received') {
517
+ filter += '+recommendation_notifications:true';
515
518
  }
516
519
  const updatedOptions = _.merge({}, options, {filter, withRelated: ['roles']});
517
520
  return this.findAll(updatedOptions).then((users) => {
@@ -4,8 +4,13 @@ class PostsRepository {
4
4
  this.moment = moment;
5
5
  }
6
6
 
7
- async getAllIds() {
8
- const rows = await this.models.Post.query().select('id').where('type', 'post');
7
+ /**
8
+ * @param {Object} options
9
+ * @returns Promise<string[]>
10
+ */
11
+ async getAllIds({transaction} = {}) {
12
+ const query = this.models.Post.query().select('id').where('type', 'post');
13
+ const rows = transaction ? await query.transacting(transaction) : await query;
9
14
 
10
15
  return rows.map(row => row.id);
11
16
  }
@@ -15,7 +15,7 @@ class CommentsServiceEmails {
15
15
  this.urlService = urlService;
16
16
  this.urlUtils = urlUtils;
17
17
 
18
- this.Handlebars = require('handlebars');
18
+ this.Handlebars = require('handlebars').create();
19
19
  }
20
20
 
21
21
  async notifyPostAuthors(comment) {
@@ -57,7 +57,8 @@ module.exports = class BookshelfMentionRepository {
57
57
  sourceExcerpt: model.get('source_excerpt'),
58
58
  sourceFavicon: model.get('source_favicon'),
59
59
  sourceFeaturedImage: model.get('source_featured_image'),
60
- verified: model.get('verified')
60
+ verified: model.get('verified'),
61
+ deleted: model.get('deleted')
61
62
  });
62
63
  }
63
64
 
@@ -27,6 +27,8 @@ function getPostUrl(post) {
27
27
  module.exports = {
28
28
  /** @type {import('@tryghost/webmentions/lib/MentionsAPI')} */
29
29
  api: null,
30
+ /** @type {import('./BookshelfMentionRepository')} */
31
+ repository: null,
30
32
  controller: new MentionController(),
31
33
  metadata: new WebmentionMetadata(),
32
34
  /** @type {import('@tryghost/webmentions/lib/MentionSendingService')} */
@@ -41,6 +43,8 @@ module.exports = {
41
43
  MentionModel: models.Mention,
42
44
  DomainEvents
43
45
  });
46
+ this.repository = repository;
47
+
44
48
  const webmentionMetadata = this.metadata;
45
49
  const discoveryService = new MentionDiscoveryService({externalRequest});
46
50
  const resourceService = new ResourceService({
@@ -14,7 +14,7 @@ module.exports = class RecommendationEnablerService {
14
14
  * @returns {string}
15
15
  */
16
16
  getSetting() {
17
- this.#settingsService.read('recommendations_enabled');
17
+ return this.#settingsService.read('recommendations_enabled');
18
18
  }
19
19
 
20
20
  /**