diff --git a/app/assets/images/pages/community/logo_slack.png b/app/assets/images/pages/community/logo_slack.png new file mode 100644 index 000000000..ef3b21178 Binary files /dev/null and b/app/assets/images/pages/community/logo_slack.png differ diff --git a/app/locale/en.coffee b/app/locale/en.coffee index 6f12fe859..276f2b07e 100644 --- a/app/locale/en.coffee +++ b/app/locale/en.coffee @@ -868,7 +868,7 @@ social_facebook: "Like CodeCombat on Facebook" social_twitter: "Follow CodeCombat on Twitter" social_gplus: "Join CodeCombat on Google+" - social_hipchat: "Chat with us in the public CodeCombat Slack channel" + social_slack: "Chat with us in the public CodeCombat Slack channel" contribute_to_the_project: "Contribute to the project" clans: @@ -1294,7 +1294,7 @@ join_desc_3: ", or find us in our " join_desc_4: "and we'll go from there!" join_url_email: "Email us" - join_url_hipchat: "public Slack channel" + join_url_slack: "public Slack channel" archmage_subscribe_desc: "Get emails on new coding opportunities and announcements." artisan_introduction_pref: "We must construct additional levels! People be clamoring for more content, and we can only build so many ourselves. Right now your workstation is level one; our level editor is barely usable even by its creators, so be wary. If you have visions of campaigns spanning for-loops to" artisan_introduction_suf: ", then this class might be for you." diff --git a/app/templates/community-view.jade b/app/templates/community-view.jade index 0ca72419f..bb2b7e1d6 100644 --- a/app/templates/community-view.jade +++ b/app/templates/community-view.jade @@ -66,7 +66,7 @@ block content img(src="/images/pages/community/logo_g+.png", data-i18n="[data-content]community.social_gplus" data-content="Join CodeCombat on Google+") a(href="https://coco-slack-invite.herokuapp.com/") - img(src="/images/pages/community/logo_hipchat.png", data-i18n="[data-content]community.social_hipchat" data-content="Chat with us in the public CodeCombat Slack channel") + img(src="/images/pages/community/logo_slack.png", data-i18n="[data-content]community.social_slack" data-content="Chat with us in the public CodeCombat Slack channel") .half-width diff --git a/app/templates/contribute/archmage.jade b/app/templates/contribute/archmage.jade index bbbcaf80c..687665ae5 100644 --- a/app/templates/contribute/archmage.jade +++ b/app/templates/contribute/archmage.jade @@ -51,7 +51,7 @@ block content | Email us span(data-i18n="contribute.join_desc_3") | , or find us in our - a(href="https://coco-slack-invite.herokuapp.com/", data-i18n="contribute.join_url_hipchat") public Slack channel + a(href="https://coco-slack-invite.herokuapp.com/", data-i18n="contribute.join_url_slack") public Slack channel span span(data-i18n="contribute.join_desc_4") | and we'll go from there! diff --git a/multicore.coffee b/multicore.coffee index de179e25e..eac603287 100644 --- a/multicore.coffee +++ b/multicore.coffee @@ -76,10 +76,10 @@ if cluster.isMaster message = "Worker #{worker.id} died! #{deaths[Math.floor Math.random() * deaths.length]}" console.log message try - hipchat = require './server/hipchat' - hipchat.sendHipChatMessage(message, ['tower'], {papertrail: true}) + slack = require './server/slack' + slack.sendSlackMessage(message, ['tower'], {papertrail: true}) catch error - console.log "Couldn't send HipChat message on server death:", error + console.log "Couldn't send Slack message on server death:", error cluster.fork() else require('coffee-script') diff --git a/server/campaigns/campaign_handler.coffee b/server/campaigns/campaign_handler.coffee index 45870a594..b5a330556 100644 --- a/server/campaigns/campaign_handler.coffee +++ b/server/campaigns/campaign_handler.coffee @@ -126,7 +126,7 @@ CampaignHandler = class CampaignHandler extends Handler onPutSuccess: (req, doc) -> docLink = "http://codecombat.com#{req.headers['x-current-path']}" - @sendChangedHipChatMessage creator: req.user, target: doc, docLink: docLink + @sendChangedSlackMessage creator: req.user, target: doc, docLink: docLink getNamesByIDs: (req, res) -> @getNamesByOriginals req, res, true diff --git a/server/commons/Handler.coffee b/server/commons/Handler.coffee index ea830e064..aba77bd5d 100644 --- a/server/commons/Handler.coffee +++ b/server/commons/Handler.coffee @@ -6,7 +6,7 @@ log = require 'winston' Patch = require '../patches/Patch' User = require '../users/User' sendwithus = require '../sendwithus' -hipchat = require '../hipchat' +slack = require '../slack' deltasLib = require '../../app/core/deltas' PROJECT = {original: 1, name: 1, version: 1, description: 1, slug: 1, kind: 1, created: 1, permissions: 1} @@ -457,7 +457,7 @@ module.exports = class Handler notifyWatchersOfChange: (editor, changedDocument, editPath) -> docLink = "http://codecombat.com#{editPath}" - @sendChangedHipChatMessage creator: editor, target: changedDocument, docLink: docLink + @sendChangedSlackMessage creator: editor, target: changedDocument, docLink: docLink watchers = changedDocument.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(editor.get('_id')) and not (w + '' in ['512ef4805a67a8c507000001', '5162fab9c92b4c751e000274', '51538fdb812dd9af02000001'])) @@ -479,10 +479,10 @@ module.exports = class Handler commit_message: changedDocument.get('commitMessage') sendwithus.api.send context, (err, result) -> - sendChangedHipChatMessage: (options) -> + sendChangedSlackMessage: (options) -> message = "#{options.creator.get('name')} saved a change to #{options.target.get('name')}: #{options.target.get('commitMessage') or '(no commit message)'}" rooms = if /Diplomat submission/.test(message) then ['main'] else ['main', 'artisans'] - hipchat.sendHipChatMessage message, rooms + slack.sendSlackMessage message, rooms makeNewInstance: (req) -> model = new @modelClass({}) diff --git a/server/middleware/versions.coffee b/server/middleware/versions.coffee index 18da20f66..c1eb916bc 100644 --- a/server/middleware/versions.coffee +++ b/server/middleware/versions.coffee @@ -2,7 +2,7 @@ utils = require '../lib/utils' errors = require '../commons/errors' User = require '../users/User' sendwithus = require '../sendwithus' -hipchat = require '../hipchat' +slack = require '../slack' _ = require 'lodash' wrap = require 'co-express' mongoose = require 'mongoose' @@ -94,10 +94,10 @@ module.exports = editPath = req.headers['x-current-path'] docLink = "http://codecombat.com#{editPath}" - # Post a message on HipChat + # Post a message on Slack message = "#{req.user.get('name')} saved a change to #{doc.get('name')}: #{doc.get('commitMessage') or '(no commit message)'}" rooms = if /Diplomat submission/.test(message) then ['main'] else ['main', 'artisans'] - hipchat.sendHipChatMessage message, rooms + slack.sendSlackMessage message, rooms # Send emails to watchers watchers = doc.get('watchers') or [] diff --git a/server/models/TrialRequest.coffee b/server/models/TrialRequest.coffee index 1a525fa67..c1e3e5012 100644 --- a/server/models/TrialRequest.coffee +++ b/server/models/TrialRequest.coffee @@ -2,7 +2,6 @@ closeIO = require '../lib/closeIO' log = require 'winston' mongoose = require 'mongoose' config = require '../../server_config' -hipchat = require '../hipchat' sendwithus = require '../sendwithus' Prepaid = require '../prepaids/Prepaid' jsonSchema = require '../../app/schemas/models/trial_request.schema' diff --git a/server/patches/patch_handler.coffee b/server/patches/patch_handler.coffee index 63debc894..93654e972 100644 --- a/server/patches/patch_handler.coffee +++ b/server/patches/patch_handler.coffee @@ -6,7 +6,7 @@ schema = require '../../app/schemas/models/patch' mongoose = require 'mongoose' log = require 'winston' sendwithus = require '../sendwithus' -hipchat = require '../hipchat' +slack = require '../slack' PatchHandler = class PatchHandler extends Handler modelClass: Patch @@ -88,7 +88,7 @@ PatchHandler = class PatchHandler extends Handler 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']}" - @sendPatchCreatedHipChatMessage creator: req.user, patch: doc, target: doc.targetLoaded, docLink: docLink + @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'])) @@ -111,8 +111,8 @@ PatchHandler = class PatchHandler extends Handler commit_message: patch.get('commitMessage') sendwithus.api.send context, (err, result) -> - sendPatchCreatedHipChatMessage: (options) -> + sendPatchCreatedSlackMessage: (options) -> message = "#{options.creator.get('name')} submitted a patch to #{options.target.get('name')}: #{options.patch.get('commitMessage')}" - hipchat.sendHipChatMessage message, ['main'] + slack.sendSlackMessage message, ['main'] module.exports = new PatchHandler() diff --git a/server/payments/payment_handler.coffee b/server/payments/payment_handler.coffee index a8b729a28..b5e5837fe 100644 --- a/server/payments/payment_handler.coffee +++ b/server/payments/payment_handler.coffee @@ -7,7 +7,7 @@ Handler = require '../commons/Handler' mongoose = require 'mongoose' log = require 'winston' sendwithus = require '../sendwithus' -hipchat = require '../hipchat' +slack = require '../slack' config = require '../../server_config' request = require 'request' async = require 'async' @@ -178,7 +178,7 @@ PaymentHandler = class PaymentHandler extends Handler if err @logPaymentError(req, 'Apple incr db error.'+err) return @sendDatabaseError(res, err) - @sendPaymentHipChatMessage user: req.user, payment: payment + @sendPaymentSlackMessage user: req.user, payment: payment @sendCreated(res, @formatEntity(req, payment)) ) ) @@ -270,7 +270,7 @@ PaymentHandler = class PaymentHandler extends Handler if err @logPaymentError(req, 'Stripe recalc db error. '+err) return @sendDatabaseError(res, err) - @sendPaymentHipChatMessage user: req.user, payment: payment + @sendPaymentSlackMessage user: req.user, payment: payment @sendSuccess(res, @formatEntity(req, payment)) ) ) @@ -333,7 +333,7 @@ PaymentHandler = class PaymentHandler extends Handler if err @logPaymentError(req, 'Stripe incr db error. '+err) return @sendDatabaseError(res, err) - @sendPaymentHipChatMessage user: req.user, payment: payment + @sendPaymentSlackMessage user: req.user, payment: payment @sendCreated(res, @formatEntity(req, payment)) ) ) @@ -403,12 +403,12 @@ PaymentHandler = class PaymentHandler extends Handler user.save((err) -> done(err)) ) - sendPaymentHipChatMessage: (options) -> + sendPaymentSlackMessage: (options) -> try message = "#{options.user?.get('name')} bought #{options.payment?.get('amount')} via #{options.payment?.get('service')}" message += " for #{options.payment.get('description')}" if options.payment?.get('description') - hipchat.sendHipChatMessage message, ['tower'] + slack.sendSlackMessage message, ['tower'] catch e - log.error "Couldn't send HipChat message on payment because of error: #{e}" + log.error "Couldn't send Slack message on payment because of error: #{e}" module.exports = new PaymentHandler() diff --git a/server/payments/subscription_handler.coffee b/server/payments/subscription_handler.coffee index bfd957faa..4643d8a14 100644 --- a/server/payments/subscription_handler.coffee +++ b/server/payments/subscription_handler.coffee @@ -7,7 +7,7 @@ mongoose = require 'mongoose' async = require 'async' config = require '../../server_config' Handler = require '../commons/Handler' -hipchat = require '../hipchat' +slack = require '../slack' discountHandler = require './discount_handler' Prepaid = require '../prepaids/Prepaid' User = require '../users/User' @@ -185,9 +185,9 @@ class SubscriptionHandler extends Handler return @sendDatabaseError(res, err) try msg = "Year subscription purchased by #{req.user.get('email')} #{req.user.id}" - hipchat.sendHipChatMessage msg, ['tower'] + slack.sendSlackMessage msg, ['tower'] catch error - @logSubscriptionError(req.user, "Year sub sale HipChat tower msg error: #{JSON.stringify(error)}") + @logSubscriptionError(req.user, "Year sub sale Slack tower msg error: #{JSON.stringify(error)}") @sendSuccess(res, user) subscribeWithPrepaidCode: (req, res) -> diff --git a/server/prepaids/prepaid_handler.coffee b/server/prepaids/prepaid_handler.coffee index b92af6a72..4bee237df 100644 --- a/server/prepaids/prepaid_handler.coffee +++ b/server/prepaids/prepaid_handler.coffee @@ -1,6 +1,6 @@ Course = require '../courses/Course' Handler = require '../commons/Handler' -hipchat = require '../hipchat' +slack = require '../slack' Prepaid = require './Prepaid' User = require '../users/User' StripeUtils = require '../lib/stripe_utils' @@ -212,7 +212,7 @@ PrepaidHandler = class PrepaidHandler extends Handler @logError(user, "createPayment error: #{JSON.stringify(err)}") return done(err) msg = "Prepaid code purchased: #{type} seats=#{maxRedeemers} #{user.get('email')}" - hipchat.sendHipChatMessage msg, ['tower'] + slack.sendSlackMessage msg, ['tower'] done(null, prepaid) purchasePrepaidTerminalSubscription: (user, description, maxRedeemers, months, timestamp, token, product, done) -> @@ -249,7 +249,7 @@ PrepaidHandler = class PrepaidHandler extends Handler @logError(user, "createPayment error: #{JSON.stringify(err)}") return done(err) msg = "Prepaid code purchased: #{type} users=#{maxRedeemers} months=#{months} #{user.get('email')}" - hipchat.sendHipChatMessage msg, ['tower'] + slack.sendSlackMessage msg, ['tower'] done(null, prepaid) get: (req, res) -> diff --git a/server/routes/contact.coffee b/server/routes/contact.coffee index 7518d5115..2056af9ef 100644 --- a/server/routes/contact.coffee +++ b/server/routes/contact.coffee @@ -5,7 +5,6 @@ sendwithus = require '../sendwithus' async = require 'async' LevelSession = require '../levels/sessions/LevelSession' moment = require 'moment' -hipchat = require '../hipchat' module.exports.setup = (app) -> app.post '/contact', (req, res) -> diff --git a/server/routes/db.coffee b/server/routes/db.coffee index 728677b98..f3bad3596 100644 --- a/server/routes/db.coffee +++ b/server/routes/db.coffee @@ -3,7 +3,7 @@ errors = require '../commons/errors' handlers = require('../commons/mapping').handlers handlerUrlOverrides = require('../commons/mapping').handlerUrlOverrides mongoose = require 'mongoose' -hipchat = require '../hipchat' +slack = require '../slack' module.exports.setup = (app) -> # This is hacky and should probably get moved somewhere else, I dunno @@ -50,7 +50,7 @@ module.exports.setup = (app) -> log.error(error.stack) # TODO: Generally ignore this error: error: Error trying db method get route analytics.log.event from undefined: Error: Cannot find module '../undefined' unless "#{parts}" in ['analytics.users.active'] - hipchat.sendHipChatMessage errorMessage, ['tower'], papertrail: true + slack.sendSlackMessage errorMessage, ['tower'], papertrail: true errors.notFound(res, "Route #{req?.path} not found.") app.all '/db/' + moduleName + '/*', routeHandler diff --git a/server/slack.coffee b/server/slack.coffee new file mode 100644 index 000000000..bcbec8d74 --- /dev/null +++ b/server/slack.coffee @@ -0,0 +1,31 @@ +config = require '../server_config' +request = require 'request' +log = require 'winston' + +roomChannelMap = + main: '#general' + artisans: '#artisan' + +module.exports.sendSlackMessage = sendSlackMessage = (message, rooms=['tower'], options={}) -> + return unless config.isProduction + unless token = config.slackToken + log.info "No Slack token." + return + for room in rooms + channel = roomChannelMap[room] ? room + form = + channel: channel + token: token + text: message + if options.papertrail + secondsFromEpoch = Math.floor(new Date().getTime() / 1000) + link = "https://papertrailapp.com/groups/488214/events?time=#{secondsFromEpoch}" + form.text += " #{link}" + # https://api.slack.com/docs/formatting + form.text = form.text.replace('&', '&').replace('<', '<').replace('>', '>') + url = "https://slack.com/api/chat.postMessage" + request.post {uri: url, form: form}, (err, res, body) -> + return log.errr('Error sending Slack message:', err) if err + return log.error("Slack returned error: #{body.error}") unless body.ok + log.warn("Slack returned warning: #{body.warning}") if body.warning + # log.info "Got Slack message response:", body diff --git a/server/users/user_handler.coffee b/server/users/user_handler.coffee index a3dd83e09..26224dbcb 100644 --- a/server/users/user_handler.coffee +++ b/server/users/user_handler.coffee @@ -21,7 +21,7 @@ EarnedAchievement = require '../achievements/EarnedAchievement' UserRemark = require './remarks/UserRemark' {findStripeSubscription} = require '../lib/utils' {isID} = require '../lib/utils' -hipchat = require '../hipchat' +slack = require '../slack' sendwithus = require '../sendwithus' Prepaid = require '../prepaids/Prepaid' UserPollsRecord = require '../polls/UserPollsRecord' @@ -503,7 +503,7 @@ UserHandler = class UserHandler extends Handler req.user.save (err) => return @sendDatabaseError(res, err) if err @sendSuccess(res, {result: 'success'}) - hipchat.sendHipChatMessage "#{req.body.githubUsername or req.user.get('name')} just signed the CLA.", ['main'] + slack.sendSlackMessage "#{req.body.githubUsername or req.user.get('name')} just signed the CLA.", ['main'] avatar: (req, res, id) -> if not isID(id) diff --git a/server_config.coffee b/server_config.coffee index 394024920..0d936c74e 100644 --- a/server_config.coffee +++ b/server_config.coffee @@ -69,6 +69,8 @@ config.hipchat = tower: process.env.COCO_HIPCHAT_TOWER_API_KEY or '' artisans: process.env.COCO_HIPCHAT_ARTISANS_API_KEY or '' +config.slackToken = process.env.COCO_SLACK_TOKEN or '' + config.queue = accessKeyId: process.env.COCO_AWS_ACCESS_KEY_ID or '' secretAccessKey: process.env.COCO_AWS_SECRET_ACCESS_KEY or '' diff --git a/server_setup.coffee b/server_setup.coffee index 0c676664b..75a9ba6c5 100644 --- a/server_setup.coffee +++ b/server_setup.coffee @@ -16,7 +16,7 @@ config = require './server_config' auth = require './server/routes/auth' routes = require './server/routes' UserHandler = require './server/users/user_handler' -hipchat = require './server/hipchat' +slack = require './server/slack' Mandate = require './server/models/Mandate' global.tv4 = require 'tv4' # required for TreemaUtils to work global.jsondiffpatch = require 'jsondiffpatch' @@ -71,7 +71,7 @@ setupErrorMiddleware = (app) -> res.status(err.status ? 500).send(error: "Something went wrong!") message = "Express error: #{req.method} #{req.path}: #{err.message}" log.error "#{message}, stack: #{err.stack}" - hipchat.sendHipChatMessage(message, ['tower'], {papertrail: true}) + slack.sendSlackMessage(message, ['tower'], {papertrail: true}) else next(err) diff --git a/spec/server/functional/article.spec.coffee b/spec/server/functional/article.spec.coffee index f450ffa37..fed443726 100644 --- a/spec/server/functional/article.spec.coffee +++ b/spec/server/functional/article.spec.coffee @@ -468,11 +468,11 @@ describe 'POST /db/article/:handle/new-version', -> yield postNewVersion({ name: 'Article name', body: 'New body', commitMessage: 'Commit message' }) - it 'sends a notification to artisan and main HipChat channels', utils.wrap (done) -> - hipchat = require '../../../server/hipchat' - spyOn(hipchat, 'sendHipChatMessage') + it 'sends a notification to artisan and main Slack channels', utils.wrap (done) -> + slack = require '../../../server/slack' + spyOn(slack, 'sendSlackMessage') yield postNewVersion({ name: 'Article name', body: 'New body' }) - expect(hipchat.sendHipChatMessage).toHaveBeenCalled() + expect(slack.sendSlackMessage).toHaveBeenCalled() done() describe 'version fetching endpoints', ->