@lukekarrys/entry-watcher
Version:
Entry watcher for bracket.club
130 lines (109 loc) • 3.46 kB
JavaScript
'use strict'
const async = require('async')
const bucker = require('bucker')
const moment = require('moment')
const _ = require('lodash')
const BracketFinder = require('bracket-finder')
const Locks = require('./locks')
const ENTRY_TYPES = {
tweet: {
dateFormat: 'ddd MMM DD HH:mm:ss ZZ YYYY',
entry: (data) => ({
created: data.created_at,
user_id: data.user.id_str,
data_id: data.id_str,
username: data.user.screen_name,
name: data.user.name,
profile_pic: data.user.profile_image_url,
link: `${data.user.screen_name}/${data.id_str}`
}),
validate: (entry, cb) => {
if (entry.hasOwnProperty('retweeted_status')) {
return cb(new Error('Tweet is a retweet'))
}
return cb(null)
}
}
}
class Entry {
constructor (options) {
if (options.tweet) {
this.type = 'tweet'
this.entry = ENTRY_TYPES[this.type].entry(options.tweet)
this.originalData = options.tweet
}
_.defaults(options, {
finder: new BracketFinder(_.pick(options, 'sport', 'year', 'domain', 'tags')),
logger: bucker.createNullLogger(),
locks: new Locks({year: options.year, sport: options.sport}),
onSave () {},
onError () {}
})
_.extend(this, _.pick(options, 'getId', 'logger', 'finder', 'save', 'locks', 'onSave', 'onError'))
if (!this.entry) {
throw new Error('Cant create an entry without data')
}
this.logger.info('[ENTRY]', JSON.stringify({
original_data: this.originalData,
entry: this.entry
}))
this.save()
}
// -----------------------
// Validation
// -----------------------
typeValidation (cb) {
ENTRY_TYPES[this.type].validate(this.originalData, cb)
}
isOnTime (cb) {
if (moment(this.entry.created, ENTRY_TYPES[this.type].dateFormat).isBefore(this.locks.moment())) {
return cb(null)
}
return cb(new Error('Entry is outside of the allotted time'))
}
hasBracket (cb) {
const entryError = () => new Error(`${this.type} does not contain a bracket: ${this.entry.link}`)
this.finder[this.type](this.originalData, (err, result) => {
// Refetch tweet in case of an error that could be because the tweet was truncated
if (err && this.originalData.truncated && this.getId) {
return this.getId(this.entry.data_id, (getIdErr, fullTweet) => {
if (getIdErr) {
this.logger.error('[GET ID ERROR]', getIdErr.message)
return cb(entryError())
}
this.logger.info('[GET ID]', JSON.stringify(fullTweet))
this.originalData = fullTweet
this.originalData.truncated = false
return this.hasBracket(cb)
})
}
if (err) {
return cb(entryError())
}
return cb(null, result)
})
}
isValid (cb) {
async.series([
this.typeValidation.bind(this),
this.isOnTime.bind(this),
this.hasBracket.bind(this)
], (err, result) => cb(err, result && result[2]))
}
// -----------------------
// Saving
// -----------------------
save () {
this.isValid((err, bracket) => {
if (err) {
this.logger.error('[VALIDATION]', err.message)
this.onError(err)
} else {
this.entry.bracket = bracket
this.logger.info('[SAVE]', JSON.stringify(_.pick(this.entry, 'username', 'bracket')))
this.onSave(this.entry)
}
})
}
}
module.exports = Entry