codecombat/server/handlers/patch_handler.coffee
Scott Erickson 7bab895dee Generalize new I18N view system
Previously, when diplomats submit translations, the system
would try to figure out whether it should be a 'patch' or a 'change',
and then would either create a patch for an admin or artisan to
review and accept or reject, or would apply the changes immediately
and they would be live. This was done as a compromise between
getting translations live quickly, but also preventing already-translated
text from getting overwritten without oversight.

But having the client handle this added logical complexity. So
this makes all diplomats submit patches, no matter what. The server
is then in charge of deciding if it should auto-accept the patch or not.
Either way, a patch is created.

There was also much refactoring. This commit includes:

* Update jsondiffpatch so changes within array items are handled correctly
* Refactor posting patches to use the new auto-accepting logic, and out of Patch model
* Refactor POST /db/patch/:handle/status so that it doesn't rely on handlers
* Refactor patch stat handling to ensure auto-accepted patches are counted
* Refactor User.incrementStat to use mongodb update commands, to avoid race conditions
* Refactor Patch tests
2016-09-09 10:59:26 -07:00

67 lines
2.8 KiB
CoffeeScript

Patch = require './../models/Patch'
User = require '../models/User'
Handler = require '../commons/Handler'
schema = require '../../app/schemas/models/patch'
{handlers} = require '../commons/mapping'
mongoose = require 'mongoose'
log = require 'winston'
sendwithus = require '../sendwithus'
slack = require '../slack'
PatchHandler = class PatchHandler extends Handler
modelClass: Patch
editableProperties: []
postEditableProperties: ['delta', 'target', 'commitMessage']
jsonSchema: require '../../app/schemas/models/patch'
makeNewInstance: (req) ->
patch = super(req)
patch.set 'creator', req.user._id
patch.set 'created', new Date().toISOString()
patch.set 'status', 'pending'
patch
get: (req, res) ->
if req.query.view in ['pending']
query = status: 'pending'
q = Patch.find(query)
q.exec (err, documents) =>
return @sendDatabaseError(res, err) if err
documents = (@formatEntity(req, doc) for doc in documents)
@sendSuccess(res, documents)
else
super(arguments...)
onPostSuccess: (req, doc) ->
log.error 'Error sending patch created: could not find the loaded target on the patch object.' unless doc.targetLoaded
return unless doc.targetLoaded
docLink = "http://codecombat.com#{req.headers['x-current-path']}"
@sendPatchCreatedSlackMessage creator: req.user, patch: doc, target: doc.targetLoaded, docLink: docLink
watchers = doc.targetLoaded.get('watchers') or []
# Don't send these emails to the person who submitted the patch, or to Nick, George, or Scott.
watchers = (w for w in watchers when not w.equals(req.user.get('_id')) and not (w + '' in ['512ef4805a67a8c507000001', '5162fab9c92b4c751e000274', '51538fdb812dd9af02000001']))
return unless watchers?.length
User.find({_id: {$in: watchers}}).select({email: 1, name: 1}).exec (err, watchers) =>
for watcher in watchers
@sendPatchCreatedEmail req.user, watcher, doc, doc.targetLoaded, docLink
sendPatchCreatedEmail: (patchCreator, watcher, patch, target, docLink) ->
return if not watcher.get('email')
# return if watcher._id is patchCreator._id
context =
email_id: sendwithus.templates.patch_created
recipient:
address: watcher.get('email')
name: watcher.get('name')
email_data:
doc_name: target.get('name') or '???'
submitter_name: patchCreator.get('name') or '???'
doc_link: docLink
commit_message: patch.get('commitMessage')
sendwithus.api.send context, (err, result) ->
sendPatchCreatedSlackMessage: (options) ->
message = "#{options.creator.get('name')} submitted a patch to #{options.target.get('name')}: #{options.patch.get('commitMessage')} #{options.docLink}"
slack.sendSlackMessage message, ['artisans']
module.exports = new PatchHandler()