Răsfoiți Sursa

Merge pull request #18 from overleaf/spd-decaf

Decaffeinate contacts
Simon Detheridge 6 ani în urmă
părinte
comite
bc80402eda
31 a modificat fișierele cu 1488 adăugiri și 576 ștergeri
  1. 0 2
      services/contacts/.dockerignore
  2. 65 0
      services/contacts/.eslintrc
  3. 0 5
      services/contacts/.gitignore
  4. 8 0
      services/contacts/.prettierrc
  5. 0 1
      services/contacts/Dockerfile
  6. 7 0
      services/contacts/Jenkinsfile
  7. 10 5
      services/contacts/Makefile
  8. 0 45
      services/contacts/app.coffee
  9. 59 0
      services/contacts/app.js
  10. 0 38
      services/contacts/app/coffee/ContactManager.coffee
  11. 0 10
      services/contacts/app/coffee/Errors.coffee
  12. 0 66
      services/contacts/app/coffee/HttpController.coffee
  13. 0 7
      services/contacts/app/coffee/mongojs.coffee
  14. 77 0
      services/contacts/app/js/ContactManager.js
  15. 16 0
      services/contacts/app/js/Errors.js
  16. 100 0
      services/contacts/app/js/HttpController.js
  17. 9 0
      services/contacts/app/js/mongojs.js
  18. 5 5
      services/contacts/buildscript.txt
  19. 0 11
      services/contacts/config/settings.defaults.coffee
  20. 17 0
      services/contacts/config/settings.defaults.js
  21. 3 4
      services/contacts/nodemon.json
  22. 628 67
      services/contacts/package-lock.json
  23. 28 13
      services/contacts/package.json
  24. 0 20
      services/contacts/test/acceptance/coffee/ContactsApp.coffee
  25. 0 71
      services/contacts/test/acceptance/coffee/GettingContactsTests.coffee
  26. 47 0
      services/contacts/test/acceptance/js/ContactsApp.js
  27. 116 0
      services/contacts/test/acceptance/js/GettingContactsTests.js
  28. 0 86
      services/contacts/test/unit/coffee/ContactsManagerTests.coffee
  29. 0 120
      services/contacts/test/unit/coffee/HttpControllerTests.coffee
  30. 143 0
      services/contacts/test/unit/js/ContactsManagerTests.js
  31. 150 0
      services/contacts/test/unit/js/HttpControllerTests.js

+ 0 - 2
services/contacts/.dockerignore

@@ -5,5 +5,3 @@ gitrev
 .npm
 .nvmrc
 nodemon.json
-app.js
-**/js/*

+ 65 - 0
services/contacts/.eslintrc

@@ -0,0 +1,65 @@
+// this file was auto-generated, do not edit it directly.
+// instead run bin/update_build_scripts from
+// https://github.com/sharelatex/sharelatex-dev-environment
+// Version: 1.3.5
+{
+  "extends": [
+    "standard",
+    "prettier",
+    "prettier/standard"
+  ],
+  "parserOptions": {
+    "ecmaVersion": 2017
+  },
+  "plugins": [
+    "mocha",
+    "chai-expect",
+    "chai-friendly"
+  ],
+  "env": {
+    "node": true,
+    "mocha": true
+  },
+  "rules": {
+    // Swap the no-unused-expressions rule with a more chai-friendly one
+    "no-unused-expressions": 0,
+    "chai-friendly/no-unused-expressions": "error"
+  },
+  "overrides": [
+    {
+      // Test specific rules
+      "files": ["test/**/*.js"],
+      "globals": {
+        "expect": true
+      },
+      "rules": {
+        // mocha-specific rules
+        "mocha/handle-done-callback": "error",
+        "mocha/no-exclusive-tests": "error",
+        "mocha/no-global-tests": "error",
+        "mocha/no-identical-title": "error",
+        "mocha/no-nested-tests": "error",
+        "mocha/no-pending-tests": "error",
+        "mocha/no-skipped-tests": "error",
+        "mocha/no-mocha-arrows": "error",
+
+        // chai-specific rules
+        "chai-expect/missing-assertion": "error",
+        "chai-expect/terminating-properties": "error",
+
+        // prefer-arrow-callback applies to all callbacks, not just ones in mocha tests.
+        // we don't enforce this at the top-level - just in tests to manage `this` scope
+        // based on mocha's context mechanism
+        "mocha/prefer-arrow-callback": "error"
+      }
+    },
+    {
+      // Backend specific rules
+      "files": ["app/**/*.js", "app.js", "index.js"],
+      "rules": {
+        // don't allow console.log in backend code
+        "no-console": "error"
+      }
+    }
+  ]
+}

+ 0 - 5
services/contacts/.gitignore

@@ -1,7 +1,2 @@
 node_modules
-app/js/
-test/unit/js
-test/acceptance/js
-app.js
-**/*.map
 forever

+ 8 - 0
services/contacts/.prettierrc

@@ -0,0 +1,8 @@
+# This file was auto-generated, do not edit it directly.
+# Instead run bin/update_build_scripts from
+# https://github.com/sharelatex/sharelatex-dev-environment
+# Version: 1.3.5
+{
+  "semi": false,
+  "singleQuote": true
+}

+ 0 - 1
services/contacts/Dockerfile

@@ -17,7 +17,6 @@ RUN npm install --quiet
 COPY . /app
 
 
-RUN npm run compile:all
 
 FROM base
 

+ 7 - 0
services/contacts/Jenkinsfile

@@ -37,6 +37,13 @@ pipeline {
       }
     }
 
+    stage('Linting') {
+      steps {
+        sh 'DOCKER_COMPOSE_FLAGS="-f docker-compose.ci.yml" make format'
+        sh 'DOCKER_COMPOSE_FLAGS="-f docker-compose.ci.yml" make lint'
+      }
+    }
+
     stage('Unit Tests') {
       steps {
         sh 'DOCKER_COMPOSE_FLAGS="-f docker-compose.ci.yml" make test_unit'

+ 10 - 5
services/contacts/Makefile

@@ -16,12 +16,17 @@ DOCKER_COMPOSE := BUILD_NUMBER=$(BUILD_NUMBER) \
 clean:
 	docker rmi ci/$(PROJECT_NAME):$(BRANCH_NAME)-$(BUILD_NUMBER)
 	docker rmi gcr.io/overleaf-ops/$(PROJECT_NAME):$(BRANCH_NAME)-$(BUILD_NUMBER)
-	rm -f app.js
-	rm -rf app/js
-	rm -rf test/unit/js
-	rm -rf test/acceptance/js
 
-test: test_unit test_acceptance
+format:
+	$(DOCKER_COMPOSE) run --rm test_unit npm run format
+
+format_fix:
+	$(DOCKER_COMPOSE) run --rm test_unit npm run format:fix
+
+lint:
+	$(DOCKER_COMPOSE) run --rm test_unit npm run lint
+
+test: format lint test_unit test_acceptance
 
 test_unit:
 	@[ ! -d test/unit ] && echo "contacts has no unit tests" || $(DOCKER_COMPOSE) run --rm test_unit

+ 0 - 45
services/contacts/app.coffee

@@ -1,45 +0,0 @@
-Metrics    = require "metrics-sharelatex"
-Metrics.initialize("contacts")
-
-Settings   = require "settings-sharelatex"
-logger     = require "logger-sharelatex"
-express    = require "express"
-bodyParser = require "body-parser"
-Errors     = require "./app/js/Errors"
-HttpController = require "./app/js/HttpController"
-
-Path       = require "path"
-
-
-logger.initialize("contacts")
-Metrics.event_loop?.monitor(logger)
-
-app = express()
-
-app.use Metrics.http.monitor(logger)
-
-Metrics.injectMetricsRoute(app)
-
-app.get  '/user/:user_id/contacts', HttpController.getContacts
-app.post '/user/:user_id/contacts', bodyParser.json(limit: "2mb"), HttpController.addContact
-
-app.get '/status', (req, res)->
-	res.send('contacts is alive')
-
-app.use (error, req, res, next) ->
-	logger.error err: error, "request errored"
-	if error instanceof Errors.NotFoundError
-		res.send 404
-	else
-		res.send(500, "Oops, something went wrong")
-
-port = Settings.internal.contacts.port
-host = Settings.internal.contacts.host
-
-
-if !module.parent # Called directly
-	app.listen port, host, (error) ->
-		throw error if error?
-		logger.info "contacts starting up, listening on #{host}:#{port}"
-
-module.exports = app

+ 59 - 0
services/contacts/app.js

@@ -0,0 +1,59 @@
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * DS207: Consider shorter variations of null checks
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const Metrics = require('metrics-sharelatex')
+Metrics.initialize('contacts')
+
+const Settings = require('settings-sharelatex')
+const logger = require('logger-sharelatex')
+const express = require('express')
+const bodyParser = require('body-parser')
+const Errors = require('./app/js/Errors')
+const HttpController = require('./app/js/HttpController')
+
+logger.initialize('contacts')
+if (Metrics.event_loop != null) {
+  Metrics.event_loop.monitor(logger)
+}
+
+const app = express()
+
+app.use(Metrics.http.monitor(logger))
+
+Metrics.injectMetricsRoute(app)
+
+app.get('/user/:user_id/contacts', HttpController.getContacts)
+app.post(
+  '/user/:user_id/contacts',
+  bodyParser.json({ limit: '2mb' }),
+  HttpController.addContact
+)
+
+app.get('/status', (req, res) => res.send('contacts is alive'))
+
+app.use(function(error, req, res, next) {
+  logger.error({ err: error }, 'request errored')
+  if (error instanceof Errors.NotFoundError) {
+    return res.send(404)
+  } else {
+    return res.send(500, 'Oops, something went wrong')
+  }
+})
+
+const { port } = Settings.internal.contacts
+const { host } = Settings.internal.contacts
+
+if (!module.parent) {
+  // Called directly
+  app.listen(port, host, function(error) {
+    if (error != null) {
+      throw error
+    }
+    return logger.info(`contacts starting up, listening on ${host}:${port}`)
+  })
+}
+
+module.exports = app

+ 0 - 38
services/contacts/app/coffee/ContactManager.coffee

@@ -1,38 +0,0 @@
-{db, ObjectId} = require "./mongojs"
-logger = require('logger-sharelatex')
-metrics = require('metrics-sharelatex')
-
-module.exports = ContactManager =
-	touchContact: (user_id, contact_id, callback = (error) ->) ->
-		try
-			user_id = ObjectId(user_id.toString())
-		catch error
-			return callback error
-
-		update = { $set: {}, $inc: {} }
-		update.$inc["contacts.#{contact_id}.n"] = 1
-		update.$set["contacts.#{contact_id}.ts"] = new Date()
-
-		db.contacts.update({
-			user_id: user_id
-		}, update, {
-			upsert: true
-		}, callback)
-	
-	getContacts: (user_id, callback = (error) ->) ->
-		try
-			user_id = ObjectId(user_id.toString())
-		catch error
-			return callback error
-		
-		db.contacts.findOne {
-			user_id: user_id
-		}, (error, user) ->
-			return callback(error) if error?
-			callback null, user?.contacts
-
-[
-	'touchContact',
-	'getContacts',
-].map (method) ->
-	metrics.timeAsyncMethod(ContactManager, method, 'mongo.ContactManager', logger)

+ 0 - 10
services/contacts/app/coffee/Errors.coffee

@@ -1,10 +0,0 @@
-NotFoundError = (message) ->
-	error = new Error(message)
-	error.name = "NotFoundError"
-	error.__proto__ = NotFoundError.prototype
-	return error
-NotFoundError.prototype.__proto__ = Error.prototype
-
-module.exports = Errors =
-	NotFoundError: NotFoundError
-

+ 0 - 66
services/contacts/app/coffee/HttpController.coffee

@@ -1,66 +0,0 @@
-ContactManager = require "./ContactManager"
-logger = require "logger-sharelatex"
-
-module.exports = HttpController =
-	addContact: (req, res, next) ->
-		{user_id} = req.params
-		{contact_id} = req.body
-		
-		if !contact_id? or contact_id == ""
-			res.status(400).send("contact_id should be a non-blank string")
-			return
-			
-		logger.log {user_id, contact_id}, "adding contact"
-
-		ContactManager.touchContact user_id, contact_id, (error) ->
-			return next(error) if error?
-			ContactManager.touchContact contact_id, user_id, (error) ->
-				return next(error) if error?
-				res.status(204).end()
-
-	CONTACT_LIMIT: 50
-	getContacts: (req, res, next) ->
-		{user_id} = req.params
-
-		if req.query?.limit?
-			limit = parseInt(req.query.limit, 10)
-		else
-			limit = HttpController.CONTACT_LIMIT
-		limit = Math.min(limit, HttpController.CONTACT_LIMIT)
-
-		logger.log {user_id}, "getting contacts"
-
-		ContactManager.getContacts user_id, (error, contact_dict) ->
-			return next(error) if error?
-			
-			contacts = []
-			for user_id, data of (contact_dict or {})
-				contacts.push {
-					user_id: user_id
-					n: data.n
-					ts: data.ts
-				}
-
-			HttpController._sortContacts contacts
-			contacts = contacts.slice(0, limit)
-			contact_ids = contacts.map (contact) -> contact.user_id
-
-			res.status(200).send({
-				contact_ids: contact_ids
-			})
-	
-	_sortContacts: (contacts) ->
-		contacts.sort (a, b) ->
-			# Sort by decreasing count, descreasing timestamp.
-			# I.e. biggest count, and most recent at front.
-			if a.n > b.n
-				return -1
-			else if a.n < b.n
-				return 1
-			else
-				if a.ts > b.ts
-					return -1
-				else if a.ts < b.ts
-					return 1
-				else
-					return 0

+ 0 - 7
services/contacts/app/coffee/mongojs.coffee

@@ -1,7 +0,0 @@
-Settings = require "settings-sharelatex"
-mongojs = require "mongojs"
-db = mongojs(Settings.mongo.url, ["contacts"])
-module.exports =
-	db: db
-	ObjectId: mongojs.ObjectId
-

+ 77 - 0
services/contacts/app/js/ContactManager.js

@@ -0,0 +1,77 @@
+/* eslint-disable
+    camelcase,
+    handle-callback-err,
+*/
+// TODO: This file was created by bulk-decaffeinate.
+// Fix any style issues and re-enable lint.
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * DS207: Consider shorter variations of null checks
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+let ContactManager
+const { db, ObjectId } = require('./mongojs')
+const logger = require('logger-sharelatex')
+const metrics = require('metrics-sharelatex')
+
+module.exports = ContactManager = {
+  touchContact(user_id, contact_id, callback) {
+    if (callback == null) {
+      callback = function(error) {}
+    }
+    try {
+      user_id = ObjectId(user_id.toString())
+    } catch (error1) {
+      const error = error1
+      return callback(error)
+    }
+
+    const update = { $set: {}, $inc: {} }
+    update.$inc[`contacts.${contact_id}.n`] = 1
+    update.$set[`contacts.${contact_id}.ts`] = new Date()
+
+    return db.contacts.update(
+      {
+        user_id
+      },
+      update,
+      {
+        upsert: true
+      },
+      callback
+    )
+  },
+
+  getContacts(user_id, callback) {
+    if (callback == null) {
+      callback = function(error) {}
+    }
+    try {
+      user_id = ObjectId(user_id.toString())
+    } catch (error1) {
+      const error = error1
+      return callback(error)
+    }
+
+    return db.contacts.findOne(
+      {
+        user_id
+      },
+      function(error, user) {
+        if (error != null) {
+          return callback(error)
+        }
+        return callback(null, user != null ? user.contacts : undefined)
+      }
+    )
+  }
+}
+;['touchContact', 'getContacts'].map(method =>
+  metrics.timeAsyncMethod(
+    ContactManager,
+    method,
+    'mongo.ContactManager',
+    logger
+  )
+)

+ 16 - 0
services/contacts/app/js/Errors.js

@@ -0,0 +1,16 @@
+/* eslint-disable
+    no-proto,
+    no-unused-vars,
+*/
+// TODO: This file was created by bulk-decaffeinate.
+// Fix any style issues and re-enable lint.
+let Errors
+var NotFoundError = function(message) {
+  const error = new Error(message)
+  error.name = 'NotFoundError'
+  error.__proto__ = NotFoundError.prototype
+  return error
+}
+NotFoundError.prototype.__proto__ = Error.prototype
+
+module.exports = Errors = { NotFoundError }

+ 100 - 0
services/contacts/app/js/HttpController.js

@@ -0,0 +1,100 @@
+/* eslint-disable
+    camelcase,
+*/
+// TODO: This file was created by bulk-decaffeinate.
+// Fix any style issues and re-enable lint.
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * DS207: Consider shorter variations of null checks
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+let HttpController
+const ContactManager = require('./ContactManager')
+const logger = require('logger-sharelatex')
+
+module.exports = HttpController = {
+  addContact(req, res, next) {
+    const { user_id } = req.params
+    const { contact_id } = req.body
+
+    if (contact_id == null || contact_id === '') {
+      res.status(400).send('contact_id should be a non-blank string')
+      return
+    }
+
+    logger.log({ user_id, contact_id }, 'adding contact')
+
+    return ContactManager.touchContact(user_id, contact_id, function(error) {
+      if (error != null) {
+        return next(error)
+      }
+      return ContactManager.touchContact(contact_id, user_id, function(error) {
+        if (error != null) {
+          return next(error)
+        }
+        return res.status(204).end()
+      })
+    })
+  },
+
+  CONTACT_LIMIT: 50,
+  getContacts(req, res, next) {
+    let limit
+    let { user_id } = req.params
+
+    if ((req.query != null ? req.query.limit : undefined) != null) {
+      limit = parseInt(req.query.limit, 10)
+    } else {
+      limit = HttpController.CONTACT_LIMIT
+    }
+    limit = Math.min(limit, HttpController.CONTACT_LIMIT)
+
+    logger.log({ user_id }, 'getting contacts')
+
+    return ContactManager.getContacts(user_id, function(error, contact_dict) {
+      if (error != null) {
+        return next(error)
+      }
+
+      let contacts = []
+      const object = contact_dict || {}
+      for (user_id in object) {
+        const data = object[user_id]
+        contacts.push({
+          user_id,
+          n: data.n,
+          ts: data.ts
+        })
+      }
+
+      HttpController._sortContacts(contacts)
+      contacts = contacts.slice(0, limit)
+      const contact_ids = contacts.map(contact => contact.user_id)
+
+      return res.status(200).send({
+        contact_ids
+      })
+    })
+  },
+
+  _sortContacts(contacts) {
+    return contacts.sort(function(a, b) {
+      // Sort by decreasing count, descreasing timestamp.
+      // I.e. biggest count, and most recent at front.
+      if (a.n > b.n) {
+        return -1
+      } else if (a.n < b.n) {
+        return 1
+      } else {
+        if (a.ts > b.ts) {
+          return -1
+        } else if (a.ts < b.ts) {
+          return 1
+        } else {
+          return 0
+        }
+      }
+    })
+  }
+}

+ 9 - 0
services/contacts/app/js/mongojs.js

@@ -0,0 +1,9 @@
+// TODO: This file was created by bulk-decaffeinate.
+// Sanity-check the conversion and remove this comment.
+const Settings = require('settings-sharelatex')
+const mongojs = require('mongojs')
+const db = mongojs(Settings.mongo.url, ['contacts'])
+module.exports = {
+  db,
+  ObjectId: mongojs.ObjectId
+}

+ 5 - 5
services/contacts/buildscript.txt

@@ -1,10 +1,10 @@
 contacts
---public-repo=False
---language=coffeescript
---env-add=
 --node-version=10.19.0
---acceptance-creds=None
+--script-version=1.3.5
 --dependencies=mongo
+--language=es
 --docker-repos=gcr.io/overleaf-ops
+--acceptance-creds=None
 --env-pass-through=
---script-version=1.3.5
+--env-add=
+--public-repo=False

+ 0 - 11
services/contacts/config/settings.defaults.coffee

@@ -1,11 +0,0 @@
-http = require('http')
-http.globalAgent.maxSockets = 300
-
-module.exports =
-	internal:
-		contacts:
-			port: 3036
-			host: process.env["LISTEN_ADDRESS"] or "localhost"
-
-	mongo:
-		url: process.env['MONGO_CONNECTION_STRING'] or "mongodb://#{process.env["MONGO_HOST"] or "localhost"}/sharelatex"

+ 17 - 0
services/contacts/config/settings.defaults.js

@@ -0,0 +1,17 @@
+const http = require('http')
+http.globalAgent.maxSockets = 300
+
+module.exports = {
+  internal: {
+    contacts: {
+      port: 3036,
+      host: process.env.LISTEN_ADDRESS || 'localhost'
+    }
+  },
+
+  mongo: {
+    url:
+      process.env.MONGO_CONNECTION_STRING ||
+      `mongodb://${process.env.MONGO_HOST || 'localhost'}/sharelatex`
+  }
+}

+ 3 - 4
services/contacts/nodemon.json

@@ -10,10 +10,9 @@
   },
 
   "watch": [
-    "app/coffee/",
-    "app.coffee",
+    "app/js/",
+    "app.js",
     "config/"
   ],
-  "ext": "coffee"
-
+  "ext": "js"
 }

Fișier diff suprimat deoarece este prea mare
+ 628 - 67
services/contacts/package-lock.json


+ 28 - 13
services/contacts/package.json

@@ -8,34 +8,49 @@
     "url": "https://github.com/sharelatex/contacts-sharelatex.git"
   },
   "scripts": {
-    "compile:app": "([ -e app/coffee ] && coffee -m $COFFEE_OPTIONS -o app/js -c app/coffee || echo 'No CoffeeScript folder to compile') && ( [ -e app.coffee ] && coffee -m $COFFEE_OPTIONS -c app.coffee || echo 'No CoffeeScript app to compile')",
-    "start": "npm run compile:app && node $NODE_APP_OPTIONS app.js",
-    "test:acceptance:_run": "mocha --recursive --reporter spec --timeout 30000 --exit $@ test/acceptance/js",
-    "test:acceptance": "npm run compile:app && npm run compile:acceptance_tests && npm run test:acceptance:_run -- --grep=$MOCHA_GREP",
-    "test:unit:_run": "mocha --recursive --reporter spec --exit $@ test/unit/js",
-    "test:unit": "npm run compile:app && npm run compile:unit_tests && npm run test:unit:_run -- --grep=$MOCHA_GREP",
-    "compile:unit_tests": "[ ! -e test/unit/coffee ] &&  echo 'No unit tests to compile' || coffee -o test/unit/js -c test/unit/coffee",
-    "compile:acceptance_tests": "[ ! -e test/acceptance/coffee ] && echo 'No acceptance tests to compile' || coffee -o test/acceptance/js -c test/acceptance/coffee",
-    "compile:all": "npm run compile:app && npm run compile:unit_tests && npm run compile:acceptance_tests && npm run compile:smoke_tests",
+    "start": "node $NODE_APP_OPTIONS app.js",
+    "test:acceptance:_run": "mocha --recursive --reporter spec --timeout 15000 --exit $@ test/acceptance/js",
+    "test:acceptance": "npm run test:acceptance:_run -- --grep=$MOCHA_GREP",
+    "test:unit:_run": "mocha --recursive --reporter spec $@ test/unit/js",
+    "test:unit": "npm run test:unit:_run -- --grep=$MOCHA_GREP",
     "nodemon": "nodemon --config nodemon.json",
-    "compile:smoke_tests": "[ ! -e test/smoke/coffee ] &&  echo 'No smoke tests to compile' || coffee -o test/smoke/js -c test/smoke/coffee"
+    "lint": "node_modules/.bin/eslint .",
+    "format": "node_modules/.bin/prettier-eslint '**/*.js' --list-different",
+    "format:fix": "node_modules/.bin/prettier-eslint '**/*.js' --write"
   },
   "dependencies": {
     "async": "~0.8.0",
     "body-parser": "~1.0.2",
-    "coffee-script": "^1.7.1",
-    "express": "~4.1.1",
+    "express": "~4.5.0",
     "logger-sharelatex": "^1.7.0",
     "metrics-sharelatex": "^2.2.0",
     "mongojs": "2.4.0",
-    "request": "~2.34.0",
+    "request": "~2.47.0",
     "settings-sharelatex": "^1.1.0",
     "underscore": "~1.6.0"
   },
   "devDependencies": {
+    "babel-eslint": "^10.0.3",
     "bunyan": "~0.22.3",
     "chai": "~1.9.1",
+    "eslint": "^6.6.0",
+    "eslint-config-prettier": "^6.10.0",
+    "eslint-config-standard": "^14.1.0",
+    "eslint-config-standard-jsx": "^8.1.0",
+    "eslint-config-standard-react": "^9.2.0",
+    "eslint-plugin-chai-expect": "^2.1.0",
+    "eslint-plugin-chai-friendly": "^0.5.0",
+    "eslint-plugin-import": "^2.20.1",
+    "eslint-plugin-jsx-a11y": "^6.2.3",
+    "eslint-plugin-mocha": "^6.2.2",
+    "eslint-plugin-node": "^11.0.0",
+    "eslint-plugin-prettier": "^3.1.2",
+    "eslint-plugin-promise": "^4.2.1",
+    "eslint-plugin-react": "^7.18.3",
+    "eslint-plugin-standard": "^4.0.1",
     "mocha": "^4.0.1",
+    "prettier": "^1.19.1",
+    "prettier-eslint-cli": "^5.0.0",
     "sandboxed-module": "~0.3.0",
     "sinon": "~1.5.2",
     "timekeeper": "0.0.5"

+ 0 - 20
services/contacts/test/acceptance/coffee/ContactsApp.coffee

@@ -1,20 +0,0 @@
-app = require('../../../app')
-require("logger-sharelatex").logger.level("error")
-
-module.exports =
-	running: false
-	initing: false
-	callbacks: []
-	ensureRunning: (callback = (error) ->) ->
-		if @running
-			return callback()
-		else if @initing
-			@callbacks.push callback
-		else
-			@initing = true
-			@callbacks.push callback
-			app.listen 3036, "localhost", (error) => 
-				throw error if error?
-				@running = true
-				for callback in @callbacks
-					callback()

+ 0 - 71
services/contacts/test/acceptance/coffee/GettingContactsTests.coffee

@@ -1,71 +0,0 @@
-sinon = require "sinon"
-chai = require("chai")
-chai.should()
-expect = chai.expect
-ObjectId = require("mongojs").ObjectId
-request = require "request"
-async = require "async"
-ContactsApp = require "./ContactsApp"
-HOST = "http://localhost:3036"
-
-describe "Getting Contacts", ->
-	describe "with no contacts", ->
-		beforeEach (done)->
-			@user_id = ObjectId().toString()
-			ContactsApp.ensureRunning done
-		
-		it "should return an empty array", (done) ->
-			request {
-				method: "GET"
-				url: "#{HOST}/user/#{@user_id}/contacts"
-				json: true
-			}, (error, response, body) ->
-				response.statusCode.should.equal 200
-				body.contact_ids.should.deep.equal []
-				done()
-		
-	describe "with contacts", ->
-		beforeEach (done) ->
-			@user_id = ObjectId().toString()
-			@contact_id_1 = ObjectId().toString()
-			@contact_id_2 = ObjectId().toString()
-			@contact_id_3 = ObjectId().toString()
-			
-			touchContact = (user_id, contact_id, cb) ->
-				request({
-					method: "POST"
-					url: "#{HOST}/user/#{user_id}/contacts"
-					json: {
-						contact_id: contact_id
-					}
-				}, cb)
-			
-			async.series [
-				# 2 is preferred since touched twice, then 3 since most recent, then 1
-				(cb) => ContactsApp.ensureRunning cb
-				(cb) => touchContact @user_id, @contact_id_1, cb
-				(cb) => touchContact @user_id, @contact_id_2, cb
-				(cb) => touchContact @user_id, @contact_id_2, cb
-				(cb) => touchContact @user_id, @contact_id_3, cb
-			], done
-		
-		it "should return a sorted list of contacts", (done) ->
-			request {
-				method: "GET"
-				url: "#{HOST}/user/#{@user_id}/contacts"
-				json: true
-			}, (error, response, body) =>
-				response.statusCode.should.equal 200
-				body.contact_ids.should.deep.equal [@contact_id_2, @contact_id_3, @contact_id_1]
-				done()
-		
-		it "should respect a limit and only return top X contacts", ->
-			request {
-				method: "GET"
-				url: "#{HOST}/user/#{@user_id}/contacts?limit=2"
-				json: true
-			}, (error, response, body) =>
-				response.statusCode.should.equal 200
-				body.contact_ids.should.deep.equal [@contact_id_2, @contact_id_3]
-				done()
-	

+ 47 - 0
services/contacts/test/acceptance/js/ContactsApp.js

@@ -0,0 +1,47 @@
+/* eslint-disable
+    handle-callback-err,
+*/
+// TODO: This file was created by bulk-decaffeinate.
+// Fix any style issues and re-enable lint.
+/*
+ * decaffeinate suggestions:
+ * DS101: Remove unnecessary use of Array.from
+ * DS102: Remove unnecessary code created because of implicit returns
+ * DS205: Consider reworking code to avoid use of IIFEs
+ * DS207: Consider shorter variations of null checks
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const app = require('../../../app')
+require('logger-sharelatex').logger.level('error')
+
+module.exports = {
+  running: false,
+  initing: false,
+  callbacks: [],
+  ensureRunning(callback) {
+    if (callback == null) {
+      callback = function(error) {}
+    }
+    if (this.running) {
+      return callback()
+    } else if (this.initing) {
+      return this.callbacks.push(callback)
+    } else {
+      this.initing = true
+      this.callbacks.push(callback)
+      return app.listen(3036, 'localhost', error => {
+        if (error != null) {
+          throw error
+        }
+        this.running = true
+        return (() => {
+          const result = []
+          for (callback of Array.from(this.callbacks)) {
+            result.push(callback())
+          }
+          return result
+        })()
+      })
+    }
+  }
+}

+ 116 - 0
services/contacts/test/acceptance/js/GettingContactsTests.js

@@ -0,0 +1,116 @@
+/* eslint-disable
+    camelcase,
+    handle-callback-err,
+    no-undef,
+    no-unused-vars,
+*/
+// TODO: This file was created by bulk-decaffeinate.
+// Fix any style issues and re-enable lint.
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const sinon = require('sinon')
+const chai = require('chai')
+chai.should()
+const { expect } = chai
+const { ObjectId } = require('mongojs')
+const request = require('request')
+const async = require('async')
+const ContactsApp = require('./ContactsApp')
+const HOST = 'http://localhost:3036'
+
+describe('Getting Contacts', function() {
+  describe('with no contacts', function() {
+    beforeEach(function(done) {
+      this.user_id = ObjectId().toString()
+      return ContactsApp.ensureRunning(done)
+    })
+
+    return it('should return an empty array', function(done) {
+      return request(
+        {
+          method: 'GET',
+          url: `${HOST}/user/${this.user_id}/contacts`,
+          json: true
+        },
+        (error, response, body) => {
+          response.statusCode.should.equal(200)
+          body.contact_ids.should.deep.equal([])
+          return done()
+        }
+      )
+    })
+  })
+
+  return describe('with contacts', function() {
+    beforeEach(function(done) {
+      this.user_id = ObjectId().toString()
+      this.contact_id_1 = ObjectId().toString()
+      this.contact_id_2 = ObjectId().toString()
+      this.contact_id_3 = ObjectId().toString()
+
+      const touchContact = (user_id, contact_id, cb) =>
+        request(
+          {
+            method: 'POST',
+            url: `${HOST}/user/${user_id}/contacts`,
+            json: {
+              contact_id
+            }
+          },
+          cb
+        )
+
+      return async.series(
+        [
+          // 2 is preferred since touched twice, then 3 since most recent, then 1
+          cb => ContactsApp.ensureRunning(cb),
+          cb => touchContact(this.user_id, this.contact_id_1, cb),
+          cb => touchContact(this.user_id, this.contact_id_2, cb),
+          cb => touchContact(this.user_id, this.contact_id_2, cb),
+          cb => touchContact(this.user_id, this.contact_id_3, cb)
+        ],
+        done
+      )
+    })
+
+    it('should return a sorted list of contacts', function(done) {
+      return request(
+        {
+          method: 'GET',
+          url: `${HOST}/user/${this.user_id}/contacts`,
+          json: true
+        },
+        (error, response, body) => {
+          response.statusCode.should.equal(200)
+          body.contact_ids.should.deep.equal([
+            this.contact_id_2,
+            this.contact_id_3,
+            this.contact_id_1
+          ])
+          return done()
+        }
+      )
+    })
+
+    return it('should respect a limit and only return top X contacts', function() {
+      return request(
+        {
+          method: 'GET',
+          url: `${HOST}/user/${this.user_id}/contacts?limit=2`,
+          json: true
+        },
+        (error, response, body) => {
+          response.statusCode.should.equal(200)
+          body.contact_ids.should.deep.equal([
+            this.contact_id_2,
+            this.contact_id_3
+          ])
+          return done()
+        }
+      )
+    })
+  })
+})

+ 0 - 86
services/contacts/test/unit/coffee/ContactsManagerTests.coffee

@@ -1,86 +0,0 @@
-sinon = require('sinon')
-chai = require('chai')
-should = chai.should()
-expect = chai.expect
-modulePath = "../../../app/js/ContactManager.js"
-SandboxedModule = require('sandboxed-module')
-ObjectId = require("mongojs").ObjectId
-tk = require("timekeeper")
-
-describe "ContactManager", ->
-	beforeEach ->
-		tk.freeze(Date.now())
-		@ContactManager = SandboxedModule.require modulePath, requires:
-			"./mongojs": {
-				db: @db = contacts: {}
-				ObjectId: ObjectId
-			},
-			'logger-sharelatex': {log: sinon.stub()},
-			'metrics-sharelatex': {timeAsyncMethod: sinon.stub()}
-		@user_id = ObjectId().toString()
-		@contact_id = ObjectId().toString()
-		@callback = sinon.stub()
-	
-	afterEach ->
-		tk.reset()
-
-	describe "touchContact", ->
-		beforeEach ->
-			@db.contacts.update = sinon.stub().callsArg(3)
-		
-		describe "with a valid user_id", ->
-			beforeEach ->
-				@ContactManager.touchContact @user_id, @contact_id = "mock_contact", @callback
-			
-			it "should increment the contact count and timestamp", ->
-				@db.contacts.update
-					.calledWith({
-						user_id: sinon.match((o) => o.toString() == @user_id.toString())
-					}, {
-						$inc:
-							"contacts.mock_contact.n": 1
-						$set:
-							"contacts.mock_contact.ts": new Date()
-					}, {
-						upsert: true
-					})
-					.should.equal true
-			
-			it "should call the callback", ->
-				@callback.called.should.equal true
-		
-		describe "with an invalid user id", ->
-			beforeEach ->
-				@ContactManager.touchContact "not-valid-object-id", @contact_id, @callback
-			
-			it "should call the callback with an error", ->
-				@callback.calledWith(new Error()).should.equal true
-	
-	describe "getContacts", ->
-		beforeEach ->
-			@user = {
-				contacts: ["mock", "contacts"]
-			}
-			@db.contacts.findOne = sinon.stub().callsArgWith(1, null, @user)
-		
-		describe "with a valid user_id", ->
-			beforeEach ->
-				@ContactManager.getContacts @user_id, @callback
-			
-			it "should find the user's contacts", ->
-				@db.contacts.findOne
-					.calledWith({
-						user_id: sinon.match((o) => o.toString() == @user_id.toString())
-					})
-					.should.equal true
-			
-			it "should call the callback with the contacts", ->
-				@callback.calledWith(null, @user.contacts).should.equal true
-		
-		describe "with an invalid user id", ->
-			beforeEach ->
-				@ContactManager.getContacts "not-valid-object-id", @callback
-			
-			it "should call the callback with an error", ->
-				@callback.calledWith(new Error()).should.equal true
-		

+ 0 - 120
services/contacts/test/unit/coffee/HttpControllerTests.coffee

@@ -1,120 +0,0 @@
-sinon = require('sinon')
-chai = require('chai')
-should = chai.should()
-expect = chai.expect
-modulePath = "../../../app/js/HttpController.js"
-SandboxedModule = require('sandboxed-module')
-
-describe "HttpController", ->
-	beforeEach ->
-		@HttpController = SandboxedModule.require modulePath, requires:
-			"./ContactManager": @ContactManager = {}
-			"logger-sharelatex": @logger = { log: sinon.stub() }
-		@user_id = "mock-user-id"
-		@contact_id = "mock-contact-id"
-		
-		@req = {}
-		@res = {}
-		@res.status = sinon.stub().returns @res
-		@res.end = sinon.stub()
-		@res.send = sinon.stub()
-		@next = sinon.stub()
-
-	describe "addContact", ->
-		beforeEach ->
-			@req.params =
-				user_id: @user_id
-			@ContactManager.touchContact = sinon.stub().callsArg(2)
-		
-		describe "with a valid user_id and contact_id", ->
-			beforeEach ->
-				@req.body =
-					contact_id: @contact_id
-				@HttpController.addContact @req, @res, @next
-			
-			it "should update the contact in the user's contact list", ->
-				@ContactManager.touchContact
-					.calledWith(@user_id, @contact_id)
-					.should.equal true
-			
-			it "should update the user in the contact's contact list", ->
-				@ContactManager.touchContact
-					.calledWith(@contact_id, @user_id)
-					.should.equal true
-			
-			it "should send back a 204 status", ->
-				@res.status.calledWith(204).should.equal true
-				@res.end.called.should.equal true
-		
-		describe "with an invalid contact id", ->
-			beforeEach ->
-				@req.body =
-					contact_id: ""
-				@HttpController.addContact @req, @res, @next
-			
-			it "should return 400, Bad Request", ->
-				@res.status.calledWith(400).should.equal true
-				@res.send.calledWith("contact_id should be a non-blank string").should.equal true
-
-	describe "getContacts", ->
-		beforeEach ->
-			@req.params =
-				user_id: @user_id
-			now = Date.now()
-			@contacts = {
-				"user-id-1": { n: 2, ts: new Date(now) }
-				"user-id-2": { n: 4, ts: new Date(now) }
-				"user-id-3": { n: 2, ts: new Date(now - 1000) }
-			}
-			@ContactManager.getContacts = sinon.stub().callsArgWith(1, null, @contacts)
-
-		describe "normally", ->
-			beforeEach ->
-				@HttpController.getContacts @req, @res, @next
-				
-			it "should look up the contacts in mongo", ->
-				@ContactManager.getContacts
-					.calledWith(@user_id)
-					.should.equal true
-			
-			it "should return a sorted list of contacts by count and timestamp", ->
-				@res.send
-					.calledWith({
-						contact_ids: [
-							"user-id-2"
-							"user-id-1"
-							"user-id-3"
-						]
-					})
-					.should.equal true
-		
-		describe "with more contacts than the limit", ->
-			beforeEach ->
-				@req.query =
-					limit: 2
-				@HttpController.getContacts @req, @res, @next
-
-			it "should return the most commonly used contacts up to the limit", ->
-				@res.send
-					.calledWith({
-						contact_ids: [
-							"user-id-2"
-							"user-id-1"
-						]
-					})
-					.should.equal true
-		
-		describe "without a contact list", ->
-			beforeEach ->
-				@ContactManager.getContacts = sinon.stub().callsArgWith(1, null, null)
-				@HttpController.getContacts @req, @res, @next
-
-			it "should return an empty list", ->
-				@res.send
-					.calledWith({
-						contact_ids: []
-					})
-					.should.equal true
-		
-		describe "with a holding account", ->
-			it "should not return holding accounts"

+ 143 - 0
services/contacts/test/unit/js/ContactsManagerTests.js

@@ -0,0 +1,143 @@
+/* eslint-disable
+    no-return-assign,
+    no-unused-vars,
+*/
+// TODO: This file was created by bulk-decaffeinate.
+// Fix any style issues and re-enable lint.
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const sinon = require('sinon')
+const chai = require('chai')
+const should = chai.should()
+const { expect } = chai
+const modulePath = '../../../app/js/ContactManager.js'
+const SandboxedModule = require('sandboxed-module')
+const { ObjectId } = require('mongojs')
+const tk = require('timekeeper')
+
+describe('ContactManager', function() {
+  beforeEach(function() {
+    tk.freeze(Date.now())
+    this.ContactManager = SandboxedModule.require(modulePath, {
+      requires: {
+        './mongojs': {
+          db: (this.db = { contacts: {} }),
+          ObjectId
+        },
+        'logger-sharelatex': { log: sinon.stub() },
+        'metrics-sharelatex': { timeAsyncMethod: sinon.stub() }
+      }
+    })
+    this.user_id = ObjectId().toString()
+    this.contact_id = ObjectId().toString()
+    return (this.callback = sinon.stub())
+  })
+
+  afterEach(function() {
+    return tk.reset()
+  })
+
+  describe('touchContact', function() {
+    beforeEach(function() {
+      return (this.db.contacts.update = sinon.stub().callsArg(3))
+    })
+
+    describe('with a valid user_id', function() {
+      beforeEach(function() {
+        return this.ContactManager.touchContact(
+          this.user_id,
+          (this.contact_id = 'mock_contact'),
+          this.callback
+        )
+      })
+
+      it('should increment the contact count and timestamp', function() {
+        return this.db.contacts.update
+          .calledWith(
+            {
+              user_id: sinon.match(
+                o => o.toString() === this.user_id.toString()
+              )
+            },
+            {
+              $inc: {
+                'contacts.mock_contact.n': 1
+              },
+              $set: {
+                'contacts.mock_contact.ts': new Date()
+              }
+            },
+            {
+              upsert: true
+            }
+          )
+          .should.equal(true)
+      })
+
+      return it('should call the callback', function() {
+        return this.callback.called.should.equal(true)
+      })
+    })
+
+    return describe('with an invalid user id', function() {
+      beforeEach(function() {
+        return this.ContactManager.touchContact(
+          'not-valid-object-id',
+          this.contact_id,
+          this.callback
+        )
+      })
+
+      return it('should call the callback with an error', function() {
+        return this.callback.calledWith(new Error()).should.equal(true)
+      })
+    })
+  })
+
+  return describe('getContacts', function() {
+    beforeEach(function() {
+      this.user = {
+        contacts: ['mock', 'contacts']
+      }
+      return (this.db.contacts.findOne = sinon
+        .stub()
+        .callsArgWith(1, null, this.user))
+    })
+
+    describe('with a valid user_id', function() {
+      beforeEach(function() {
+        return this.ContactManager.getContacts(this.user_id, this.callback)
+      })
+
+      it("should find the user's contacts", function() {
+        return this.db.contacts.findOne
+          .calledWith({
+            user_id: sinon.match(o => o.toString() === this.user_id.toString())
+          })
+          .should.equal(true)
+      })
+
+      return it('should call the callback with the contacts', function() {
+        return this.callback
+          .calledWith(null, this.user.contacts)
+          .should.equal(true)
+      })
+    })
+
+    return describe('with an invalid user id', function() {
+      beforeEach(function() {
+        return this.ContactManager.getContacts(
+          'not-valid-object-id',
+          this.callback
+        )
+      })
+
+      return it('should call the callback with an error', function() {
+        return this.callback.calledWith(new Error()).should.equal(true)
+      })
+    })
+  })
+})

+ 150 - 0
services/contacts/test/unit/js/HttpControllerTests.js

@@ -0,0 +1,150 @@
+/* eslint-disable
+    mocha/no-pending-tests,
+    no-return-assign,
+    no-unused-vars,
+*/
+// TODO: This file was created by bulk-decaffeinate.
+// Fix any style issues and re-enable lint.
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const sinon = require('sinon')
+const chai = require('chai')
+const should = chai.should()
+const { expect } = chai
+const modulePath = '../../../app/js/HttpController.js'
+const SandboxedModule = require('sandboxed-module')
+
+describe('HttpController', function() {
+  beforeEach(function() {
+    this.HttpController = SandboxedModule.require(modulePath, {
+      requires: {
+        './ContactManager': (this.ContactManager = {}),
+        'logger-sharelatex': (this.logger = { log: sinon.stub() })
+      }
+    })
+    this.user_id = 'mock-user-id'
+    this.contact_id = 'mock-contact-id'
+
+    this.req = {}
+    this.res = {}
+    this.res.status = sinon.stub().returns(this.res)
+    this.res.end = sinon.stub()
+    this.res.send = sinon.stub()
+    return (this.next = sinon.stub())
+  })
+
+  describe('addContact', function() {
+    beforeEach(function() {
+      this.req.params = { user_id: this.user_id }
+      return (this.ContactManager.touchContact = sinon.stub().callsArg(2))
+    })
+
+    describe('with a valid user_id and contact_id', function() {
+      beforeEach(function() {
+        this.req.body = { contact_id: this.contact_id }
+        return this.HttpController.addContact(this.req, this.res, this.next)
+      })
+
+      it("should update the contact in the user's contact list", function() {
+        return this.ContactManager.touchContact
+          .calledWith(this.user_id, this.contact_id)
+          .should.equal(true)
+      })
+
+      it("should update the user in the contact's contact list", function() {
+        return this.ContactManager.touchContact
+          .calledWith(this.contact_id, this.user_id)
+          .should.equal(true)
+      })
+
+      return it('should send back a 204 status', function() {
+        this.res.status.calledWith(204).should.equal(true)
+        return this.res.end.called.should.equal(true)
+      })
+    })
+
+    return describe('with an invalid contact id', function() {
+      beforeEach(function() {
+        this.req.body = { contact_id: '' }
+        return this.HttpController.addContact(this.req, this.res, this.next)
+      })
+
+      return it('should return 400, Bad Request', function() {
+        this.res.status.calledWith(400).should.equal(true)
+        return this.res.send
+          .calledWith('contact_id should be a non-blank string')
+          .should.equal(true)
+      })
+    })
+  })
+
+  return describe('getContacts', function() {
+    beforeEach(function() {
+      this.req.params = { user_id: this.user_id }
+      const now = Date.now()
+      this.contacts = {
+        'user-id-1': { n: 2, ts: new Date(now) },
+        'user-id-2': { n: 4, ts: new Date(now) },
+        'user-id-3': { n: 2, ts: new Date(now - 1000) }
+      }
+      return (this.ContactManager.getContacts = sinon
+        .stub()
+        .callsArgWith(1, null, this.contacts))
+    })
+
+    describe('normally', function() {
+      beforeEach(function() {
+        return this.HttpController.getContacts(this.req, this.res, this.next)
+      })
+
+      it('should look up the contacts in mongo', function() {
+        return this.ContactManager.getContacts
+          .calledWith(this.user_id)
+          .should.equal(true)
+      })
+
+      return it('should return a sorted list of contacts by count and timestamp', function() {
+        return this.res.send
+          .calledWith({
+            contact_ids: ['user-id-2', 'user-id-1', 'user-id-3']
+          })
+          .should.equal(true)
+      })
+    })
+
+    describe('with more contacts than the limit', function() {
+      beforeEach(function() {
+        this.req.query = { limit: 2 }
+        return this.HttpController.getContacts(this.req, this.res, this.next)
+      })
+
+      return it('should return the most commonly used contacts up to the limit', function() {
+        return this.res.send
+          .calledWith({
+            contact_ids: ['user-id-2', 'user-id-1']
+          })
+          .should.equal(true)
+      })
+    })
+
+    describe('without a contact list', function() {
+      beforeEach(function() {
+        this.ContactManager.getContacts = sinon
+          .stub()
+          .callsArgWith(1, null, null)
+        return this.HttpController.getContacts(this.req, this.res, this.next)
+      })
+
+      return it('should return an empty list', function() {
+        return this.res.send
+          .calledWith({
+            contact_ids: []
+          })
+          .should.equal(true)
+      })
+    })
+  })
+})

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff