Skip to content

Commit

Permalink
Initial import
Browse files Browse the repository at this point in the history
  • Loading branch information
glejeune committed Feb 4, 2010
0 parents commit 887f6bf
Show file tree
Hide file tree
Showing 11 changed files with 545 additions and 0 deletions.
215 changes: 215 additions & 0 deletions ceres.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
require 'rubygems'
require 'capcode'
require 'capcode/base/dm'

# Require Ceres libs
require './lib/feed.rb'

require 'pp'

Ceres::Feeds::Reader.new(20).start

# -- Modele -------------------------------------------------------------------

class Feed < Capcode::Base
include Capcode::Resource

property :id, Serial

property :host, String
property :url, String
property :feed, String
property :title, String
property :description, Text
property :active, String

property :last_update, Date

has n, :posts
end

class Post < Capcode::Base
include Capcode::Resource
property :id, Serial

property :title, String
property :content, Text
property :date, Date
property :url, String
property :post_id, String

belongs_to :feed

def self.paginate( opts = {} )
opts = {:page => 1, :per_page => 10, :order => :date.desc}.merge(opts)

order = opts.delete(:order) || []

all = Post.all( :order => order )

number_of_pages = all.count / opts[:per_page]
number_of_pages = ((all.count - (number_of_pages * opts[:per_page])) > 0)?(number_of_pages+1):number_of_pages

page = opts[:page]
page = 1 if page < 1
page = number_of_pages if page > number_of_pages
page -= 1

start = page*opts[:per_page]

all[start, opts[:per_page]]
end
end

class Moderator < Capcode::Base
include Capcode::Resource
property :id, Serial

property :login, String
property :realname, String
property :password_hash, String
property :password_salt, String

def password=(pass)
salt = [Array.new(6){rand(256).chr}.join].pack("m").chomp
self.password_salt, self.password_hash = salt, Digest::SHA256.hexdigest( pass + salt )
end

def self.authenticate( login, password )
user = Moderator.first( :login => login )
if user.blank? || Digest::SHA256.hexdigest( password + user.password_salt ) != user.password_hash
return nil
end
return user
end
end

# -- Controller ---------------------------------------------------------------

module Capcode
set :erb, "views"
set :static, "static"

before_filter :check_login
before_filter :user_logged, :only => [:Administration]

def check_login
if session[:user]
@user = Moderator.get(session[:user])
else
@user = nil
end
nil
end

def user_logged
if session[:user]
nil
else
redirect Capcode::Login
end
end

class Index < Route '/'
def get
@posts = Post.paginate( )
render :erb => :index
end
end

class Style < Route '/style'
def get
render :static => "style.css"
end
end

class ProposeFeed < Route '/propose'
def get
@alternates = nil
render :erb => :propose
end

def post
@alternates = Ceres::Feeds.fromURL( params['url'] )
render :erb => :propose
end
end

class SubmitFeed < Route '/propose/submit'
def get
redirect ProposeFeed
end

def post
feed = Feed.new(params)
if feed.save
redirect Index
else
@error = true
render :erb => :proposal
end
end
end

class Login < Route '/login'
def get
if session[:user]
redirect Index
else
render :erb => :login
end
end

def post
user = Moderator.authenticate( params['login'], params['password'] )
if user
session[:user] = user.id
end

redirect Index
end
end

class Logout < Route '/logout'
def get
session.delete(:user)
redirect Index
end
end

class Administration < Route '/admin'
def get
@feeds = Feed.all
@users = Moderator.all

render :erb => :administration
end
end

class Activate < Route '/activate/(.*)'
def get( id )
feed = Feed.get(id.to_i)
feed.active = "yes"
feed.save
redirect Administration
end
end

class Deactivate < Route '/deactivate/(.*)'
def get( id )
feed = Feed.get(id.to_i)
feed.active = nil
feed.save
redirect Administration
end
end

end

Capcode.run( :port => 3001, :host => "localhost", :db_config => "ceres.yml" ) do
if Moderator.all.count <= 0
m = Moderator.new( :login => "admin", :realname => "Admin")
m.password = "admin"
m.save
end
end
2 changes: 2 additions & 0 deletions ceres.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
adapter: sqlite3
database: ceres.db
113 changes: 113 additions & 0 deletions lib/feed.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
require 'rubygems'
require 'feed-normalizer'
require 'open-uri'
require 'eventmachine'
require 'nokogiri'
require 'uri'

module Ceres
class Feeds
FEED_LINK_TYPE = ['application/rss+xml', 'text/xml', 'application/atom+xml']

# This method take a website URL and return all alternate for feeds
def self.fromURL( url )
feed = {
:url => url,
:links => []
}

uri = URI.parse( url )
feed[:host] = uri.scheme + "://" +
((uri.userinfo)?(uri.userinfo+"@"):"") + uri.host +
((uri.port and uri.port != 80)?(":"+uri.port.to_s):"")

doc = Nokogiri::HTML(open( url ))
feed[:title] = doc.xpath('/html/head/title').children.to_s
doc.xpath('//link[@rel="alternate"]').each do |link|
if FEED_LINK_TYPE.include?( link.attribute('type').value )
feed[:links] << {
:type => link.attribute('type').value,
:href => (
(URI.parse(link.attribute('href').value).host)?
(link.attribute('href').value):
(URI.join(feed[:host],link.attribute('href').value).to_s)
),
:title => link.attribute('title').value
}
end
end

return feed
end

class Parser
def initialize( )
@feed = FeedNormalizer::FeedNormalizer.parse open(url)
end
end

class Reader

def initialize( interval = 60*60*6 )
# Default : we extract new feeds every 6 hours
@interval = interval
end

def populate
begin
feeds = Feed.all( :active.not => "" )
feeds.each do |feed|
new_posts = false
content = FeedNormalizer::FeedNormalizer.parse open(feed.feed)

# Check all items
content.items.each do |item|
# Verify if the items already existe or not
post = Post.all( :post_id => item.id )
if post.nil? or post.size == 0
new_posts = true

Post.new(
:title => item.title,
:content => item.content,
:date => item.last_updated || Time.now(),
:url => item.urls[0],
:post_id => item.id,
:feed => feed
).save
end
end

feed.last_update = content.last_updated || Time.now()
feed.save
end
rescue => e
puts "** ERROR : #{e.message}"
end

end

def start
Thread.new do
EventMachine.run do
EM.add_periodic_timer(@interval) do
at_exit { EM.stop_event_loop }

populate
end
end
end
end

def stop
EM.stop_event_loop
end

end
end
end





4 changes: 4 additions & 0 deletions lib/options.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module Ceres
class Options
end
end
Binary file added static/images/ceres.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 887f6bf

Please sign in to comment.