From b866089c64b0ab50f95523bd30d3e77c593baea0 Mon Sep 17 00:00:00 2001
From: chris48s <chris48s@users.noreply.github.com>
Date: Fri, 26 Oct 2018 20:08:02 +0100
Subject: [PATCH] allow badge maxAge to be set by category; affects [discord]
 (#2205)

* allow badge maxAge to be set by category
* override default cache length for [discord]
* update maxAge docs
---
 frontend/components/usage.js        |  5 +++--
 lib/request-handler.js              | 29 +++++++++++++++++++++--------
 lib/request-handler.spec.js         | 12 ++++++++++++
 services/base.js                    | 10 ++++++++++
 services/discord/discord.service.js |  4 ++++
 5 files changed, 50 insertions(+), 10 deletions(-)

diff --git a/frontend/components/usage.js b/frontend/components/usage.js
index 923ce7eced..a94cc4560c 100644
--- a/frontend/components/usage.js
+++ b/frontend/components/usage.js
@@ -269,8 +269,9 @@ export default class Usage extends React.PureComponent {
                 <code>?maxAge=3600</code>
               </td>
               <td>
-                Set the HTTP cache lifetime in secs (values below the default
-                (currently 120 seconds) will be ignored)
+                Set the HTTP cache lifetime in secs (rules are applied to infer
+                a default value on a per-badge basis, any values specified below
+                the default will be ignored)
               </td>
             </tr>
           </tbody>
diff --git a/lib/request-handler.js b/lib/request-handler.js
index 48d99ed5c9..aa93684ecd 100644
--- a/lib/request-handler.js
+++ b/lib/request-handler.js
@@ -56,10 +56,29 @@ function flattenQueryParams(queryParams) {
   return Array.from(union).sort()
 }
 
+function getBadgeMaxAge(handlerOptions, queryParams) {
+  let maxAge = isInt(process.env.BADGE_MAX_AGE_SECONDS)
+    ? parseInt(process.env.BADGE_MAX_AGE_SECONDS)
+    : 120
+  if (handlerOptions.cacheLength) {
+    // if we've set a more specific cache length for this badge (or category),
+    // use that instead of env.BADGE_MAX_AGE_SECONDS
+    maxAge = parseInt(handlerOptions.cacheLength)
+  }
+  if (isInt(queryParams.maxAge) && parseInt(queryParams.maxAge) > maxAge) {
+    // only allow queryParams.maxAge to override the default
+    // if it is greater than the default
+    maxAge = parseInt(queryParams.maxAge)
+  }
+  return maxAge
+}
+
 // handlerOptions can contain:
 // - handler: The service's request handler function
 // - queryParams: An array of the field names of any custom query parameters
 //   the service uses
+// - cacheLength: An optional badge or category-specific cache length
+//   (in number of seconds) to be used in preference to the default
 //
 // For safety, the service must declare the query parameters it wants to use.
 // Only the declared parameters (and the global parameters) are provided to
@@ -81,14 +100,7 @@ function handleRequest(makeBadge, handlerOptions) {
   return (queryParams, match, end, ask) => {
     const reqTime = new Date()
 
-    let maxAge = isInt(process.env.BADGE_MAX_AGE_SECONDS)
-      ? parseInt(process.env.BADGE_MAX_AGE_SECONDS)
-      : 120
-    if (isInt(queryParams.maxAge) && parseInt(queryParams.maxAge) > maxAge) {
-      // only queryParams.maxAge to override the default
-      // if it is greater than env.BADGE_MAX_AGE_SECONDS
-      maxAge = parseInt(queryParams.maxAge)
-    }
+    const maxAge = getBadgeMaxAge(handlerOptions, queryParams)
     // send both Cache-Control max-age and Expires
     // in case the client implements HTTP/1.0 but not HTTP/1.1
     if (maxAge === 0) {
@@ -269,4 +281,5 @@ module.exports = {
   clearRequestCache,
   // Expose for testing.
   _requestCache: requestCache,
+  getBadgeMaxAge,
 }
diff --git a/lib/request-handler.spec.js b/lib/request-handler.spec.js
index d3fc1b4f12..1adba41078 100644
--- a/lib/request-handler.spec.js
+++ b/lib/request-handler.spec.js
@@ -1,6 +1,7 @@
 'use strict'
 
 const { expect } = require('chai')
+const { test, given } = require('sazerac')
 const fetch = require('node-fetch')
 const config = require('./test-config')
 const Camp = require('camp')
@@ -10,6 +11,7 @@ const {
   makeHandleRequestFn,
   clearRequestCache,
   _requestCache,
+  getBadgeMaxAge,
 } = require('./request-handler')
 const testHelpers = require('./make-badge-test-helpers')
 
@@ -206,4 +208,14 @@ describe('The request handler', function() {
       })
     })
   })
+
+  describe('getBadgeMaxAge function', function() {
+    process.env.BADGE_MAX_AGE_SECONDS = 120
+    test(getBadgeMaxAge, () => {
+      given({}, {}).expect(120)
+      given({ cacheLength: 900 }, {}).expect(900)
+      given({ cacheLength: 900 }, { maxAge: 1000 }).expect(1000)
+      given({ cacheLength: 900 }, { maxAge: 400 }).expect(900)
+    })
+  })
 })
diff --git a/services/base.js b/services/base.js
index ce9a684ff4..2cf802dd3a 100644
--- a/services/base.js
+++ b/services/base.js
@@ -165,6 +165,15 @@ class BaseService {
     return new RegExp(fullRegex)
   }
 
+  static get _cacheLength() {
+    const cacheLengths = {
+      build: 30,
+      license: 3600,
+      version: 300,
+    }
+    return cacheLengths[this.category]
+  }
+
   static _namedParamsForMatch(match) {
     const names = this.url.capture || []
 
@@ -315,6 +324,7 @@ class BaseService {
           const format = match.slice(-1)[0]
           sendBadge(format, badgeData)
         },
+        cacheLength: this._cacheLength,
       })
     )
   }
diff --git a/services/discord/discord.service.js b/services/discord/discord.service.js
index 414820d86f..6b2bae01d8 100644
--- a/services/discord/discord.service.js
+++ b/services/discord/discord.service.js
@@ -22,6 +22,10 @@ module.exports = class Discord extends BaseJsonService {
     })
   }
 
+  static get _cacheLength() {
+    return 30
+  }
+
   static render({ members }) {
     return {
       message: `${members} online`,
-- 
GitLab