cortex-reaver 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +1 -1
- data/bin/cortex_reaver +3 -4
- data/lib/cortex_reaver.rb +270 -110
- data/lib/cortex_reaver/cache.rb +23 -0
- data/lib/cortex_reaver/config.rb +178 -74
- data/lib/cortex_reaver/controller/admin.rb +64 -4
- data/lib/cortex_reaver/controller/comment.rb +4 -4
- data/lib/cortex_reaver/controller/controller.rb +3 -3
- data/lib/cortex_reaver/controller/journal.rb +4 -2
- data/lib/cortex_reaver/controller/main.rb +117 -26
- data/lib/cortex_reaver/controller/page.rb +7 -0
- data/lib/cortex_reaver/controller/photograph.rb +12 -10
- data/lib/cortex_reaver/controller/tag.rb +1 -1
- data/lib/cortex_reaver/controller/user.rb +7 -2
- data/lib/cortex_reaver/helper/attachments.rb +2 -2
- data/lib/cortex_reaver/helper/crud.rb +7 -7
- data/lib/cortex_reaver/helper/feeds.rb +56 -38
- data/lib/cortex_reaver/helper/form.rb +12 -16
- data/lib/cortex_reaver/helper/navigation.rb +35 -16
- data/lib/cortex_reaver/helper/photographs.rb +2 -2
- data/lib/cortex_reaver/helper/sidebar.rb +44 -0
- data/lib/cortex_reaver/helper/tags.rb +32 -9
- data/lib/cortex_reaver/helper/workflow.rb +2 -14
- data/lib/cortex_reaver/layout/blank.rhtml +27 -31
- data/lib/cortex_reaver/layout/text.rhtml +54 -67
- data/lib/cortex_reaver/migrations/014_convert_projects_to_pages.rb +79 -0
- data/lib/cortex_reaver/model/comment.rb +7 -8
- data/lib/cortex_reaver/model/page.rb +5 -3
- data/lib/cortex_reaver/model/photograph.rb +57 -13
- data/lib/cortex_reaver/model/tag.rb +1 -4
- data/lib/cortex_reaver/model/user.rb +6 -3
- data/lib/cortex_reaver/plugin.rb +1 -1
- data/lib/cortex_reaver/plugins/twitter.rb +185 -0
- data/lib/cortex_reaver/public/css/actions.css +31 -0
- data/lib/cortex_reaver/public/css/admin.css +50 -27
- data/lib/cortex_reaver/public/css/attachments.css +11 -0
- data/lib/cortex_reaver/public/css/autotags.css +38 -0
- data/lib/cortex_reaver/public/css/code.css +10 -2
- data/lib/cortex_reaver/public/css/colophon.css +10 -0
- data/lib/cortex_reaver/public/css/commments.css +7 -0
- data/lib/cortex_reaver/public/css/custom.css +1 -0
- data/lib/cortex_reaver/public/css/flash.css +17 -0
- data/lib/cortex_reaver/public/css/fonts.css +22 -0
- data/lib/cortex_reaver/public/css/form.css +15 -3
- data/lib/cortex_reaver/public/css/generics.css +39 -0
- data/lib/cortex_reaver/public/css/icons.css +4 -0
- data/lib/cortex_reaver/public/css/journals.css +3 -0
- data/lib/cortex_reaver/public/css/main.css +30 -312
- data/lib/cortex_reaver/public/css/pagination.css +50 -0
- data/lib/cortex_reaver/public/css/photo-show.css +87 -0
- data/lib/cortex_reaver/public/css/photo.css +28 -97
- data/lib/cortex_reaver/public/css/progress.css +35 -0
- data/lib/cortex_reaver/public/css/sidebar.css +83 -0
- data/lib/cortex_reaver/public/css/table-of-contents.css +26 -0
- data/lib/cortex_reaver/public/css/table.css +3 -0
- data/lib/cortex_reaver/public/css/tags.css +29 -0
- data/lib/cortex_reaver/public/css/text.css +19 -1
- data/lib/cortex_reaver/public/css/top_actions.css +50 -0
- data/lib/cortex_reaver/public/css/users.css +3 -0
- data/lib/cortex_reaver/public/images/admin/icons.png +0 -0
- data/lib/cortex_reaver/public/images/admin/icons.xcf +0 -0
- data/lib/cortex_reaver/public/images/background_tile.png +0 -0
- data/lib/cortex_reaver/public/images/edit_34.png +0 -0
- data/lib/cortex_reaver/public/images/edit_34_prelight.png +0 -0
- data/lib/cortex_reaver/public/images/elided.png +0 -0
- data/lib/cortex_reaver/public/images/grid_34.png +0 -0
- data/lib/cortex_reaver/public/images/grid_34_prelight.png +0 -0
- data/lib/cortex_reaver/public/images/next_11.png +0 -0
- data/lib/cortex_reaver/public/images/next_34.png +0 -0
- data/lib/cortex_reaver/public/images/next_34_prelight.png +0 -0
- data/lib/cortex_reaver/public/images/prev_11.png +0 -0
- data/lib/cortex_reaver/public/images/prev_34.png +0 -0
- data/lib/cortex_reaver/public/images/prev_34_prelight.png +0 -0
- data/lib/cortex_reaver/public/js/admin.js +15 -22
- data/lib/cortex_reaver/public/js/autotags.js +120 -0
- data/lib/cortex_reaver/public/js/jquery.autocomplete.js +135 -176
- data/lib/cortex_reaver/public/js/jquery.color.js +124 -0
- data/lib/cortex_reaver/public/js/jquery.corners.min.js +7 -0
- data/lib/cortex_reaver/public/js/jquery.hotkeys-0.7.9.js +244 -0
- data/lib/cortex_reaver/public/js/jquery.js +4361 -4
- data/lib/cortex_reaver/public/js/jquery.periodicalupdater.js +98 -0
- data/lib/cortex_reaver/public/js/photo.js +3 -32
- data/lib/cortex_reaver/public/robots.txt +3 -0
- data/lib/cortex_reaver/snippets/ramaze/cache/memcached.rb +13 -10
- data/lib/cortex_reaver/snippets/range.rb +9 -0
- data/lib/cortex_reaver/support/attachments.rb +12 -0
- data/lib/cortex_reaver/support/comments.rb +1 -3
- data/lib/cortex_reaver/support/renderer.rb +20 -17
- data/lib/cortex_reaver/support/sequenceable.rb +6 -6
- data/lib/cortex_reaver/support/tags.rb +15 -7
- data/lib/cortex_reaver/version.rb +1 -1
- data/lib/cortex_reaver/view/admin/configuration.rhtml +7 -0
- data/lib/cortex_reaver/view/admin/index.rhtml +3 -0
- data/lib/cortex_reaver/view/admin/regenerate_photo_sizes.rhtml +16 -0
- data/lib/cortex_reaver/view/adminbox.rhtml +34 -44
- data/lib/cortex_reaver/view/comments/comment.rhtml +1 -1
- data/lib/cortex_reaver/view/comments/form.rhtml +1 -2
- data/lib/cortex_reaver/view/comments/post_form.rhtml +2 -10
- data/lib/cortex_reaver/view/head.rhtml +11 -0
- data/lib/cortex_reaver/view/journals/journal.rhtml +3 -3
- data/lib/cortex_reaver/view/journals/show.rhtml +0 -4
- data/lib/cortex_reaver/view/js.rhtml +1 -0
- data/lib/cortex_reaver/view/pages/list.rhtml +3 -23
- data/lib/cortex_reaver/view/pages/row.rhtml +13 -0
- data/lib/cortex_reaver/view/photographs/grid.rhtml +30 -36
- data/lib/cortex_reaver/view/photographs/show.rhtml +42 -108
- data/lib/cortex_reaver/view/sidebar/explore_photos.rhtml +7 -0
- data/lib/cortex_reaver/view/sidebar/photographs.rhtml +15 -0
- data/lib/cortex_reaver/view/sidebar/sections.rhtml +4 -0
- data/lib/cortex_reaver/view/sidebar/twitter.rhtml +12 -0
- data/lib/cortex_reaver/view/tags/show.rhtml +0 -10
- data/lib/cortex_reaver/view/tracker.rhtml +0 -0
- data/lib/cortex_reaver/view/users/list.rhtml +1 -7
- data/lib/cortex_reaver/view/users/login.rhtml +1 -1
- metadata +103 -43
- data/lib/cortex_reaver/controller/project.rb +0 -53
- data/lib/cortex_reaver/helper/template.rb +0 -37
- data/lib/cortex_reaver/model/project.rb +0 -57
- data/lib/cortex_reaver/public/css/ramaze_error.css +0 -90
- data/lib/cortex_reaver/public/images/atom-xml-icon.png +0 -0
- data/lib/cortex_reaver/public/images/body.png +0 -0
- data/lib/cortex_reaver/public/images/border_bottom.png +0 -0
- data/lib/cortex_reaver/public/images/border_bottom_left.png +0 -0
- data/lib/cortex_reaver/public/images/border_bottom_right.png +0 -0
- data/lib/cortex_reaver/public/images/border_left.png +0 -0
- data/lib/cortex_reaver/public/images/border_right.png +0 -0
- data/lib/cortex_reaver/public/images/border_top.png +0 -0
- data/lib/cortex_reaver/public/images/border_top_left.png +0 -0
- data/lib/cortex_reaver/public/images/border_top_right.png +0 -0
- data/lib/cortex_reaver/public/images/header.png +0 -0
- data/lib/cortex_reaver/public/images/header.xcf +0 -0
- data/lib/cortex_reaver/public/images/indicator.gif +0 -0
- data/lib/cortex_reaver/public/images/rss-xml-icon.png +0 -0
- data/lib/cortex_reaver/public/images/sections.png +0 -0
- data/lib/cortex_reaver/public/images/sections_highlight.png +0 -0
- data/lib/cortex_reaver/public/js/jquery.autocompletefb.js +0 -125
- data/lib/cortex_reaver/view/photographs/sidebar.rhtml +0 -7
- data/lib/cortex_reaver/view/projects/form.rhtml +0 -14
- data/lib/cortex_reaver/view/projects/list.rhtml +0 -31
- data/lib/cortex_reaver/view/projects/show.rhtml +0 -42
- data/lib/proto/cortex_reaver.yaml +0 -47
@@ -0,0 +1,79 @@
|
|
1
|
+
module CortexReaver
|
2
|
+
class ProjectsToPagesSchema < Sequel::Migration
|
3
|
+
|
4
|
+
def down
|
5
|
+
# Nope. Not even going to try.
|
6
|
+
end
|
7
|
+
|
8
|
+
def up
|
9
|
+
pages = self[:pages]
|
10
|
+
projects = self[:projects]
|
11
|
+
|
12
|
+
# Create projects page
|
13
|
+
unless root = pages.filter(:name => 'projects').first
|
14
|
+
pages.insert(
|
15
|
+
:name => 'projects',
|
16
|
+
:title => 'Projects',
|
17
|
+
:created_on => Time.now,
|
18
|
+
:updated_on => Time.now
|
19
|
+
)
|
20
|
+
end
|
21
|
+
root = pages.filter(:name => 'projects').first
|
22
|
+
|
23
|
+
# Migrate each project
|
24
|
+
projects.all.each do |project|
|
25
|
+
project_id = project[:id]
|
26
|
+
|
27
|
+
# Create page
|
28
|
+
project.delete :description
|
29
|
+
project.delete :id
|
30
|
+
project[:page_id] = root[:id]
|
31
|
+
pages << project
|
32
|
+
|
33
|
+
# Get page id
|
34
|
+
page_id = pages.filter(:page_id => root[:id], :name => project[:name]).first[:id]
|
35
|
+
|
36
|
+
# Reparent comments
|
37
|
+
self[:comments].filter(:project_id => project_id).update(
|
38
|
+
:project_id => nil,
|
39
|
+
:page_id => page_id
|
40
|
+
)
|
41
|
+
|
42
|
+
# Copy tags
|
43
|
+
self[:projects_tags].filter(:project_id => project_id).each do |t|
|
44
|
+
self[:pages_tags] << {:page_id => page_id, :tag_id => t[:tag_id]}
|
45
|
+
end
|
46
|
+
|
47
|
+
# Move attachments
|
48
|
+
# This is a little tricky; I'd like to deprecate the entire model at
|
49
|
+
# some point. We assume it lives in config.public_dir/data/projects/id
|
50
|
+
project_dir = File.join(
|
51
|
+
CortexReaver.config.public_root, 'data', 'projects', project_id.to_s
|
52
|
+
)
|
53
|
+
page_dir = File.join(
|
54
|
+
CortexReaver.config.public_root, 'data', 'pages', page_id.to_s
|
55
|
+
)
|
56
|
+
if File.directory? project_dir
|
57
|
+
if File.directory? page_dir
|
58
|
+
puts "WARNING: #{page_dir} already exists. Not moving contents of #{project_dir} into it. You should take a look."
|
59
|
+
else
|
60
|
+
FileUtils.move project_dir, page_dir
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
projects.filter(:id => project_id).delete
|
65
|
+
end
|
66
|
+
|
67
|
+
# Drop associated columns
|
68
|
+
# Can't do this yet--foreign key constraints...
|
69
|
+
# alter_table :comments do
|
70
|
+
# drop_column :project_id
|
71
|
+
# end
|
72
|
+
|
73
|
+
# Drop projects table
|
74
|
+
unless table_exists? :projects
|
75
|
+
drop_table :projects
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -10,7 +10,6 @@ module CortexReaver
|
|
10
10
|
many_to_one :creator, :class => 'CortexReaver::User', :key => 'created_by'
|
11
11
|
many_to_one :updater, :class => 'CortexReaver::User', :key => 'updated_by'
|
12
12
|
many_to_one :journal, :class => 'CortexReaver::Journal'
|
13
|
-
many_to_one :project, :class => 'CortexReaver::Project'
|
14
13
|
many_to_one :photograph, :class => 'CortexReaver::Photograph'
|
15
14
|
many_to_one :page, :class => 'CortexReaver::Page'
|
16
15
|
many_to_one :comment, :class => 'CortexReaver::Comment'
|
@@ -90,21 +89,21 @@ module CortexReaver
|
|
90
89
|
|
91
90
|
def validate
|
92
91
|
validates_presence :body
|
93
|
-
validates_max_length 255, :title
|
94
|
-
validates_max_length 255, :name
|
95
|
-
validates_max_length 255, :http
|
96
|
-
validates_max_length 255, :email
|
97
|
-
validates_format(/^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/, :email)
|
92
|
+
validates_max_length 255, :title, :allow_blank => true
|
93
|
+
validates_max_length 255, :name, :allow_blank => true
|
94
|
+
validates_max_length 255, :http, :allow_blank => true
|
95
|
+
validates_max_length 255, :email, :allow_blank => true
|
96
|
+
validates_format(/^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/, :email, :allow_blank => true)
|
98
97
|
|
99
98
|
# Ensure comments with an email specified do *not* conflict with another
|
100
99
|
# user.
|
101
|
-
if (not email.blank?) and User.filter(:email =>
|
100
|
+
if (not email.blank?) and User.filter(:email => email).count > 0
|
102
101
|
self.errors[:email] << 'conflicts with a registered user'
|
103
102
|
end
|
104
103
|
|
105
104
|
# Ensures comments belong to exactly one parent.
|
106
105
|
count = 0
|
107
|
-
[:page_id, :
|
106
|
+
[:page_id, :journal_id, :comment_id, :photograph_id].each do |field|
|
108
107
|
unless self[field].blank?
|
109
108
|
count += 1
|
110
109
|
if count > 1
|
@@ -10,8 +10,10 @@ module CortexReaver
|
|
10
10
|
plugin :viewable
|
11
11
|
include CortexReaver::Model::Renderer
|
12
12
|
|
13
|
+
self.sequence_order = :name
|
14
|
+
|
13
15
|
many_to_one :page, :class => 'CortexReaver::Page'
|
14
|
-
one_to_many :pages, :class => 'CortexReaver::Page'
|
16
|
+
one_to_many :pages, :class => 'CortexReaver::Page', :order => :name
|
15
17
|
many_to_one :creator, :class => 'CortexReaver::User', :key => 'created_by'
|
16
18
|
many_to_one :updater, :class => 'CortexReaver::User', :key => 'updated_by'
|
17
19
|
one_to_many :comments, :class => 'CortexReaver::Comment'
|
@@ -111,12 +113,12 @@ module CortexReaver
|
|
111
113
|
end
|
112
114
|
|
113
115
|
# Create a default page if none exists.
|
114
|
-
if
|
116
|
+
if db.table_exists?(table_name) and Page.count == 0
|
115
117
|
Page.new(
|
116
118
|
:name => 'about',
|
117
119
|
:title => 'About Cortex Reaver',
|
118
120
|
:body => <<EOF
|
119
|
-
<p>Cortex Reaver is a blog engine designed for managing photographs,
|
121
|
+
<p>Cortex Reaver is a blog engine designed for managing photographs, pages,
|
120
122
|
journal entries, and more, with support for tags and comments. Cortex
|
121
123
|
Reaver is written in <a href="http://ruby-lang.org">Ruby</a> using <a
|
122
124
|
href="http://ramaze.net">Ramaze</a>, uses the <a
|
@@ -10,7 +10,7 @@ module CortexReaver
|
|
10
10
|
|
11
11
|
# Target image sizes
|
12
12
|
SIZES = {
|
13
|
-
:thumbnail => '
|
13
|
+
:thumbnail => '166x',
|
14
14
|
:grid => '150x150',
|
15
15
|
:small => 'x512',
|
16
16
|
:medium => 'x768',
|
@@ -34,6 +34,12 @@ module CortexReaver
|
|
34
34
|
reverse_order(:created_on).limit(16)
|
35
35
|
end
|
36
36
|
|
37
|
+
def self.regenerate_sizes
|
38
|
+
all.each do |p|
|
39
|
+
p.regenerate_sizes
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
37
43
|
def self.url
|
38
44
|
'/photographs'
|
39
45
|
end
|
@@ -72,19 +78,10 @@ module CortexReaver
|
|
72
78
|
end
|
73
79
|
|
74
80
|
# Write file to disk
|
75
|
-
attachment = Attachment.new(self, 'original.jpg')
|
76
|
-
attachment.file = file
|
77
|
-
|
78
|
-
# Read image through ImageMagick
|
79
|
-
image = Magick::Image.read(attachment.local_path).first
|
81
|
+
attachment = Attachment.new(self, 'original.jpg').file = file
|
80
82
|
|
81
|
-
#
|
82
|
-
|
83
|
-
image.change_geometry(geometry) do |width, height|
|
84
|
-
attachment = Attachment.new(self, size.to_s + '.jpg')
|
85
|
-
image.scale(width, height).write(attachment.local_path)
|
86
|
-
end
|
87
|
-
end
|
83
|
+
# Compute thumbnails
|
84
|
+
regenerate_sizes
|
88
85
|
|
89
86
|
true
|
90
87
|
end
|
@@ -111,6 +108,53 @@ module CortexReaver
|
|
111
108
|
attachment(size.to_s + '.jpg').path(type)
|
112
109
|
end
|
113
110
|
|
111
|
+
# Regenerates various photo sizes.
|
112
|
+
def regenerate_sizes
|
113
|
+
Ramaze::Log.info "Regenerating photo sizes for #{self}"
|
114
|
+
|
115
|
+
# Find existing attachments, in order of decreasing (roughly) size
|
116
|
+
known_files = attachments.map{|a| a.name.sub(/\.jpg$/,'')} & (SIZES.keys.map(&:to_s) + ['original'])
|
117
|
+
largest = attachment(
|
118
|
+
known_files.sort_by { |f|
|
119
|
+
File.stat(attachment("#{f}.jpg").path).size
|
120
|
+
}.last + '.jpg'
|
121
|
+
)
|
122
|
+
|
123
|
+
# Replace original.jpg with the largest available, if necessary.
|
124
|
+
orig = attachment 'original.jpg'
|
125
|
+
unless orig.exists? and orig == largest
|
126
|
+
orig.file = largest
|
127
|
+
end
|
128
|
+
|
129
|
+
# Delete everything but original.jpg
|
130
|
+
attachments.reject {|a| a.name == 'original.jpg'}.each{|a| a.delete}
|
131
|
+
|
132
|
+
# Read image through ImageMagick
|
133
|
+
begin
|
134
|
+
image = Magick::Image.read(orig.local_path).first
|
135
|
+
rescue => e
|
136
|
+
Ramaze::Log.error "Invalid image #{orig.local_path}; not processing."
|
137
|
+
return false
|
138
|
+
end
|
139
|
+
|
140
|
+
# Write appropriate sizes to disk
|
141
|
+
SIZES.each do |size, geometry|
|
142
|
+
image.change_geometry(geometry) do |width, height|
|
143
|
+
attachment = attachment(size.to_s + '.jpg')
|
144
|
+
image.scale(width, height).write(attachment.local_path)
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
# Yep, GC time. Gotta clear out those imagemagick stubs.
|
150
|
+
GC.start
|
151
|
+
|
152
|
+
# Free IM stubs
|
153
|
+
GC.start
|
154
|
+
|
155
|
+
true
|
156
|
+
end
|
157
|
+
|
114
158
|
# Returns the system path to the thumbnail photograph
|
115
159
|
def thumbnail_local_path
|
116
160
|
path :local, 'thumbnail'
|
@@ -4,7 +4,6 @@ module CortexReaver
|
|
4
4
|
|
5
5
|
many_to_many :photographs, :class => 'CortexReaver::Photograph'
|
6
6
|
many_to_many :journals, :class => 'CortexReaver::Journal'
|
7
|
-
many_to_many :projects, :class => 'CortexReaver::Project'
|
8
7
|
many_to_many :pages, :class => 'CortexReaver::Page'
|
9
8
|
|
10
9
|
subset :unused, :count => 0
|
@@ -23,7 +22,6 @@ module CortexReaver
|
|
23
22
|
|
24
23
|
remove_all_photographs
|
25
24
|
remove_all_journals
|
26
|
-
remove_all_projects
|
27
25
|
remove_all_pages
|
28
26
|
|
29
27
|
true
|
@@ -62,8 +60,7 @@ module CortexReaver
|
|
62
60
|
old_count = self[:count]
|
63
61
|
self[:count] = photographs_dataset.count +
|
64
62
|
journals_dataset.count +
|
65
|
-
pages_dataset.count
|
66
|
-
projects_dataset.count
|
63
|
+
pages_dataset.count
|
67
64
|
|
68
65
|
# Save and return
|
69
66
|
changed = changed_columns.include? :count
|
@@ -9,12 +9,10 @@ module CortexReaver
|
|
9
9
|
one_to_many :created_journals, :key => 'created_by', :class => 'CortexReaver::Journal'
|
10
10
|
one_to_many :created_pages, :key => 'created_by', :class => 'CortexReaver::Page'
|
11
11
|
one_to_many :created_photographs, :key => 'created_by', :class => 'CortexReaver::Photograph'
|
12
|
-
one_to_many :created_projects, :key => 'created_by', :class => 'CortexReaver::Project'
|
13
12
|
one_to_many :updated_comments, :key => 'updated_by', :class => 'CortexReaver::Comment'
|
14
13
|
one_to_many :updated_journals, :key => 'updated_by', :class => 'CortexReaver::Journal'
|
15
14
|
one_to_many :updated_pages, :key => 'updated_by', :class => 'CortexReaver::Page'
|
16
15
|
one_to_many :updated_photographs, :key => 'updated_by', :class => 'CortexReaver::Photograph'
|
17
|
-
one_to_many :updated_projects, :key => 'updated_by', :class => 'CortexReaver::Project'
|
18
16
|
|
19
17
|
|
20
18
|
self.window_size = 64
|
@@ -70,6 +68,11 @@ module CortexReaver
|
|
70
68
|
self[:login => id] || self[id]
|
71
69
|
end
|
72
70
|
|
71
|
+
# Class URL
|
72
|
+
def self.url
|
73
|
+
'/users'
|
74
|
+
end
|
75
|
+
|
73
76
|
# Returns true if the user is an administrator.
|
74
77
|
def admin?
|
75
78
|
self.admin
|
@@ -269,7 +272,7 @@ module CortexReaver
|
|
269
272
|
public
|
270
273
|
|
271
274
|
# Create default user if none exist
|
272
|
-
if
|
275
|
+
if db.table_exists?(table_name) and count == 0
|
273
276
|
u = User.new(
|
274
277
|
:login => 'shodan',
|
275
278
|
:name => 'Shodan',
|
data/lib/cortex_reaver/plugin.rb
CHANGED
@@ -0,0 +1,185 @@
|
|
1
|
+
#--
|
2
|
+
#
|
3
|
+
# Kyle Kingsbury: This plugin is adapted from Ryan's Thoth. His license follows:
|
4
|
+
#
|
5
|
+
# Copyright (c) 2009 Ryan Grove <ryan@wonko.com>
|
6
|
+
# All rights reserved.
|
7
|
+
#
|
8
|
+
# Redistribution and use in source and binary forms, with or without
|
9
|
+
# modification, are permitted provided that the following conditions are met:
|
10
|
+
#
|
11
|
+
# * Redistributions of source code must retain the above copyright notice,
|
12
|
+
# this list of conditions and the following disclaimer.
|
13
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
14
|
+
# this list of conditions and the following disclaimer in the documentation
|
15
|
+
# and/or other materials provided with the distribution.
|
16
|
+
# * Neither the name of this project nor the names of its contributors may be
|
17
|
+
# used to endorse or promote products derived from this software without
|
18
|
+
# specific prior written permission.
|
19
|
+
#
|
20
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
21
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
22
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
23
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
24
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
25
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
26
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
27
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
28
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
29
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
30
|
+
#++
|
31
|
+
|
32
|
+
require 'json'
|
33
|
+
require 'open-uri'
|
34
|
+
require 'timeout'
|
35
|
+
require 'uri'
|
36
|
+
|
37
|
+
module CortexReaver; module Plugins
|
38
|
+
|
39
|
+
# Twitter plugin for Cortex Reaver.
|
40
|
+
module Twitter
|
41
|
+
Config = CortexReaver.config.plugins.twitter ||= Construct.new
|
42
|
+
|
43
|
+
# The twitter username to look for
|
44
|
+
Config.define :username, :default => 'aphyr_'
|
45
|
+
|
46
|
+
# Whether or not to include replies. If this is false, the most recent
|
47
|
+
# non-reply tweets will be displayed.
|
48
|
+
Config.define :include_replies, :default => false
|
49
|
+
|
50
|
+
# Time in seconds to cache results. It's a good idea to keep this nice
|
51
|
+
# and high both to improve the performance of your site and to avoid
|
52
|
+
# pounding on Twitter's servers. Default is 600 seconds (10 minutes).
|
53
|
+
Config.define :cache_ttl, :default => 600
|
54
|
+
|
55
|
+
# Request timeout in seconds.
|
56
|
+
Config.define :request_timeout, :default => 3
|
57
|
+
|
58
|
+
# If Twitter fails to respond at least this many times in a row, no new
|
59
|
+
# requests will be sent until the failure_timeout expires in order to
|
60
|
+
# avoid hindering your blog's performance.
|
61
|
+
Config.define :failure_threshold, :default => 3
|
62
|
+
|
63
|
+
# After the failure_threshold is reached, the plugin will wait this many
|
64
|
+
# seconds before trying again. Default is 600 seconds (10 minutes).
|
65
|
+
Config.define :failure_timeout, :default => 600
|
66
|
+
|
67
|
+
class << self
|
68
|
+
|
69
|
+
# Parses tweet text and converts it into HTML. Explicit URLs and @username
|
70
|
+
# or #hashtag references will be turned into links.
|
71
|
+
def parse_tweet(tweet)
|
72
|
+
index = 0
|
73
|
+
html = tweet.dup
|
74
|
+
protocols = ['ftp', 'ftps', 'git', 'http', 'https', 'mailto', 'scp',
|
75
|
+
'sftp', 'ssh', 'telnet']
|
76
|
+
urls = []
|
77
|
+
|
78
|
+
# Extract URLs and replace them with placeholders for later.
|
79
|
+
URI.extract(html.dup, protocols) do |url|
|
80
|
+
html.sub!(url, "__URL#{index}__")
|
81
|
+
urls << url
|
82
|
+
index += 1
|
83
|
+
end
|
84
|
+
|
85
|
+
# Replace URL placeholders with links.
|
86
|
+
urls.each_with_index do |url, index|
|
87
|
+
html.sub!("__URL#{index}__", "<a href=\"#{url}\">" <<
|
88
|
+
"#{url.length > 26 ? url[0..26] + '...' : url}</a>")
|
89
|
+
end
|
90
|
+
|
91
|
+
# Turn @username into a link to the specified user's Twitter profile.
|
92
|
+
html.gsub!(/@([a-zA-Z0-9_]{1,16})([^a-zA-Z0-9_])?/,
|
93
|
+
'@<a href="http://twitter.com/\1">\1</a>\2')
|
94
|
+
|
95
|
+
# Turn #hashtags into links.
|
96
|
+
html.gsub!(/#([a-zA-Z0-9_]{1,32})([^a-zA-Z0-9_])?/,
|
97
|
+
'<a href="http://search.twitter.com/search?q=%23\1">#\1</a>\2')
|
98
|
+
|
99
|
+
return html
|
100
|
+
end
|
101
|
+
|
102
|
+
# Gets a Hash containing recent tweets for the specified _user_. The only
|
103
|
+
# valid option currently is <code>:count</code>, which specifies the
|
104
|
+
# maximum number of tweets that should be returned.
|
105
|
+
def recent_tweets(user = Config.username, options = {:count => 1})
|
106
|
+
if @skip_until
|
107
|
+
return [] if @skip_until > Time.now
|
108
|
+
@skip_until = nil
|
109
|
+
end
|
110
|
+
|
111
|
+
cache = Ramaze::Cache.plugin
|
112
|
+
options = {:count => 5}.merge(options)
|
113
|
+
count = options[:count].to_i
|
114
|
+
|
115
|
+
count += 10 unless Config.include_replies
|
116
|
+
count = 200 if count > 200
|
117
|
+
|
118
|
+
url = "http://twitter.com/statuses/user_timeline/#{user}.json?count=" <<
|
119
|
+
count.to_s
|
120
|
+
|
121
|
+
if value = cache[url]
|
122
|
+
return value
|
123
|
+
end
|
124
|
+
|
125
|
+
tweets = []
|
126
|
+
|
127
|
+
Timeout.timeout(Config.request_timeout, StandardError) do
|
128
|
+
failed = 0
|
129
|
+
begin
|
130
|
+
tweets = JSON.parse(open(url).read)
|
131
|
+
rescue JSON::ParserError => e
|
132
|
+
# Twitter likes to hand out weird HTML responses sometimes. :/
|
133
|
+
failed += 1
|
134
|
+
retry unless failed > 3
|
135
|
+
|
136
|
+
# Admit defeat
|
137
|
+
raise RuntimeError.new("Failed to parse Twitter response 4 times: #{e}")
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# Weed out replies if necessary.
|
142
|
+
unless Config.include_replies
|
143
|
+
tweets.delete_if do |tweet|
|
144
|
+
!tweet['in_reply_to_status_id'].nil? ||
|
145
|
+
!tweet['in_reply_to_user_id'].nil?
|
146
|
+
end
|
147
|
+
|
148
|
+
tweets = tweets.slice(0, options[:count].to_i)
|
149
|
+
end
|
150
|
+
|
151
|
+
# Parse the tweets into an easier-to-use format.
|
152
|
+
tweets.map! do |tweet|
|
153
|
+
{
|
154
|
+
:created_at => Time.parse(tweet['created_at']),
|
155
|
+
:html => parse_tweet(tweet['text']),
|
156
|
+
:id => tweet['id'],
|
157
|
+
:source => tweet['source'],
|
158
|
+
:text => tweet['text'],
|
159
|
+
:truncated => tweet['truncated'],
|
160
|
+
:url => "http://twitter.com/#{user}/statuses/#{tweet['id']}"
|
161
|
+
}
|
162
|
+
end
|
163
|
+
|
164
|
+
@failures = 0
|
165
|
+
|
166
|
+
return cache.store(url, tweets, :ttl => Config.cache_ttl)
|
167
|
+
|
168
|
+
rescue => e
|
169
|
+
Ramaze::Log.error "CortexReaver::Plugins::Twitter: #{e.message}"
|
170
|
+
|
171
|
+
@failures ||= 0
|
172
|
+
@failures += 1
|
173
|
+
|
174
|
+
if @failures >= Config.failure_threshold
|
175
|
+
@skip_until = Time.now + Config.failure_timeout
|
176
|
+
Ramaze::Log.error "CortexReaver::Plugins::Twitter: Twitter failed to respond #{@failures} times. Will retry after #{@skip_until}."
|
177
|
+
end
|
178
|
+
|
179
|
+
return []
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|
185
|
+
end; end
|