Basic email structure plus distributed locking system

This commit is contained in:
Michael Schmatz 2014-07-09 16:24:14 -07:00
parent d22e8dbde1
commit 013ace65f6
10 changed files with 128 additions and 1 deletions

View file

@ -0,0 +1,16 @@
c = require './../schemas'
#This will represent transactional emails which have been sent
MailSentSchema = c.object {
title: 'Sent mail'
description: 'Emails which have been sent through the system'
}
_.extend MailSentSchema.properties,
mailTask: c.objectId {}
user: c.objectId links: [{rel: 'extra', href: '/db/user/{($)}'}]
sent: c.date title: 'Sent', readOnly: true
c.extendBasicProperties MailSentSchema, 'mail.sent'
module.exports = MailSentSchema

View file

@ -0,0 +1,21 @@
c = require './../schemas'
#This will represent transactional emails which have been sent
MailTaskSchema = c.object {
title: 'Mail task'
description: 'Mail tasks to call at certain intervals'
}
_.extend MailTaskSchema.properties,
url:
title: 'URL'
description: 'The associated URL of the mailtask to call'
type: 'string'
frequency:
title: 'Frequency'
description: 'The number of seconds the servers should check whether or not to send the email'
type: 'integer'
c.extendBasicProperties MailTaskSchema, 'mail.task'
module.exports = MailTaskSchema

View file

@ -0,0 +1,24 @@
config = require '../../server_config'
redis = require 'redis'
class LockManager
constructor: ->
unless config.isProduction or config.redis.host isnt "localhost"
throw "You shouldn't be instantiating distributed locks unless in production."
@redisClient = redis.createClient config.redis.port, config.redis.host
@lockValues = {}
@unlockScript = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then return redis.call(\"del\",KEYS[1]) else return 0 end"
setLock: (lockName, timeoutMs, cb) =>
randomNumber = Math.floor(Math.random() * 1000000000)
@redisClient.set [lockName,randomNumber, "NX", "PX", timeoutMs], (err, res) ->
if err? then return cb err, null
@lockValues[lockName] = randomNumber
cb null, res
releaseLock: (lockName, cb) =>
@redisClient.eval [@unlockScript, 1, lockName, @lockValues[lockName]], (err, res) ->
if err? then return cb err, null
#1 represents success, 0 failure
cb null, Boolean(Number(res))
module.exports = new RedisLock()

View file

@ -9,6 +9,8 @@ module.exports.handlers =
'thang_type': 'levels/thangs/thang_type_handler' 'thang_type': 'levels/thangs/thang_type_handler'
'user': 'users/user_handler' 'user': 'users/user_handler'
'user_remark': 'users/remarks/user_remark_handler' 'user_remark': 'users/remarks/user_remark_handler'
'mail_task': 'mail/tasks/mail_task_handler'
'mail_sent': 'mail/sent/mail_sent_handler'
'achievement': 'achievements/achievement_handler' 'achievement': 'achievements/achievement_handler'
'earned_achievement': 'achievements/earned_achievement_handler' 'earned_achievement': 'achievements/earned_achievement_handler'

View file

@ -0,0 +1,11 @@
mongoose = require 'mongoose'
plugins = require '../../plugins/plugins'
jsonschema = require '../../../app/schemas/models/mail_sent'
MailSent = new mongoose.Schema({
sent:
type: Date
'default': Date.now
}, {strict: false})
module.exports = MailSent = mongoose.model('mailSent', MailSent)

View file

@ -0,0 +1,12 @@
MailSent = require './MailSent'
Handler = require '../../commons/Handler'
class MailSentHandler extends Handler
modelClass: MailSent
editableProperties: ['mailTask','user','sent']
jsonSchema: require '../../../app/schemas/models/mail_sent'
hasAccess: (req) ->
req.user?.isAdmin()
module.exports = new MailSentHandler()

View file

@ -0,0 +1,7 @@
mongoose = require 'mongoose'
plugins = require '../../plugins/plugins'
jsonschema = require '../../../app/schemas/models/mail_task'
MailTaskSchema = new mongoose.Schema({}, {strict: false})
module.exports = MailTask = mongoose.model('mail.task', MailTaskSchema)

View file

@ -0,0 +1,12 @@
MailTask = require './MailTask'
Handler = require '../../commons/Handler'
class MailTaskHandler extends Handler
modelClass: MailTask
editableProperties: ['url','frequency']
jsonSchema: require '../../../app/schemas/models/mail_task'
hasAccess: (req) ->
req.user?.isAdmin()
module.exports = new MailTaskHandler()

View file

@ -1,4 +1,5 @@
mail = require '../commons/mail' mail = require '../commons/mail'
MailTask = require '../mail/tasks/MailTask'
User = require '../users/User' User = require '../users/User'
errors = require '../commons/errors' errors = require '../commons/errors'
config = require '../../server_config' config = require '../../server_config'
@ -6,11 +7,16 @@ LevelSession = require '../levels/sessions/LevelSession'
Level = require '../levels/Level' Level = require '../levels/Level'
log = require 'winston' log = require 'winston'
sendwithus = require '../sendwithus' sendwithus = require '../sendwithus'
if config.isProduction || true
redis = require 'redis'
redisClient = redis.createClient(config.redis.port,config.redis.host)
module.exports.setup = (app) -> module.exports.setup = (app) ->
app.all config.mail.mailchimpWebhook, handleMailchimpWebHook app.all config.mail.mailchimpWebhook, handleMailchimpWebHook
app.get '/mail/cron/ladder-update', handleLadderUpdate app.get '/mail/cron/ladder-update', handleLadderUpdate
app.post '/mail/task', createMailTask
#setInterval(handleScheduledMail, 5000)
DEBUGGING = false DEBUGGING = false
@ -28,6 +34,18 @@ isRequestFromDesignatedCronHandler = (req, res) ->
return false return false
return true return true
createMailTask = (req, res) ->
#unless req.user?.isAdmin() then return errors.forbidden(res)
unless req.body.url and req.body.frequency then return errors.badInput(res)
console.log "Creating mail task with url #{req.body.url} and frequency #{req.body.frequency}"
newMailTask = new MailTask {}
newMailTask.set("url",req.body.url)
newMailTask.set("frequency",req.body.frequency)
newMailTask.save (err) ->
if err? then return errors.serverError(res, err)
res.send("Created mail task!")
res.end()
handleLadderUpdate = (req, res) -> handleLadderUpdate = (req, res) ->
log.info('Going to see about sending ladder update emails.') log.info('Going to see about sending ladder update emails.')
requestIsFromDesignatedCronHandler = isRequestFromDesignatedCronHandler req, res requestIsFromDesignatedCronHandler = isRequestFromDesignatedCronHandler req, res

View file

@ -12,6 +12,10 @@ config.mongo =
host: process.env.COCO_MONGO_HOST or 'localhost' host: process.env.COCO_MONGO_HOST or 'localhost'
db: process.env.COCO_MONGO_DATABASE_NAME or 'coco' db: process.env.COCO_MONGO_DATABASE_NAME or 'coco'
mongoose_replica_string: process.env.COCO_MONGO_MONGOOSE_REPLICA_STRING or '' mongoose_replica_string: process.env.COCO_MONGO_MONGOOSE_REPLICA_STRING or ''
config.redis =
port: process.env.COCO_REDIS_PORT or 6379
host: process.env.COCO_REDIS_HOST or 'localhost'
if config.unittest if config.unittest
config.port += 1 config.port += 1