Created
January 22, 2014 23:41
-
-
Save ndreckshage/8569869 to your computer and use it in GitHub Desktop.
snapsecret v3 (node + ember, not all code included)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(-> | |
Ember = require 'ember' | |
moment = require 'moment' | |
# Socket.io | |
io = window.io | |
host = location.origin.replace /^http/, 'ws' | |
socket = io.connect host | |
# SnapSecret | |
window.SnapSecret = SnapSecret = Ember.Application.create() | |
# Controllers | |
require('./controllers/application_controller.coffee')(SnapSecret, socket) | |
require('./controllers/index_controller.coffee')(SnapSecret, socket) | |
require('./controllers/confess_controller.coffee')(SnapSecret, socket, moment) | |
# Views | |
require('./views/application_view.coffee')(SnapSecret) | |
require('./views/commentable_button_view.coffee')(SnapSecret) | |
require('./views/blow_the_whistle_button_view.coffee')(SnapSecret) | |
# Helpers | |
require('./helpers/moment_helper.coffee')(Ember, moment) | |
# Templates | |
require './templates.js' | |
# Routes | |
require('./router.coffee')(SnapSecret) | |
require('./routes/index_route.coffee')(SnapSecret) | |
require('./routes/confess_route.coffee')(SnapSecret) | |
)() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module.exports = (SnapSecret, socket) -> | |
SnapSecret.ApplicationController = Ember.Controller.extend | |
needs: ['index', 'confess'] | |
defaultCountdown: 60 | |
countdownWarning: false | |
indexRoute: false | |
confessRoute: false | |
activeSecret: false | |
failureMessage: null | |
successMessage: null | |
stats: | |
showStats: false | |
totalSpilled: 0 | |
totalRead: 0 | |
countdown: 60 | |
init: () -> | |
if window.activeExpiry and window.activeSecret | |
@set 'countdown', window.activeExpiry | |
@set 'activeSecret', true | |
@startTheClock() | |
if window.secretStats | |
@set('stats.totalSpilled', window.secretStats.totalSpilled) \ | |
if window.secretStats.totalSpilled | |
@set('stats.totalRead', window.secretStats.totalRead) \ | |
if window.secretStats.totalRead | |
@setShowStats() | |
@initIO() | |
initIO: () -> | |
indexController = @get 'controllers.index' | |
socket.on 'spill secret', (data) => | |
if @get 'activeSecret' | |
indexController.send 'addToQueue', data | |
else | |
@send 'newSecret', data | |
indexController.send 'activateSecret', data | |
indexController.set 'waitingMessage', false | |
socket.on 'comment added', (data) => | |
indexController.send 'commentAdded', data | |
setShowStats: (() -> | |
if @get('stats.totalSpilled') > 10 and @get('stats.totalRead') > 10 | |
@set 'stats.showStats', true | |
else | |
@set 'stats.showStats', false | |
).observes('stats.totalSpilled', 'stats.totalRead') | |
flash: (message, type = 'error') -> | |
# console.log 'hit' | |
if type is 'error' \ | |
then @set 'failureMessage', message \ | |
else @set 'successMessage', message | |
flashClear: () -> | |
@set 'successMessage', null | |
@set 'failureMessage', null | |
startTheClock: () -> | |
@countdownInterval = setInterval $.proxy(@contentCountdown, @), 1000 | |
reset: () -> | |
clearInterval @countdownInterval | |
@set 'countdown', @defaultCountdown | |
@set 'activeSecret', false | |
contentCountdown: () -> | |
indexController = @get 'controllers.index' | |
indexController.set 'waitingMessage', false | |
counter = @get 'countdown' | |
counter-- | |
@set 'countdown', counter | |
if counter is 0 | |
@reset() | |
# TODO - implement confirmation behavior | |
indexController.send 'nextInQueue' | |
warnAtTen: (() -> | |
if @countdown <= 10 | |
@set 'countdownWarning', true | |
else if @countdown > 10 | |
@set 'countdownWarning', false | |
).observes('countdown') | |
actions: | |
newSecret: (data) -> | |
@set 'activeSecret', true | |
currentSpilled = @get 'stats.totalSpilled' | |
# console.log 'applicationController', '@actions.newSecret', data | |
newSpilled = currentSpilled += data.view_count | |
@set 'stats.totalSpilled', newSpilled | |
currentRead = @get 'stats.totalRead' | |
@set 'stats.totalRead', ++currentRead | |
@startTheClock() | |
navigateHome: () -> | |
@transitionToRoute 'index' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module.exports = (SnapSecret, socket, moment) -> | |
SnapSecret.ConfessController = Ember.Controller.extend | |
needs: ['application', 'index'] | |
init: () -> | |
# console.log 'confess', 'secretTimes', window.secretTimes | |
@get('secret.spilled').pushObjects window.secretTimes \ | |
if window.secretTimes | |
@initIO() | |
initIO: () -> | |
socket.on 'create secret response', (data) => | |
# if no errors | |
# console.log 'confessController', '@initIO', 'response data', data | |
@transitionToRoute 'index' | |
if data == 0 | |
@get('controllers.index').send 'queueFlash', \ | |
"your secret is safe with us.", \ | |
'success' | |
else | |
@get('controllers.index').send 'queueFlash', \ | |
"your secret is set to spill " + \ | |
"#{moment().add('minutes', data).fromNow()}", \ | |
'success' | |
@set 'message.value', '' | |
@set 'inFlight', false | |
# console.log 'confess io response', 'before', @get('secret.spilled') | |
@get('secret.spilled').pushObject Date.now() | |
# console.log 'confess io response', 'after', @get('secret.spilled') | |
disableForm: (() -> | |
@get('inFlight') or @get('secret.inValid') | |
).property('inFlight', 'secret.inValid') | |
inFlight: false | |
secret: | |
maxPerHour: 2 | |
inValid: false | |
spilled: Ember.A() | |
updateSecretCount: () -> | |
# console.log 'confess', 'updateSecretCount', \ | |
# 'before', @get('secret.spilled') | |
@set 'secret.spilled', @get('secret.spilled').filter (item) -> | |
Date.now() - item <= 60 * 60 * 1000 | |
# console.log 'confess', 'updateSecretCount', \ | |
# 'after', @get('secret.spilled') | |
secretValidate: (() -> | |
# console.log 'confess', 'secretValidate', \ | |
# 'called', @get('secret.spilled').length, @get 'secret.maxPerHour' | |
applicationController = @get('controllers.application') | |
if @get('secret.spilled').length >= @get 'secret.maxPerHour' | |
@set 'secret.inValid', true | |
applicationController.flash "easy there, snowden. " + \ | |
"#{@get('secret.maxPerHour')} secrets per hour." | |
false | |
else | |
@set 'secret.inValid', false | |
applicationController.flashClear() | |
true | |
# console.log 'confess', 'secretValidate', @get 'secret.inValid' | |
).observes 'secret.spilled.@each' | |
commentable: true | |
commentableCurrent: (() -> | |
if @get('commentable') then 'on' else 'off' | |
).property('commentable') | |
name: '' | |
location: '' | |
message: | |
value : '' | |
minWords : 10 | |
maxWords : 500 | |
valid : false | |
error : null | |
messageValidate: (() -> | |
message = @get('message.value') | |
wordCount = (message.match(/\S+/g) || []).length | |
minWords = @get 'message.minWords' | |
maxWords = @get 'message.maxWords' | |
if maxWords >= wordCount >= minWords | |
@get('controllers.application').flashClear() | |
@set 'message.valid', true | |
@set 'message.error', null | |
true | |
else | |
error = if wordCount < minWords then \ | |
"a secret with less then #{minWords} words is hardly a secret." else \ | |
"#{maxWords} words max. this isnt wikileaks. " + \ | |
"(you entered #{wordCount})" | |
@set 'message.valid', false | |
@set 'message.error', error | |
false | |
).observes 'message.value' | |
actions: | |
toggleComments: () -> | |
if @get('commentable') is on \ | |
then @set('commentable', off) \ | |
else @set('commentable', on) | |
confessSecret: () -> | |
# console.log 'confessSecret', 'action', @get('secret.inValid') | |
unless @get('secret.inValid') | |
@messageValidate() | |
if @get 'message.valid' | |
@set 'inFlight', true | |
socket.emit 'create secret', | |
ip_address: window.staticIP | |
message: @get('message.value') | |
commentable: @get('commentable') | |
location: @get('location') | |
name: @get('name') | |
else | |
@get('controllers.application').flash @get 'message.error' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module.exports = (SnapSecret, socket) -> | |
SnapSecret.IndexController = Ember.ObjectController.extend | |
needs: ['application'] | |
queue: Ember.A() | |
queueFlash: | |
message: null | |
type: null | |
comments: Ember.A() | |
commentable: false | |
commentsEnabled: true | |
showComments: false | |
waitingMessage: false | |
secretsRead: 0 | |
nsaCheck: false | |
comment: | |
maxCount: 1 | |
valid: true | |
inValid: false | |
count: 0 | |
value: '' | |
init: () -> | |
secret = window.activeSecret | |
@set 'content', secret: secret if secret | |
if window.activeCommentCount | |
@set('comment.count', window.activeCommentCount) | |
if secret and secret.comments | |
secret.comments.forEach (comment) => | |
@comments.pushObject comment | |
@comments.reverse() | |
@setCommentable() | |
@commentValidate() | |
@commentInvalid() | |
@setShowComments() | |
commentInvalid: (() -> | |
if @get('comment.valid') | |
@set('comment.inValid', false) | |
else | |
@set('comment.inValid', true) | |
).observes('comment.valid') | |
setNSACheck: (() -> | |
secretsRead = @get 'secretsRead' | |
if secretsRead % 5 == 0 | |
@set 'nsaCheck', true | |
else | |
@set 'nsaCheck', false | |
).observes('secretsRead') | |
setShowComments: (() -> | |
commentable = @get 'commentable' | |
# console.log 'indexController', '@setShowComments', \ | |
# '#commentable', commentable | |
commentsEnabled = @get 'commentsEnabled' | |
# console.log 'indexController', '@setShowComments', \ | |
# '#commentsEnabled', commentsEnabled | |
showComments = commentable and commentsEnabled | |
# console.log 'indexController', '@setShowComments', \ | |
# '#showComments', showComments | |
@set 'showComments', showComments | |
).observes('commentable', 'commentsEnabled') | |
setCommentable: (() -> | |
commentable = @get('content.secret.commentable') | |
# console.log 'indexController', '@setCommentable', commentable | |
@set('commentable', commentable) | |
).observes('content.secret.commentable') | |
commentValidate: (() -> | |
if @get('comment.count') < @get('comment.maxCount') | |
@set('comment.valid', true) | |
else | |
@set('comment.valid', false) | |
).observes('comment.count') | |
_clearSecretSwitch: () -> | |
# console.log 'indexController', '@_clearSecretSwitch' | |
@set 'waitingMessage', false | |
clearTimeout @noSecretTimeout if @noSecretTimeout | |
_noSecretSwitch: () -> | |
# console.log 'indexController', '@_noSecretSwitch', 'called' | |
unless @get('controllers.application').get 'activeSecret' | |
# console.log 'indexController', '@_noSecretSwitch', 'waiting' | |
@noSecretTimeout = setTimeout () => | |
# console.log 'indexController', '@_noSecretSwitch', 'active' | |
@set 'waitingMessage', true | |
, 3000 | |
clearContent: () -> | |
# console.log 'indexController', '@clearContent' | |
@set 'content', null | |
@_noSecretSwitch() | |
actions: | |
queueFlash: (message, type = 'error') -> | |
@set 'queueFlash.message', message | |
@set 'queueFlash.type', type | |
addToQueue: (secret) -> | |
@queue.pushObject secret: secret | |
activateSecret: (secret) -> | |
@set 'content', secret: secret | |
secretsRead = @get 'secretsRead' | |
# console.log 'indexController', '@actions.activeSecret', \ | |
# '#secretsRead', secretsRead | |
@set 'secretsRead', ++secretsRead | |
# console.log '@activeSecret', 'active' | |
commentAdded: (comment) -> | |
@comments.unshiftObject comment | |
nextInQueue: () -> | |
applicationController = @get 'controllers.application' | |
secret = @queue.shiftObject() | |
if secret | |
content = secret | |
applicationController.send('newSecret', secret) if secret | |
# console.log '@nextInQueue', 'secret active' | |
else | |
content = null | |
@_noSecretSwitch() | |
# console.log '@nextInQueue', 'no secrets' | |
@set 'content', content | |
addComment: () -> | |
@commentValidate() | |
if @get('comment.valid') | |
socket.emit 'add comment', | |
ip_address: window.staticIP | |
message: @get('comment.value') | |
belongsTo: null | |
@set('comment.value', '') | |
count = @get('comment.count') | |
@set('comment.count', ++count) | |
toggleComments: () -> | |
if @get('commentsEnabled') \ | |
then @set('commentsEnabled', false) \ | |
else @set('commentsEnabled', true) | |
reportSecret: () -> | |
socket.emit 'report secret' | |
applicationController = @get 'controllers.application' | |
applicationController.send 'flash', 'Thanks! -- The NSA', 'success' | |
applicationController.send 'reset' | |
@clearContent() | |
clearSecretSwitch: () -> @_clearSecretSwitch() | |
noSecretSwitch: () -> @_noSecretSwitch() | |
confirmNSA: () -> | |
# console.log 'indexController', '@actions.confirmNSA', 'hit' | |
window.location.href = "http://www.whitehouse.gov/" + \ | |
"our-government/the-constitution" | |
confirmNotNSA: () -> | |
# console.log 'indexController', '@actions.confirmNotNSA', 'hit' | |
@set 'nsaCheck', false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module.exports = (SnapSecret) -> | |
SnapSecret.ConfessRoute = Ember.Route.extend | |
model: () -> {} | |
activate: () -> | |
@controllerFor('application').set 'confessRoute', true | |
# console.log 'confess route', 'update count' | |
@controllerFor('confess').updateSecretCount() | |
deactivate: () -> | |
applicationController = @controllerFor('application') | |
applicationController.set 'confessRoute', false | |
applicationController.flashClear() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module.exports = (SnapSecret) -> | |
SnapSecret.IndexRoute = Ember.Route.extend | |
activate: () -> | |
indexController = @controllerFor 'index' | |
applicationController = @controllerFor 'application' | |
# console.log 'here' | |
queueFlash = indexController.get 'queueFlash' | |
# console.log queueFlash | |
if queueFlash.message and queueFlash.type | |
applicationController.send 'flash', queueFlash.message, queueFlash.type | |
indexController.set 'queueFlash.message', null | |
indexController.set 'queueFlash.type', null | |
applicationController.set 'indexRoute', true | |
indexController.send 'noSecretSwitch' | |
deactivate: () -> | |
@controllerFor('application').set 'indexRoute', false | |
@controllerFor('index').send 'clearSecretSwitch' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module.exports = (SnapSecret) -> | |
SnapSecret.Router.map () -> | |
@route 'read' | |
@route 'confess' | |
@route 'what' | |
@route 'terms' | |
@route 'privacy' | |
@route 'use' | |
if window.history and window.history.pushState | |
SnapSecret.Router.reopen | |
location: 'history' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module.exports = (SnapSecret) -> | |
SnapSecret.BlowTheWhistleButton = Ember.View.extend | |
tagName: 'a' | |
classNames: ['btn', 'btn-default', 'show-comments-btn'] | |
click: () -> | |
@get('controller').send 'reportSecret' | |
didInsertElement: () -> | |
$(@get('element')).tooltip | |
title: 'report if the secret is abusive, etc.' | |
placement: 'right' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class API | |
constructor: (Secret, expiry = 60) -> | |
@Secret = Secret | |
@DEFAULT_COUNTER = expiry | |
@activeExpiry = @DEFAULT_COUNTER | |
@activeSecret = null | |
@totalRead = 0 | |
@totalSpilled = 0 | |
@initSecretStats() | |
API::initSecretStats = () -> | |
@Secret.count | |
displayed: true | |
, (error, count) => | |
unless error | |
@totalSpilled = count | |
@Secret.find | |
displayed: true | |
, (error, secrets) => | |
unless error | |
totalRead = 0 | |
secrets.forEach (secret) => | |
totalRead += secret.view_count | |
@totalRead = totalRead | |
API::initIO = (io) -> | |
io.on "connection", (socket) => | |
socket.on "create secret", (reqIO) => | |
reqIO.view_count = io.sockets.clients().length | |
@_createSecret reqIO, socket, () => | |
# When this callback is called, activesecret send to sockets | |
@totalRead += @activeSecret.view_count | |
@totalSpilled += 1 | |
io.sockets.emit "spill secret", @_serializeSecret() | |
socket.on 'add comment', (reqIO) => | |
@_addComment reqIO, socket, (comment) => | |
io.sockets.emit "comment added", @_serializeComment comment | |
socket.on 'report secret', () => @_reportSecret() | |
API::getActiveSecret = () -> | |
if @activeSecret then @_serializeSecret() else null | |
API::getActiveExpiry = () -> | |
if @activeSecret then @activeExpiry else null | |
API::getActiveCommentCount = (ip_address) -> | |
if @activeSecret | |
comments = @activeSecret.comments.filter (comment) -> | |
comment.ip_address == ip_address | |
comments.length | |
else | |
0 | |
API::getSecretStats = () -> | |
totalRead: @totalRead | |
totalSpilled: @totalSpilled | |
API::_serializeSecret = () -> | |
if @activeSecret | |
id: @activeSecret.id | |
message: @activeSecret.message | |
view_count: @activeSecret.view_count | |
queue_estimate: @activeSecret.queue_estimate | |
commentable: @activeSecret.commentable | |
comments: @activeSecret.comments.map (comment) => | |
@_serializeComment comment | |
name: if @activeSecret.name \ | |
then @activeSecret.name \ | |
else null | |
location: if @activeSecret.location \ | |
then @activeSecret.location \ | |
else null | |
API::_serializeComment = (comment) -> | |
if comment | |
id: comment.id | |
message: comment.message | |
orignal_poster: comment.orignal_poster | |
timestamp: comment.date | |
API::_reset = () -> | |
@activeSecret = null | |
@activeExpiry = @DEFAULT_COUNTER | |
API::_createSecret = (reqIO, socket, resIO) -> | |
secret = new @Secret | |
message: reqIO.message | |
ip_address: reqIO.ip_address | |
view_count: reqIO.view_count | |
name: reqIO.name | |
location: reqIO.location | |
commentable: reqIO.commentable | |
secret.save (error) => | |
unless error | |
@Secret.count | |
displayed: false | |
, (error, count) => | |
unless error | |
unless @activeSecret | |
@_spillSecret secret, resIO | |
response = 0 | |
else | |
response = --count | |
# Give the secret spiller some info about their secret. | |
socket.emit 'create secret response', response | |
API::_spillSecret = (instance, resIO) -> | |
@activeSecret = instance | |
@_startTheClock(resIO) | |
resIO() | |
API::_startTheClock = (resIO) -> | |
interval = setInterval () => | |
console.log @activeExpiry | |
if @activeExpiry is 0 | |
clearInterval interval | |
@_expireSecret(resIO) | |
else | |
@activeExpiry-- | |
, 1000 | |
API::_reportSecret = () -> | |
@Secret.findOne | |
_id: @activeSecret.id | |
, (error, secret) => | |
unless error | |
reports = secret.reports | |
secret.reports = ++reports | |
secret.save | |
API::_expireSecret = (resIO) -> | |
@Secret.findOneAndUpdate | |
_id: @activeSecret.id | |
, displayed: true | |
, {} | |
, (error) => | |
if error | |
@_reset() | |
else | |
@_kickTheQueue(resIO) | |
API::_kickTheQueue = (resIO) -> | |
@Secret.findOne | |
displayed: false | |
, (error, secret) => | |
@_reset() | |
unless error | |
if secret | |
@_spillSecret secret, resIO | |
API::_addComment = (reqIO, socket, resIO) -> | |
secret = @activeSecret | |
comment = | |
message: reqIO.message | |
ip_address: reqIO.ip_address | |
secret.comments.push comment | |
secret.save (error) => | |
unless error | |
resIO comment | |
module.exports = () -> API |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
express = require 'express' | |
http = require 'http' | |
path = require 'path' | |
app = express() | |
mongoose = require 'mongoose' | |
if app.get('env') is 'development' | |
mongoose.connect 'mongodb://localhost/snapsecret' | |
else | |
mongoose.connect process.env.MONGOHQ_URL | |
db = mongoose.connection | |
db.on 'error', console.error.bind(console, 'connection error:') | |
db.once 'open', () -> | |
console.log 'DB CONNECTION' | |
app.set 'port', process.env.PORT || 3000 | |
app.set 'views', path.join(__dirname, '../', 'views') | |
app.set 'view engine', 'jade' | |
app.set 'trust proxy', true | |
app.use express.favicon() | |
app.use express.logger('dev') | |
app.use express.json() | |
app.use express.urlencoded() | |
app.use express.methodOverride() | |
app.use app.router | |
app.use express.static(path.join(__dirname, '../', 'public')) | |
if app.get('env') is 'development' | |
app.use express.errorHandler() | |
server = http.createServer app | |
io = require('socket.io').listen server | |
Secret = require('./models')('secret')() | |
API = require('./api')() | |
api = new API(Secret) | |
api.initIO io | |
indexRoute = (req, res) -> | |
Secret.find | |
ip_address: req.ip | |
created_at: | |
$gte: new Date Date.now() - 60 * 60 * 1000 | |
, (error, secrets) -> | |
secretTimes = [] | |
if error | |
console.log "Failed to get secrets, #{error}" | |
else | |
secrets.forEach (secret) -> | |
secretTimes.push secret.created_at.getTime() | |
res.render 'index', | |
title: 'snapsecret' | |
activeSecret: JSON.stringify api.getActiveSecret() | |
activeCommentCount: JSON.stringify api.getActiveCommentCount(req.ip) | |
activeExpiry: JSON.stringify api.getActiveExpiry() | |
secretTimes: JSON.stringify secretTimes | |
secretStats: JSON.stringify api.getSecretStats() | |
staticIP: JSON.stringify req.ip | |
# Ember Routes (to work with History API) | |
app.get '/', indexRoute | |
app.get '/read', indexRoute | |
app.get '/confess', indexRoute | |
app.get '/what', indexRoute | |
app.get '/terms', indexRoute | |
app.get '/privacy', indexRoute | |
app.get '/use', indexRoute | |
server.listen app.get('port'), () -> | |
console.log "Express server listening on port #{app.get('port')}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
mongoose = require 'mongoose' | |
module.exports = () -> | |
Schema = mongoose.Schema | |
commentSchema = new Schema | |
message: | |
type: String | |
required: 'Comment needs a body' | |
date: | |
type: Date | |
default: Date.now | |
ip_address: | |
type: String | |
required: 'No IP' | |
orignal_poster: | |
type: Boolean | |
default: false | |
secretSchema = new Schema | |
message: | |
type: String | |
required: 'Whoops' | |
ip_address: | |
type: String | |
required: 'No IP' | |
commentable: | |
type: Boolean | |
default: true | |
displayed: | |
type: Boolean | |
default: false | |
view_count: | |
type: Number | |
default: 0 | |
created_at: | |
type: Date | |
default: Date.now | |
reports: | |
type: Number | |
default: 0 | |
name: String | |
location: String | |
queue_estimate: Number | |
comments: [commentSchema] | |
Secret = mongoose.model 'Secret', secretSchema | |
# Validate 2 secrets per hour | |
# Secret.schema.path('ip_address').validate (value, respond) -> | |
# Secret.find | |
# ip_address: value | |
# created_at: | |
# $gte: new Date Date.now() - 60 * 60 * 1000 | |
# , (error, secrets) -> | |
# if error | |
# console.log "Failed to get secrets, #{error}" | |
# respond false | |
# else | |
# respond secrets.length < 2 | |
# , 'easy there, snowden. 2 secrets per hour' | |
Secret |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
doctype 5 | |
html | |
head | |
title= title | |
link(rel='stylesheet', href='/stylesheets/application.css') | |
script(src='/socket.io/socket.io.js') | |
script(type='text/javascript', src='/javascripts/application.js') | |
script(type='text/javascript')!= | |
window.activeSecret = !{activeSecret}; | |
window.activeExpiry = !{activeExpiry}; | |
window.secretTimes = !{secretTimes}; | |
window.activeCommentCount = !{activeCommentCount}; | |
window.secretStats = !{secretStats}; | |
window.staticIP = !{staticIP}; | |
body |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment