Przeglądaj źródła

Add daily limit for shortening URLs

Pouria Ezzati 7 lat temu
rodzic
commit
1fc793dc92
3 zmienionych plików z 44 dodań i 3 usunięć
  1. 3 0
      server/config.example.js
  2. 19 3
      server/controllers/urlController.js
  3. 22 0
      server/db/url.js

+ 3 - 0
server/config.example.js

@@ -9,6 +9,9 @@ module.exports = {
   DB_USERNAME: '',
   DB_PASSWORD: '',
 
+  /* The daily limit for each user */
+  USER_LIMIT_PER_DAY: 50,
+
   /* A passphrase to encrypt JWT. Use a long and secure key. */
   JWT_SECRET: 'securekey',
 

+ 19 - 3
server/controllers/urlController.js

@@ -4,17 +4,20 @@ const generate = require('nanoid/generate');
 const useragent = require('useragent');
 const geoip = require('geoip-lite');
 const bcrypt = require('bcryptjs');
+const subDay = require('date-fns/sub_days');
 const {
   createShortUrl,
   createVisit,
+  deleteCustomDomain,
+  deleteUrl,
   findUrl,
+  getCustomDomain,
   getStats,
   getUrls,
-  getCustomDomain,
   setCustomDomain,
-  deleteCustomDomain,
-  deleteUrl,
+  urlCountFromDate,
 } = require('../db/url');
+
 const { addProtocol, generateShortUrl } = require('../utils');
 const config = require('../config');
 
@@ -26,6 +29,19 @@ const generateId = async () => {
 };
 
 exports.urlShortener = async ({ body, user }, res) => {
+  // Check if user has passed daily limit
+  if (user) {
+    const { count } = await urlCountFromDate({
+      email: user.email,
+      date: subDay(new Date(), 365).toJSON(),
+    });
+    if (count > config.USER_LIMIT_PER_DAY) {
+      return res.status(429).json({
+        error: `You have reached your daily limit (${config.USER_LIMIT_PER_DAY}). Please wait 24h.`,
+      });
+    }
+  }
+
   // if "reuse" is true, try to return
   // the existent URL without creating one
   if (user && body.reuse) {

+ 22 - 0
server/db/url.js

@@ -393,3 +393,25 @@ exports.getStats = ({ id, domain, user }) =>
       })
       .catch(() => session.close() && reject);
   });
+
+exports.urlCountFromDate = ({ date, email }) =>
+  new Promise((resolve, reject) => {
+    const session = driver.session();
+    session
+      .readTransaction(tx =>
+        tx.run(
+          'MATCH (u:USER { email: $email })-[:CREATED]->(l) WHERE l.createdAt > $date ' +
+            'RETURN COUNT(l) as count',
+          {
+            date,
+            email,
+          }
+        )
+      )
+      .then(({ records }) => {
+        session.close();
+        const count = records.length && records[0].get('count').toNumber();
+        return resolve({ count });
+      })
+      .catch(err => reject(err));
+  });