require 'sinatra/activerecord' require 'digest/md5' require 'sqlite3' require_relative 'time_ago' ENV_NAME = ENV['RACK_ENV'] || 'development' module Cachai CACHE_MINUTES = 10 * 60 # 10 minutes def self.boot(domain, redis_host = 'localhost') self.domain = domain self.cache = Redis.new(:host => redis_host) self.load_db! end def self.load_db! load_schema unless schema_loaded? end def self.load_schema require_relative '../db/schema.rb' end def self.schema_loaded? Post.first true rescue ActiveRecord::StatementInvalid => e # SQLite3::SQLException => e # return !e.message['no such table'] false rescue ActiveRecord::ConnectionNotEstablished puts "Connection not established." false end def self.domain=(value) @domain = value end def self.domain @domain end def self.cache=(obj) @cache = obj end def self.cache @cache end def self.clear_cache(path) cache.del(key_for(path)) end def self.key_for(path) raise "Domain not set!" unless domain "comments:#{domain}:#{path}" end def self.get_comments_for(path, nocache = false) key = key_for(path) unless !nocache && json_list = cache.get(key) # puts "Not cached. Getting from DB: #{path}" if post = Post.find_by_path(path) json_list = get_and_sort_comments_for(post).to_json else json_list = '[]' end cache.set(key, json_list) cache.expire(key, CACHE_MINUTES) end json_list end def self.get_and_sort_comments_for(post) result = [] top_level = post.responses.comment.approved.top_level nested = post.responses.comment.approved.nested top_level.each_with_index do |comment, i| obj = comment.as_json children = nested.select do |nested| nested.parent_id == comment.id end obj.merge!(:children => children) if children.any? result.push(obj) end result end class Post < ActiveRecord::Base has_many :responses validates_presence_of :path validates_uniqueness_of :path def self.find_or_create_by_path(path) find_by_path(path) || create({:path => path}) end def comments_closed?(days_to_remain_open) return true if comments_allowed.to_i == 0 return false if !days_to_remain_open # ok, we got an expiration period (seconds) # if we add it to the creation date and it's past # that date then yes, comments are closed. (created_at + days_to_remain_open) < Time.now end def clear_cache Cachai.clear_cache(path) end end class Response < ActiveRecord::Base belongs_to :post validates_presence_of :author_name, :author_email, :content scope :approved, lambda { where(:approved => 1) } scope :comment, lambda { where(:response_type => 'comment') } scope :pingback, lambda { where(:response_type => 'pingback') } scope :top_level, lambda { where(:parent_id => 0) } scope :nested, lambda { where("parent_id != 0") } def parent @parent ||= Response.find(parent_id) rescue nil end def as_json(options = {}) { :id => id, :author_name => author_name, # :author_email => author_email, :author_img => author_img, :author_url => author_url, :content => content, :timestamp => created_at.to_i, :parent_id => parent_id, :type => response_type, # :created_at => created_at, :created_ago => Timeago.since(created_at) } end def author_img(size = 50) id = Digest::MD5::hexdigest(author_email.strip.downcase) "https://www.gravatar.com/avatar/#{id}.jpg?s=#{size}" end end end