mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-29 05:23:40 -05:00
Add endpoint to remove learned words
This commit is contained in:
parent
134ff0b29d
commit
e7ab9f79a9
7 changed files with 157 additions and 2 deletions
|
@ -30,6 +30,7 @@ server.del('/user/:user_id', SpellingAPIController.deleteDic)
|
||||||
server.get('/user/:user_id', SpellingAPIController.getDic)
|
server.get('/user/:user_id', SpellingAPIController.getDic)
|
||||||
server.post('/user/:user_id/check', SpellingAPIController.check)
|
server.post('/user/:user_id/check', SpellingAPIController.check)
|
||||||
server.post('/user/:user_id/learn', SpellingAPIController.learn)
|
server.post('/user/:user_id/learn', SpellingAPIController.learn)
|
||||||
|
server.post('/user/:user_id/unlearn', SpellingAPIController.unlearn)
|
||||||
server.get('/status', (req, res) => res.send({ status: 'spelling api is up' }))
|
server.get('/status', (req, res) => res.send({ status: 'spelling api is up' }))
|
||||||
|
|
||||||
server.get('/health_check', HealthCheckController.healthCheck)
|
server.get('/health_check', HealthCheckController.healthCheck)
|
||||||
|
|
|
@ -24,6 +24,22 @@ const LearnedWordsManager = {
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
unlearnWord(userToken, word, callback) {
|
||||||
|
if (callback == null) {
|
||||||
|
callback = () => {}
|
||||||
|
}
|
||||||
|
mongoCache.del(userToken)
|
||||||
|
return db.spellingPreferences.update(
|
||||||
|
{
|
||||||
|
token: userToken
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$pull: { learnedWords: word }
|
||||||
|
},
|
||||||
|
callback
|
||||||
|
)
|
||||||
|
},
|
||||||
|
|
||||||
getLearnedWords(userToken, callback) {
|
getLearnedWords(userToken, callback) {
|
||||||
if (callback == null) {
|
if (callback == null) {
|
||||||
callback = () => {}
|
callback = () => {}
|
||||||
|
@ -61,6 +77,7 @@ const LearnedWordsManager = {
|
||||||
|
|
||||||
const promises = {
|
const promises = {
|
||||||
learnWord: promisify(LearnedWordsManager.learnWord),
|
learnWord: promisify(LearnedWordsManager.learnWord),
|
||||||
|
unlearnWord: promisify(LearnedWordsManager.unlearnWord),
|
||||||
getLearnedWords: promisify(LearnedWordsManager.getLearnedWords),
|
getLearnedWords: promisify(LearnedWordsManager.getLearnedWords),
|
||||||
deleteUsersLearnedWords: promisify(
|
deleteUsersLearnedWords: promisify(
|
||||||
LearnedWordsManager.deleteUsersLearnedWords
|
LearnedWordsManager.deleteUsersLearnedWords
|
||||||
|
@ -70,7 +87,7 @@ const promises = {
|
||||||
LearnedWordsManager.promises = promises
|
LearnedWordsManager.promises = promises
|
||||||
|
|
||||||
module.exports = LearnedWordsManager
|
module.exports = LearnedWordsManager
|
||||||
;['learnWord', 'getLearnedWords'].map(method =>
|
;['learnWord', 'unlearnWord', 'getLearnedWords'].map(method =>
|
||||||
metrics.timeAsyncMethod(
|
metrics.timeAsyncMethod(
|
||||||
LearnedWordsManager,
|
LearnedWordsManager,
|
||||||
method,
|
method,
|
||||||
|
|
|
@ -49,6 +49,19 @@ module.exports = {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
unlearn(req, res, next) {
|
||||||
|
metrics.inc('spelling-unlearn', 0.1)
|
||||||
|
const { token, word } = extractLearnRequestData(req)
|
||||||
|
logger.info({ token, word }, 'unlearning word')
|
||||||
|
SpellingAPIManager.unlearnWord(token, req.body, function(error) {
|
||||||
|
if (error != null) {
|
||||||
|
return next(error)
|
||||||
|
}
|
||||||
|
res.sendStatus(200)
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
deleteDic(req, res, next) {
|
deleteDic(req, res, next) {
|
||||||
const { token, word } = extractLearnRequestData(req)
|
const { token, word } = extractLearnRequestData(req)
|
||||||
logger.log({ token, word }, 'deleting user dictionary')
|
logger.log({ token, word }, 'deleting user dictionary')
|
||||||
|
|
|
@ -30,6 +30,20 @@ const SpellingAPIManager = {
|
||||||
return LearnedWordsManager.learnWord(token, request.word, callback)
|
return LearnedWordsManager.learnWord(token, request.word, callback)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
unlearnWord(token, request, callback) {
|
||||||
|
if (callback == null) {
|
||||||
|
callback = () => {}
|
||||||
|
}
|
||||||
|
if (request.word == null) {
|
||||||
|
return callback(new Error('malformed JSON'))
|
||||||
|
}
|
||||||
|
if (token == null) {
|
||||||
|
return callback(new Error('no token provided'))
|
||||||
|
}
|
||||||
|
|
||||||
|
return LearnedWordsManager.unlearnWord(token, request.word, callback)
|
||||||
|
},
|
||||||
|
|
||||||
deleteDic(token, callback) {
|
deleteDic(token, callback) {
|
||||||
return LearnedWordsManager.deleteUsersLearnedWords(token, callback)
|
return LearnedWordsManager.deleteUsersLearnedWords(token, callback)
|
||||||
},
|
},
|
||||||
|
|
|
@ -19,6 +19,14 @@ const learnWord = word =>
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const unlearnWord = word =>
|
||||||
|
request.post({
|
||||||
|
url: `/user/${USER_ID}/unlearn`,
|
||||||
|
body: JSON.stringify({
|
||||||
|
word
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
const deleteDict = () =>
|
const deleteDict = () =>
|
||||||
request.del({
|
request.del({
|
||||||
url: `/user/${USER_ID}`
|
url: `/user/${USER_ID}`
|
||||||
|
@ -51,3 +59,24 @@ describe('learning words', () => {
|
||||||
expect(responseBody.misspellings.length).to.equals(1)
|
expect(responseBody.misspellings.length).to.equals(1)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('unlearning words', () => {
|
||||||
|
it('should return status 200 when posting a word successfully', async () => {
|
||||||
|
const response = await unlearnWord('anything')
|
||||||
|
expect(response.statusCode).to.equal(200)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return misspellings after a word is unlearnt', async () => {
|
||||||
|
await learnWord('abv')
|
||||||
|
|
||||||
|
const response = await checkWord(['abv'])
|
||||||
|
const responseBody = JSON.parse(response.body)
|
||||||
|
expect(responseBody.misspellings.length).to.equals(0)
|
||||||
|
|
||||||
|
await unlearnWord('abv')
|
||||||
|
|
||||||
|
const response2 = await checkWord(['abv'])
|
||||||
|
const responseBody2 = JSON.parse(response2.body)
|
||||||
|
expect(responseBody2.misspellings.length).to.equals(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
|
@ -24,7 +24,7 @@ describe('LearnedWordsManager', function() {
|
||||||
this.callback = sinon.stub()
|
this.callback = sinon.stub()
|
||||||
this.db = {
|
this.db = {
|
||||||
spellingPreferences: {
|
spellingPreferences: {
|
||||||
update: sinon.stub().callsArg(3)
|
update: sinon.stub().yields()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.cache = {
|
this.cache = {
|
||||||
|
@ -80,6 +80,34 @@ describe('LearnedWordsManager', function() {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('unlearnWord', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
this.word = 'instanton'
|
||||||
|
return this.LearnedWordsManager.unlearnWord(
|
||||||
|
this.token,
|
||||||
|
this.word,
|
||||||
|
this.callback
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should remove the word from the word list in the database', function() {
|
||||||
|
return expect(
|
||||||
|
this.db.spellingPreferences.update.calledWith(
|
||||||
|
{
|
||||||
|
token: this.token
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$pull: { learnedWords: this.word }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
).to.equal(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
return it('should call the callback', function() {
|
||||||
|
return expect(this.callback.called).to.equal(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('getLearnedWords', function() {
|
describe('getLearnedWords', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
this.wordList = ['apples', 'bananas', 'pears']
|
this.wordList = ['apples', 'bananas', 'pears']
|
||||||
|
|
|
@ -21,6 +21,7 @@ describe('SpellingAPIManager', function() {
|
||||||
this.LearnedWordsManager = {
|
this.LearnedWordsManager = {
|
||||||
getLearnedWords: sinon.stub().callsArgWith(1, null, this.learnedWords),
|
getLearnedWords: sinon.stub().callsArgWith(1, null, this.learnedWords),
|
||||||
learnWord: sinon.stub().callsArg(2),
|
learnWord: sinon.stub().callsArg(2),
|
||||||
|
unlearnWord: sinon.stub().callsArg(2),
|
||||||
promises: {
|
promises: {
|
||||||
getLearnedWords: sinon.stub().returns(promiseStub(this.learnedWords))
|
getLearnedWords: sinon.stub().returns(promiseStub(this.learnedWords))
|
||||||
}
|
}
|
||||||
|
@ -229,4 +230,56 @@ describe('SpellingAPIManager', function() {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('unlearnWord', function() {
|
||||||
|
describe('without a token', function() {
|
||||||
|
beforeEach(function(done) {
|
||||||
|
this.SpellingAPIManager.unlearnWord(null, { word: 'banana' }, error => {
|
||||||
|
this.error = error
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return an error', function() {
|
||||||
|
expect(this.error).to.exist
|
||||||
|
expect(this.error).to.be.instanceof(Error)
|
||||||
|
expect(this.error.message).to.equal('no token provided')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('without a word', function() {
|
||||||
|
beforeEach(function(done) {
|
||||||
|
this.SpellingAPIManager.unlearnWord(this.token, {}, error => {
|
||||||
|
this.error = error
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return an error', function() {
|
||||||
|
expect(this.error).to.exist
|
||||||
|
expect(this.error).to.be.instanceof(Error)
|
||||||
|
expect(this.error.message).to.equal('malformed JSON')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('with a word and a token', function() {
|
||||||
|
beforeEach(function(done) {
|
||||||
|
this.word = 'banana'
|
||||||
|
this.SpellingAPIManager.unlearnWord(
|
||||||
|
this.token,
|
||||||
|
{ word: this.word },
|
||||||
|
error => {
|
||||||
|
this.error = error
|
||||||
|
done()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should call LearnedWordsManager.unlearnWord', function() {
|
||||||
|
this.LearnedWordsManager.unlearnWord
|
||||||
|
.calledWith(this.token, this.word)
|
||||||
|
.should.equal(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue