Skip to content

Instantly share code, notes, and snippets.

@ndreckshage
Last active January 4, 2016 04:39
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ndreckshage/8569553 to your computer and use it in GitHub Desktop.
Save ndreckshage/8569553 to your computer and use it in GitHub Desktop.
snapsecret v2 (not everything included...)
window.SnapSecret.ApplicationController = Ember.Controller.extend
countdownWarning: false
countdown: 60
stats:
totalRead: if !!window.secretStats and !!window.secretStats.totalRead then window.secretStats.totalRead else null
totalSpilled: if !!window.secretStats and !!window.secretStats.totalSpilled then window.secretStats.totalSpilled else null
warnAtTen: (() ->
if @countdown == 10
@set 'countdownWarning', true
else if @countdown > 10
@set 'countdownWarning', false
).observes('countdown')
<div class="clearfix">
<form accept-charset="UTF-8" action="/confess" class="new_secret" id="new_secret" method="post" role="form" {{bind-attr class="previewMarkdown"}} >
<div class="form-group">
{{view Ember.TextArea valueBinding="message" rows="5" placeholder="submit a secret..." class="form-control"}}
</div>
<input type="submit" class="btn btn-default" value="confess" {{action confessSecret}}>
{{#if previewMarkdown}}
<button class="btn btn-default" {{action hideMarkdown}}>hide preview</button>
{{/if}}
</form>
{{#if previewMarkdown}}
<div class="preview-container">
<div class="preview-markdown">
{{#if message}}
{{message}}
{{else}}
<p><i>start typing in the left box...</i></p>
{{/if}}
</div>
<button class="btn btn-link markdown-supported" {{action markdownLink}}>markdown supported</button>
</div>
{{/if}}
</div>
window.SnapSecret.ConfessController = Ember.ObjectController.extend
needs: ['index', 'messages']
message: ''
validate: () ->
message = @get('message') || ''
wordCount = (message.match(/\S+/g) || []).length
if 500 >= wordCount >= 10
@set 'isValid', true
@get('controllers.messages').set('failureMessages', [])
else
@set 'isValid', false
error = if wordCount < 10 then "a secret with less then 10 words is hardly a secret." else "500 words max. this isnt wikileaks. (you entered #{wordCount})"
@get('controllers.messages').set('failureMessages', [error])
formatTime: (time_in_minutes) ->
time_in_minutes = 1 if time_in_minutes is 0
hours = Math.floor(time_in_minutes / 60)
minutes = time_in_minutes % 60
message = ""
if hours > 0
message += "#{hours} hour"
message += "s" unless hours is 1
if minutes > 0
message += " and " unless hours is 0
message += "#{minutes} minute"
message += "s" unless minutes is 1
message
handleErrors: (model) ->
if model.errors
if model.errors.message and model.errors.tooManySecrets
errors = $.merge(model.errors.message, model.errors.tooManySecrets)
else if model.errors.message
errors = model.errors.message
else if model.errors.tooManySecrets
errors = model.errors.tooManySecrets
@get('controllers.messages').set 'failureMessages', errors
handleSuccess: (model) ->
@set 'message', ''
data = model.get('data')
queued_secrets = data.queue_estimate
queued_minutes = @formatTime(queued_secrets)
secrets = if queued_secrets is 1 then "secret" else "secrets"
if queued_secrets is 0 and @get('controllers.index').get('model.secret.message') is null
@get('controllers.messages').set 'successMessage', "Spilling your secret as we speak..."
window.activeSecret = { secret: data }
else
@get('controllers.messages').set 'successMessage', "Secret set to be spilled in #{queued_minutes}, after #{queued_secrets} #{secrets}."
@transitionToRoute('index')
actions:
confessSecret: () ->
@validate()
if @get 'isValid'
@store.createRecord('secret', {
message: @get 'message'
}).save().then ((model) => @handleSuccess model
), (model) => @handleErrors model
previewMarkdown: () ->
@set 'previewMarkdown', true
hideMarkdown: () ->
@set 'previewMarkdown', false
markdownLink: () ->
window.open('http://daringfireball.net/projects/markdown/')
window.SnapSecret.ConfessRoute = Ember.Route.extend
model: () -> {}
renderTemplate: (controller, model) ->
@controllerFor('messages').set('successMessage', null)
@render('messages', {
outlet: 'messages'
})
@render('confess')
{{#if secret}}
{{#if needsConfirmation}}
<p class="no-secrets">
<span>you've read {{secretsRead}} secrets, are you in the NSA?&nbsp;</span>
<button class="btn btn-default" {{action confirmNSA}}>yes</button>&nbsp;
<button class="btn btn-default" {{action confirmNotNSA}}>no</button>
</p>
{{else}}
{{#if fetchingSecret}}
<p class="no-secrets">secret sealed. getting the latest secret<span class="ellipses"></span></p>
{{else}}
{{#if secret.message}}
<div><p>{{secret.message}}</p></div>
<p class="no-secrets"><i>Seen by: {{secret.view_count}}</i></p>
{{else}}
<p class="no-secrets">
<span>all secrets sealed :(</span><br><br>
{{#link-to 'confess'}}leak one{{/link-to}}.
<a href="#" {{action checkAgain}}>check again</a>.
</p>
{{/if}}
{{/if}}
{{/if}}
{{/if}}
window.SnapSecret.IndexController = Ember.ObjectController.extend
needs: ['application', 'messages']
needsConfirmation: false
defaultCountdown: 60
defaultConfirm: 5
secretsSpilled: 1
secretsRead: 1
updateModel: () ->
@get('controllers.messages').set 'successMessage', null
window.SnapSecret.Secret.find().then (data) =>
_data = if data then data else { secret: { message: null }}
@set 'model', _data
@updateComplete()
updateComplete: () ->
@set 'fetchingSecret', false
application = @get('controllers.application')
application.set 'countdown', @get('defaultCountdown')
stats = @get 'secret.stats'
application.set('stats', stats) if stats
secretsSpilled = @get 'secretsSpilled'
@set 'secretsSpilled', ++secretsSpilled
secretsRead = @get 'secretsRead'
@set 'secretsRead', ++secretsRead
@countdownInterval = setInterval $.proxy(@contentCountdown, @), 1000
contentCountdown: () ->
application = @get('controllers.application')
counter = application.get('countdown')
counter--
application.set 'countdown', counter
if counter is 0
clearInterval @countdownInterval
if @get('secretsSpilled') >= @get('defaultConfirm')
@set 'needsConfirmation', true
else
@set 'fetchingSecret', true
@updateModel()
reset: () ->
clearInterval @countdownInterval
application = @get('controllers.application')
application.set 'countdown', @get('defaultCountdown')
@set 'secretsSpilled', 1
@set 'needsConfirmation', false
actions:
startTheClock: () ->
@countdownInterval = setInterval $.proxy(@contentCountdown, @), 1000
stopTheClock: () ->
@reset()
confirmNSA: () ->
window.location.href = 'http://www.whitehouse.gov/our-government/the-constitution'
confirmNotNSA: () ->
@set 'needsConfirmation', false
@set 'secretsSpilled', 0
@updateModel()
checkAgain: () ->
@reset()
@set 'fetchingSecret', true
@updateModel()
window.SnapSecret.IndexRoute = Ember.Route.extend
model: () -> window.activeSecret
setupController: (controller, model) ->
model = { secret: { message: null }} unless model
controller.set 'model', model
controller.send 'startTheClock'
deactivate: () ->
@controller.send('stopTheClock')
renderTemplate: (controller, model) ->
@controllerFor('messages').set('failureMessages', [])
@render('messages', {
outlet: 'messages'
})
@render('index')
window.SnapSecret.Secret = DS.Model.extend
message: DS.attr('string')
window.SnapSecret.Secret.reopenClass
find: () -> $.getJSON('/api/v1/secrets.json').then (data) =>
window.activeSecret = if data then data else { secret: { message: null }}
class Secret < ActiveRecord::Base
validate :two_secrets_per_hour
validates :message, length: {
minimum: 10,
maximum: 500,
tokenizer: lambda { |str| str.scan(/\w+/) },
too_short: "a secret with less then %{count} words is hardly a secret.",
too_long: "%{count} words max. this isnt wikileaks."
}
scope :unseen, -> { where(displayed: false).order(:id) }
scope :seen, -> { where(displayed: true).order(:id) }
scope :from_past_hour, -> { where('created_at > ?', Time.now - 1.hour) }
scope :with_ip_address, -> (ip_address) { where('ip_address = ?', ip_address) }
def self.get_from_cache
secret = Rails.cache.fetch('secret', expires_in: 50.seconds) { self.get }
secret.increment_view_count if secret
secret
end
def self.get_stats_from_cache
Rails.cache.fetch('secret_stats', expires_in: 1.minutes) { self.get_stats }
end
def self.get_queue
unseen.count
end
def increment_view_count
previous = Rails.cache.read([self, 'view_count']) || self.view_count
current = previous += 1
Rails.cache.write([self, 'view_count'], current)
self.view_count = current
save
end
private
def self.get
previous = self.seen.last
current = self.unseen.first
current.update_attribute(:displayed, true) unless current.nil?
current
end
def self.get_stats
totalSpilled = Secret.count
totalRead = Secret.sum(:view_count).to_i
{ totalSpilled: totalSpilled, totalRead: totalRead }
end
def two_secrets_per_hour
if self.class.unseen.present? and self.class.from_past_hour.with_ip_address(self.ip_address).length > 1
errors.add(:too_many_secrets, "easy there, snowden. two secrets per hour.")
end
end
end
class Api::V1::SecretsController < ApplicationController
respond_to :json
def index
respond_with Secret.get_from_cache
end
def create
@secret = Secret.new(secret_params.merge({
ip_address: request.remote_ip,
queue_estimate: Secret.get_queue
}))
if @secret.save
render json: @secret, status: :created
else
render json: { errors: @secret.errors }, status: :unprocessable_entity
end
end
private
def secret_params
params.fetch(:secret, {}).permit(:message, :queue_estimate, :ip_address)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment