Permalink
Browse files

Main app commit. Successfully handles pingbacks and stores in the dat…

…abase.
  • Loading branch information...
1 parent 6d91307 commit cd92663d0c99342f0bffb91fb41a13146fe5c939 @aaronpk committed Jun 9, 2012
View
@@ -0,0 +1,10 @@
+development:
+ database_url: "mysql://root@127.0.0.1/pingback"
+ session_secret: SUPERSECRET
+ ga_id:
+ geoloqi:
+ api_key:
+ api_secret:
+ github:
+ client_id:
+ client_secret:
View
@@ -0,0 +1,163 @@
+class Controller < Sinatra::Base
+ before do
+ # puts "================="
+ # puts "Path: #{request.path}"
+ # puts "IP: #{request.ip}"
+ # puts
+
+ # Require login on everything except home page
+ if request.path.match /[a-zA-Z0-9_\.]\/xmlrpc/
+ # No login required for /xmlrpc routes
+ else
+ if !["/", "/auth/github", "/auth/github/callback"].include? request.path
+ puts request.body.read
+ require_login
+ end
+ end
+ end
+
+ def require_login
+ if session[:user_id].nil?
+ puts "Login required. Redirecting."
+ redirect "/"
+ end
+
+ @user = User.get session[:user_id]
+ if @user.nil?
+ puts "No user found. Redirecting."
+ redirect "/"
+ end
+ end
+
+ get '/?' do
+ erb :index
+ end
+
+ get '/dashboard/?' do
+ title "Dashboard"
+ erb :dashboard
+ end
+
+ # Web Hooks
+
+ # XML RPC
+ post '/:username/xmlrpc' do |username|
+
+ puts "RECEIVED PINGBACK REQUEST"
+
+ @target_user = User.first :username => username
+
+ if @target_user.nil?
+ rpc_error 404, 0, "Not Found"
+ end
+
+ xml = request.body.read
+ method, arguments = XMLRPC::Marshal.load_call(xml)
+
+ method.gsub! /\./, '_'
+ puts "Method: #{method} Args: #{arguments}"
+
+ if respond_to?(method)
+ content_type("text/xml", :charset => "utf-8")
+ send method, arguments
+ else
+ rpc_error 404, 0, "Not Found"
+ end
+ end
+
+ def pingback_ping(args)
+ source, target = args
+
+ puts "Verifying link exists from #{source} to #{target}"
+
+ target_domain = URI.parse(target).host
+
+ return rpc_error 200, 0, "Malformed target URI" if target_domain.nil?
+
+ site = Site.first_or_create :user => @target_user, :domain => target_domain
+ page = Page.first_or_create({:site => site, :href => target}, {:user => @target_user})
+ link = Link.first_or_create(:page => page, :href => source)
+
+ unless link.nil?
+ rpc_error 200, 0x0030, "The pingback has already been registered"
+ end
+
+ agent = Mechanize.new {|agent|
+ agent.user_agent_alias = "Mac Safari"
+ }
+ scraper = agent.get source
+
+ valid = scraper.link_with(:href => target) != nil
+
+ if valid
+ link.verified = true
+ link.save
+ rpc_respond 200, "Pingback from #{source} to #{target} was successful! Keep the web talking!"
+ else
+ rpc_error 200, 0x0011, "There appears to be no link to us!"
+ end
+
+ # See http://www.hixie.ch/specs/pingback/pingback for a list of error codes to return
+ end
+
+ # Authentication
+
+ get '/auth/github/callback' do
+ auth = request.env["omniauth.auth"]
+ user = User.first :username => auth["info"]["nickname"]
+ if user.nil?
+ puts "Unauthorized github login"
+ title "Unauthorized"
+ @message = "Sorry, you are not authorized to log in"
+ erb :error
+ else
+ user.last_login_date = Time.now
+ if user.email == '' && auth["info"]["email"]
+ user.email = auth["info"]["email"]
+ end
+ user.save
+ session[:user_id] = user[:id]
+ puts "User successfully logged in"
+ redirect "/dashboard/"
+ end
+ end
+
+ get '/auth/failure' do
+ @message = "The authentication provider replied with an error: #{params['message']}"
+ title "Error"
+ erb :error
+ end
+
+ get '/reset' do
+ session.clear
+ title "Session"
+ erb :session
+ end
+
+ # Helpers
+
+ def rpc_respond(code, string)
+ error code, XMLRPC::Marshal.dump_response(string)
+ end
+
+ def rpc_error(code, error, string)
+ error code, XMLRPC::Marshal.dump_response(XMLRPC::FaultException.new(error.to_i, string))
+ end
+
+ def json_error(code, data)
+ return [code, {
+ 'Content-Type' => 'application/json;charset=UTF-8',
+ 'Cache-Control' => 'no-store'
+ },
+ data.to_json]
+ end
+
+ def json_respond(code, data)
+ return [code, {
+ 'Content-Type' => 'application/json;charset=UTF-8',
+ 'Cache-Control' => 'no-store'
+ },
+ data.to_json]
+ end
+
+end
View
@@ -0,0 +1,62 @@
+Encoding.default_internal = 'UTF-8'
+require 'rubygems'
+require 'bundler/setup'
+require 'cgi'
+require 'openid/store/filesystem'
+require 'xmlrpc/marshal'
+
+Bundler.require
+Dir.glob(['lib', 'models', 'helpers'].map! {|d| File.join File.expand_path(File.dirname(__FILE__)), d, '*.rb'}).each {|f| require f}
+
+unless File.exists? './config.yml'
+ puts 'Please provide a config.yml file.'
+ exit false
+end
+
+class ConfigHelper < Hashie::Mash
+ def key; self['key'] end
+end
+
+SiteConfig = ConfigHelper.new YAML.load_file('config.yml')[ENV['RACK_ENV']] if File.exists?('config.yml')
+
+
+class Controller < Sinatra::Base
+ configure do
+
+ helpers Sinatra::UserAgentHelpers
+
+ # Set controller names so we can map them in the config.ru file.
+ set :controller_names, []
+ Dir.glob('controllers/*.rb').each do |file|
+ settings.controller_names << File.basename(file, '.rb')
+# require_relative "./#{file}"
+ end
+
+ use Rack::Session::Cookie, :key => 'rack.session',
+ :path => '/',
+ :expire_after => 2592000,
+ :secret => SiteConfig.session_secret
+
+ set :root, File.dirname(__FILE__)
+ set :show_exceptions, true
+ set :raise_errors, false
+
+ use OmniAuth::Builder do
+ use OmniAuth::Strategies::GitHub, SiteConfig.github.client_id, SiteConfig.github.client_secret
+ end
+
+ DataMapper.finalize
+ DataMapper.setup :default, SiteConfig.database_url
+
+ set :views, 'views'
+ set :erubis, :escape_html => true
+ set :public_folder, File.dirname(__FILE__) + '/public'
+ end
+
+ def p; params end
+end
+
+require_relative './controller.rb'
+Dir.glob(['controllers'].map! {|d| File.join d, '*.rb'}).each do |f|
+ require_relative f
+end
View
@@ -0,0 +1,35 @@
+class Controller < Sinatra::Base
+ helpers do
+
+ def title(value=nil)
+ return @_title if value.nil?
+ @_title = value
+ end
+
+ def viewport
+ '<meta name="viewport" content="width=device-width,initial-scale=1">' if @_mobile
+ end
+
+ def partial(page, options={})
+ erb page, options.merge!(:layout => false)
+ end
+
+ def path_class
+ classes = request.path.split('/')
+ classes.push('home') if request.path == '/'
+
+ #if logged_in?
+ # classes.push('logged-in')
+ #else
+ # classes.push('logged-out')
+ #end
+
+ classes.join(" ")
+ end
+
+ def request_headers
+ env.inject({}){|acc, (k,v)| acc[$1.downcase] = v if k =~ /^http_(.*)/i; acc}
+ end
+
+ end
+end
View
@@ -0,0 +1,12 @@
+class Link
+ include DataMapper::Resource
+ property :id, Serial
+
+ property :href, String, :length => 512
+ property :verified, Boolean
+
+ belongs_to :page
+
+ property :created_at, DateTime
+ property :updated_at, DateTime
+end
View
@@ -0,0 +1,13 @@
+class Page
+ include DataMapper::Resource
+ property :id, Serial
+
+ property :href, String, :length => 512
+
+ belongs_to :user
+ belongs_to :site
+ has n, :links
+
+ property :created_at, DateTime
+ property :updated_at, DateTime
+end
View
@@ -0,0 +1,12 @@
+class Site
+ include DataMapper::Resource
+ property :id, Serial
+
+ property :domain, String, :length => 255
+
+ belongs_to :user
+ has n, :pages
+
+ property :created_at, DateTime
+ property :updated_at, DateTime
+end
View
@@ -0,0 +1,14 @@
+class User
+ include DataMapper::Resource
+ property :id, Serial
+
+ property :username, String, :length => 255
+ property :email, String, :length => 255
+
+ has n, :sites
+
+ property :last_login_date, DateTime
+ property :created_at, DateTime
+ property :updated_at, DateTime
+
+end
Oops, something went wrong.

0 comments on commit cd92663

Please sign in to comment.