cortex-reaver 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. data/LICENSE +25 -0
  2. data/README +48 -0
  3. data/bin/console +11 -0
  4. data/bin/cortex_reaver +110 -0
  5. data/bin/import.rb +78 -0
  6. data/lib/cortex_reaver.rb +114 -0
  7. data/lib/cortex_reaver/config.rb +21 -0
  8. data/lib/cortex_reaver/controller/comment.rb +113 -0
  9. data/lib/cortex_reaver/controller/config.rb +14 -0
  10. data/lib/cortex_reaver/controller/journal.rb +40 -0
  11. data/lib/cortex_reaver/controller/main.rb +56 -0
  12. data/lib/cortex_reaver/controller/page.rb +34 -0
  13. data/lib/cortex_reaver/controller/photograph.rb +45 -0
  14. data/lib/cortex_reaver/controller/project.rb +40 -0
  15. data/lib/cortex_reaver/controller/tag.rb +67 -0
  16. data/lib/cortex_reaver/controller/user.rb +71 -0
  17. data/lib/cortex_reaver/helper/activity.rb +9 -0
  18. data/lib/cortex_reaver/helper/attachments.rb +139 -0
  19. data/lib/cortex_reaver/helper/auth.rb +45 -0
  20. data/lib/cortex_reaver/helper/canonical.rb +55 -0
  21. data/lib/cortex_reaver/helper/crud.rb +317 -0
  22. data/lib/cortex_reaver/helper/date.rb +29 -0
  23. data/lib/cortex_reaver/helper/error.rb +14 -0
  24. data/lib/cortex_reaver/helper/feeds.rb +88 -0
  25. data/lib/cortex_reaver/helper/form.rb +114 -0
  26. data/lib/cortex_reaver/helper/navigation.rb +142 -0
  27. data/lib/cortex_reaver/helper/photographs.rb +25 -0
  28. data/lib/cortex_reaver/helper/tags.rb +47 -0
  29. data/lib/cortex_reaver/helper/workflow.rb +27 -0
  30. data/lib/cortex_reaver/migrations/001_users.rb +24 -0
  31. data/lib/cortex_reaver/migrations/002_pages.rb +29 -0
  32. data/lib/cortex_reaver/migrations/003_journals.rb +26 -0
  33. data/lib/cortex_reaver/migrations/004_photographs.rb +24 -0
  34. data/lib/cortex_reaver/migrations/005_projects.rb +27 -0
  35. data/lib/cortex_reaver/migrations/006_tags.rb +64 -0
  36. data/lib/cortex_reaver/migrations/007_comments.rb +40 -0
  37. data/lib/cortex_reaver/migrations/008_config.rb +23 -0
  38. data/lib/cortex_reaver/model/comment.rb +109 -0
  39. data/lib/cortex_reaver/model/journal.rb +53 -0
  40. data/lib/cortex_reaver/model/page.rb +87 -0
  41. data/lib/cortex_reaver/model/photograph.rb +133 -0
  42. data/lib/cortex_reaver/model/project.rb +49 -0
  43. data/lib/cortex_reaver/model/tag.rb +72 -0
  44. data/lib/cortex_reaver/model/user.rb +147 -0
  45. data/lib/cortex_reaver/public/css/admin.css +45 -0
  46. data/lib/cortex_reaver/public/css/custom.css +0 -0
  47. data/lib/cortex_reaver/public/css/form.css +51 -0
  48. data/lib/cortex_reaver/public/css/main.css +325 -0
  49. data/lib/cortex_reaver/public/css/photo.css +113 -0
  50. data/lib/cortex_reaver/public/css/ramaze_error.css +90 -0
  51. data/lib/cortex_reaver/public/css/text.css +25 -0
  52. data/lib/cortex_reaver/public/dispatch.fcgi +11 -0
  53. data/lib/cortex_reaver/public/images/CortexReaver.gif +0 -0
  54. data/lib/cortex_reaver/public/images/atom-xml-icon.png +0 -0
  55. data/lib/cortex_reaver/public/images/body.png +0 -0
  56. data/lib/cortex_reaver/public/images/border_bottom.png +0 -0
  57. data/lib/cortex_reaver/public/images/border_bottom_left.png +0 -0
  58. data/lib/cortex_reaver/public/images/border_bottom_right.png +0 -0
  59. data/lib/cortex_reaver/public/images/border_left.png +0 -0
  60. data/lib/cortex_reaver/public/images/border_right.png +0 -0
  61. data/lib/cortex_reaver/public/images/border_top.png +0 -0
  62. data/lib/cortex_reaver/public/images/border_top_left.png +0 -0
  63. data/lib/cortex_reaver/public/images/border_top_right.png +0 -0
  64. data/lib/cortex_reaver/public/images/comment.gif +0 -0
  65. data/lib/cortex_reaver/public/images/dark_trans.png +0 -0
  66. data/lib/cortex_reaver/public/images/delete.gif +0 -0
  67. data/lib/cortex_reaver/public/images/edit.gif +0 -0
  68. data/lib/cortex_reaver/public/images/header.png +0 -0
  69. data/lib/cortex_reaver/public/images/header.xcf +0 -0
  70. data/lib/cortex_reaver/public/images/header_background.png +0 -0
  71. data/lib/cortex_reaver/public/images/parent.gif +0 -0
  72. data/lib/cortex_reaver/public/images/rss-xml-icon.png +0 -0
  73. data/lib/cortex_reaver/public/images/sections.png +0 -0
  74. data/lib/cortex_reaver/public/images/sections_highlight.png +0 -0
  75. data/lib/cortex_reaver/public/js/admin.js +36 -0
  76. data/lib/cortex_reaver/public/js/cookie.js +27 -0
  77. data/lib/cortex_reaver/public/js/jquery.js +32 -0
  78. data/lib/cortex_reaver/public/js/photo.js +33 -0
  79. data/lib/cortex_reaver/snippets/array.rb +7 -0
  80. data/lib/cortex_reaver/snippets/ramaze/dispatcher/file.rb +37 -0
  81. data/lib/cortex_reaver/support/attachments.rb +235 -0
  82. data/lib/cortex_reaver/support/cached_rendering.rb +79 -0
  83. data/lib/cortex_reaver/support/canonical.rb +107 -0
  84. data/lib/cortex_reaver/support/comments.rb +69 -0
  85. data/lib/cortex_reaver/support/pagination.rb +38 -0
  86. data/lib/cortex_reaver/support/renderer.rb +196 -0
  87. data/lib/cortex_reaver/support/sequenceable.rb +248 -0
  88. data/lib/cortex_reaver/support/tags.rb +108 -0
  89. data/lib/cortex_reaver/support/timestamps.rb +33 -0
  90. data/lib/cortex_reaver/version.rb +8 -0
  91. data/lib/cortex_reaver/view/adminbox.rhtml +56 -0
  92. data/lib/cortex_reaver/view/blank_layout.rhtml +46 -0
  93. data/lib/cortex_reaver/view/comments/comment.rhtml +34 -0
  94. data/lib/cortex_reaver/view/comments/form.rhtml +25 -0
  95. data/lib/cortex_reaver/view/comments/list.rhtml +5 -0
  96. data/lib/cortex_reaver/view/comments/post_form.rhtml +36 -0
  97. data/lib/cortex_reaver/view/config/form.rhtml +10 -0
  98. data/lib/cortex_reaver/view/error.rhtml +72 -0
  99. data/lib/cortex_reaver/view/journals/form.rhtml +12 -0
  100. data/lib/cortex_reaver/view/journals/journal.rhtml +39 -0
  101. data/lib/cortex_reaver/view/journals/list.rhtml +33 -0
  102. data/lib/cortex_reaver/view/journals/short.rhtml +3 -0
  103. data/lib/cortex_reaver/view/journals/show.rhtml +5 -0
  104. data/lib/cortex_reaver/view/pages/form.rhtml +12 -0
  105. data/lib/cortex_reaver/view/pages/list.rhtml +26 -0
  106. data/lib/cortex_reaver/view/pages/show.rhtml +12 -0
  107. data/lib/cortex_reaver/view/photographs/atom_fragment.rhtml +82 -0
  108. data/lib/cortex_reaver/view/photographs/form.rhtml +19 -0
  109. data/lib/cortex_reaver/view/photographs/grid.rhtml +36 -0
  110. data/lib/cortex_reaver/view/photographs/list.rhtml +9 -0
  111. data/lib/cortex_reaver/view/photographs/short.rhtml +3 -0
  112. data/lib/cortex_reaver/view/photographs/show.rhtml +114 -0
  113. data/lib/cortex_reaver/view/photographs/sidebar.rhtml +7 -0
  114. data/lib/cortex_reaver/view/projects/form.rhtml +13 -0
  115. data/lib/cortex_reaver/view/projects/list.rhtml +27 -0
  116. data/lib/cortex_reaver/view/projects/show.rhtml +38 -0
  117. data/lib/cortex_reaver/view/tags/form.rhtml +9 -0
  118. data/lib/cortex_reaver/view/tags/list.rhtml +28 -0
  119. data/lib/cortex_reaver/view/tags/show.rhtml +51 -0
  120. data/lib/cortex_reaver/view/text_layout.rhtml +78 -0
  121. data/lib/cortex_reaver/view/users/form.rhtml +16 -0
  122. data/lib/cortex_reaver/view/users/list.rhtml +38 -0
  123. data/lib/cortex_reaver/view/users/login.rhtml +13 -0
  124. data/lib/cortex_reaver/view/users/register.rhtml +13 -0
  125. data/lib/cortex_reaver/view/users/show.rhtml +37 -0
  126. data/lib/cortex_reaver/view/users/user.rhtml +35 -0
  127. data/lib/proto/cortex_reaver.yaml +28 -0
  128. metadata +285 -0
@@ -0,0 +1,88 @@
1
+ module Ramaze
2
+ module Helper
3
+ # Adds an atom method to each controller it's included in, which
4
+ # lists that controller's recent elements by yielding a block with
5
+ # each record and a builder object for the feed.
6
+ #
7
+ # Requires crud.
8
+ module Feeds
9
+ require 'builder'
10
+
11
+ Helper::LOOKUP << self
12
+
13
+ def self.included(base)
14
+ base.instance_eval do
15
+ def self.for_feed(&block)
16
+ @for_feed_block = block
17
+ end
18
+
19
+ def self.for_feed_block
20
+ @for_feed_block
21
+ end
22
+ end
23
+ end
24
+
25
+ def atom
26
+ atom_builder
27
+ end
28
+
29
+ private
30
+
31
+ def atom_builder(params = {:model_class => self.model_class})
32
+ response['Content-Type'] = 'application/atom+xml'
33
+
34
+ x = Builder::XmlMarkup.new(:indent => 2)
35
+ x.instruct!
36
+
37
+ # Get model class to work with
38
+ model_class = params[:model_class]
39
+
40
+ # Get recent items
41
+ recent = params[:recent] || model_class.recent
42
+
43
+ # Find update time
44
+ updated = recent.first.updated_on.xmlschema
45
+
46
+ x.feed(:xmlns => 'http://www.w3.org/2005/Atom') do
47
+ x.id = model_class.url
48
+ x.title CortexReaver.config.name + ' - ' + model_class.to_s.demodulize.titleize
49
+ # x.subtitle
50
+ x.updated updated
51
+ x.link :href => model_class.url
52
+ x.link :href => model_class.atom_url, :rel => 'self'
53
+
54
+ recent.all do |model|
55
+ x.entry do
56
+ x.id model.url
57
+ x.title model.title
58
+ x.published model.created_on.xmlschema
59
+ x.updated model.updated_on.xmlschema
60
+ x.link :href => model.url, :rel => 'alternate'
61
+
62
+ x.author do
63
+ x.name model.user.name
64
+
65
+ if model.user.http
66
+ x.uri model.user.http
67
+ end
68
+ end
69
+
70
+ # Any additional controller-specific info
71
+ if self.class.for_feed_block
72
+ self.class.for_feed_block.call(model, x)
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ def feeds
80
+ @feeds ||= {}
81
+ end
82
+
83
+ def feed(title, href)
84
+ feeds[title] = href
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,114 @@
1
+ module Ramaze
2
+ module Helper
3
+ # Helps make forms, especially by escaping.
4
+ module Form
5
+
6
+ # Displays errors on a record.
7
+ def errors_on(model)
8
+ unless model.errors.empty?
9
+ s = "<div class=\"form-errors\">\n<h3>Errors</h3>\n<ul>\n"
10
+ model.errors.each do |attribute, error|
11
+ s << "<li>#{attribute} #{error}</li>\n"
12
+ end
13
+ s << "</ul></div>"
14
+ end
15
+ end
16
+
17
+ # Makes a form for a model. Takes a model, form action, and an array of
18
+ # fields, which are passed to form_p.
19
+ def form_for(model, action, fields = [])
20
+ if model.nil?
21
+ raise ArgumentError.new("needs a model")
22
+ elsif action.nil?
23
+ raise ArgumentError.new("needs an action")
24
+ end
25
+
26
+ f = ''
27
+
28
+ unless model.errors.empty?
29
+ f << "<div class=\"form-errors\">\n"
30
+ f << "<ul>\n"
31
+ model.errors.each do |attribute, error|
32
+ f << "<li>#{attribute} #{error}\n</li>"
33
+ end
34
+ f << "</ul>\n"
35
+ f << "</div>\n"
36
+ end
37
+
38
+ f = "<form action=\"#{action}\" method=\"post\" class=\"edit-form\">"
39
+
40
+ fields.each do |field|
41
+ case field
42
+ when Array
43
+ f << form_p(field[0], ({:model => model}.merge!(field[1] || {})))
44
+ else
45
+ f << form_p(field, :model => model)
46
+ end
47
+ end
48
+
49
+ f << form_submit("Submit #{model.class.to_s.demodulize.titleize}")
50
+ end
51
+
52
+ # Makes a paragraph for accessing an attribute. Escapes the default value.
53
+ # Parameters:
54
+ # id => the HTML id/name of the form field.
55
+ # :type => the type of form field to generate (text, password, checkbox...)
56
+ # :description => The label for the field (inferred from id by default)
57
+ # :model => The model to query for fields
58
+ # :default => The default value for the field (inferred from model and id)
59
+ def form_p(id, params = {})
60
+ type = params[:type]
61
+ description = params[:description] || id.to_s.titleize
62
+ model = params[:model]
63
+ default = params[:default]
64
+ if model and not default
65
+ default = model.send(id)
66
+ end
67
+
68
+ unless type
69
+ case default
70
+ when true
71
+ type = 'checkbox'
72
+ when false
73
+ type = 'checkbox'
74
+ else
75
+ type = 'text'
76
+ end
77
+ end
78
+
79
+ f = '<p>'
80
+ unless type == 'checkbox' or type == 'hidden'
81
+ f << "<label for=\"#{id}\">#{description}</label>"
82
+ end
83
+
84
+ if type == 'textarea'
85
+ f << '<br />'
86
+ end
87
+
88
+ case type
89
+ when 'textarea'
90
+ f << "<textarea name=\"#{id}\" id=\"#{id}\">#{default}</textarea>"
91
+ when 'checkbox'
92
+ f << "<input type=\"checkbox\" name=\"#{id}\" id=\"#{id}\" #{default ? 'checked="checked"' : ''} />"
93
+ else
94
+ f << "<input name=\"#{id}\" id=\"#{id}\" type=\"#{type}\" value=\"#{attr_h(default)}\" />"
95
+ end
96
+
97
+ if type == 'checkbox'
98
+ f << "<label class=\"checkbox\" for=\"#{id}\">#{description}</label>"
99
+ end
100
+
101
+ f << "</p>\n"
102
+ end
103
+
104
+ def form_submit(value = "Submit")
105
+ '<p><input name="submit" type="submit" value="' + attr_h(value) + '" /></p>'
106
+ end
107
+
108
+ # Escapes quotes for HTML attributes.
109
+ def attr_h(string)
110
+ h(string).gsub('"', '&quot;')
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,142 @@
1
+ module Ramaze
2
+ module Helper
3
+ # Provides navigation rendering shortcuts
4
+ module Navigation
5
+ # Returns a div with next/up/previous links for the record.
6
+ def model_nav(model)
7
+ n = '<div class="navigation actions">'
8
+ if model.previous
9
+ n << ' <a class="previous" href="' + model.previous.url + '">&laquo; Previous ' + model.class.to_s.demodulize + '</a>'
10
+ end
11
+ n << ' <a class="up" href="' + model.absolute_window_url + '">Back to ' + model.class.to_s.demodulize.pluralize + '</a>'
12
+ if model.next
13
+ n << ' <a class="next" href="' + model.next.url + '">Next ' + model.class.to_s.demodulize + ' &raquo;</a>'
14
+ end
15
+ n << '</div>'
16
+ end
17
+
18
+ # Generate pagination links from a Sequenceable class and index.
19
+ # The index can be :first or :last for the corresponding pages, an instance
20
+ # of the class (in which case the page which would contain that instance
21
+ # is highlighted, or a page number. Limit determines how many numeric links
22
+ # to include--use :all to include all pages.
23
+ def page_nav(klass, index = nil, limit = 15)
24
+ # Translate :first, :last into corresponding windows.
25
+ case index
26
+ when :first
27
+ page = 0
28
+ when :last
29
+ page = klass.window_count - 1
30
+ when klass
31
+ # Index is actually an instance of the target class
32
+ page = index.window_absolute_index
33
+ else
34
+ # Index is a page number
35
+ page = index.to_i
36
+ end
37
+
38
+ pages = Array.new
39
+ links = '<ol class="pagination actions">'
40
+ window_count = klass.window_count
41
+
42
+ # Determine which pages to create links to
43
+ if limit.kind_of? Integer and window_count > limit
44
+ # There are more pages than we can display.
45
+
46
+ # Default first and last pages are the size of the collection
47
+ first_page = 1
48
+ last_page = window_count - 2
49
+
50
+ # The desired number of previous or next pages
51
+ previous_pages = (Float(limit - 3) / 2).floor
52
+ next_pages = (Float(limit - 3) / 2).floor
53
+
54
+ if (offset = first_page - (page - previous_pages)) > 0
55
+ # Window extends before the start of the pages
56
+ last_page = first_page + (limit - 2)
57
+ elsif (offset = (page + next_pages) - last_page) > 0
58
+ # Window extends beyond the end of the pages
59
+ first_page = last_page - (limit - 2)
60
+ else
61
+ # Window is somewhere in the middle
62
+ first_page = page - previous_pages
63
+ last_page = page + next_pages
64
+ end
65
+
66
+ # Generate list of pages
67
+ pages = [0] + (first_page..last_page).to_a + [window_count - 1]
68
+ else
69
+ # The window encompasses the entire set of pages
70
+ pages = (0 .. window_count - 1).to_a
71
+ end
72
+
73
+ if page > 0
74
+ # Add "previous page" link.
75
+ links << "<li><a href=\"#{klass.url}/page/#{page - 1}\">&laquo; Previous</a></li>"
76
+ end
77
+
78
+ # Convert pages to links
79
+ unless pages.empty?
80
+ pages.inject(pages.first - 1) do |previous, i|
81
+ if (i - previous) > 1
82
+ # These pages are not side-by-side.
83
+ links << '<li>&hellip;</li>'
84
+ end
85
+
86
+ if i == page
87
+ # This is a link to the current page.
88
+ links << "<li class=\"current\">#{i + 1}</li>"
89
+ else
90
+ # This is a link to a different page.
91
+ links << "<li><a href=\"#{klass.url}/page/#{i}\">#{i + 1}</a></li>"
92
+ end
93
+
94
+ # Remember this as the previous page.
95
+ i
96
+ end
97
+ end
98
+
99
+ if page < klass.window_count - 1
100
+ # Add "next page" link.
101
+ links << "<li><a href=\"#{klass.url}/page/#{page + 1}\">Next &raquo;</a></li>"
102
+ end
103
+
104
+ links << '</ol>'
105
+ end
106
+
107
+ # Returns a link to a user.
108
+ def user_link(x)
109
+ case x
110
+ when CortexReaver::User
111
+ name = x.name || x.login
112
+ A(name, :href => x.url)
113
+ when CortexReaver::Comment
114
+ if x.user
115
+ # Use attached user
116
+ user_link x.user
117
+ else
118
+ # Use anonymous info
119
+ name = x.name || x.email || 'Anonymous'
120
+ if x.email
121
+ s = "<a href=\"mailto:#{attr_h x.email}\">#{h name}</a>"
122
+ if x.http
123
+ s << " (<a href=\"#{attr_h x.http}\" rel=\"nofollow\">#{h x.http}</a>)"
124
+ end
125
+ s
126
+ elsif x.http
127
+ "<a href=\"#{attr_h x.http}\" rel=\"nofollow\">#{h name}</a>"
128
+ else
129
+ h name
130
+ end
131
+ end
132
+ else
133
+ if x.respond_to? :user
134
+ user_link x.user
135
+ else
136
+ raise ArgumentError.new("don't know how to make a user link to #{x.inspect}")
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,25 @@
1
+ module Ramaze
2
+ module Helper
3
+ # Helps display photographs
4
+ module Photographs
5
+ def description_of(photo)
6
+ begin
7
+ if exif = photo.exif
8
+ description = ''
9
+ description << photo.date.strftime('%m/%d/%Y') + ': '
10
+ description << exif.make if exif.make
11
+ description << ' ' + exif.model + ', ' if exif.model
12
+ description << ' ' + exif.focal_length_in_35mm_film.to_i.to_s + 'mm' if exif.focal_length_in_35mm_film
13
+ description << ' at ' + exposure_time_to_s(exif.exposure_time) if exif.exposure_time
14
+ description << ' F' + exif.f_number.to_f.to_s if exif.f_number
15
+ else
16
+ nil
17
+ end
18
+ rescue
19
+ # File might not be available, or EXIF might be missing...
20
+ return description
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,47 @@
1
+ module Ramaze
2
+ module Helper
3
+ module Tags
4
+ # Adds an AJAX-ified tag editor for a model.
5
+ def live_tags_field(model, opts={:name => 'tags'})
6
+ name = opts[:name]
7
+ title = opts[:title] || name.to_s.titleize
8
+
9
+ s = "<p><label for=\"#{name}\">#{title}</label>"
10
+ s << "<input name=\"#{name}\" id=\"#{name}\" type=\"text\" class=\"autobox\" value=\"#{attr_h(tags_on(model, false))}\" />"
11
+ s << "</p>"
12
+
13
+ s << <<EOF
14
+
15
+ <script type="text/javascript">
16
+ /* <![CDATA[ */
17
+
18
+
19
+ /* ]]> */
20
+ </script>
21
+ EOF
22
+ end
23
+
24
+ # Returns an html list of tags on a model that supports #tags.
25
+ def tags_on(model, html=true)
26
+ begin
27
+ if html
28
+ t = '<ul class="tags">'
29
+ model.tags.each do |tag|
30
+ t << "<li><a href=\"#{tag.url}\">#{tag.title}</a></li>"
31
+ end
32
+ t << '</ul>'
33
+ else
34
+ t = model.tags.map{ |t| t.title }.join(', ')
35
+ end
36
+ rescue
37
+ # HACK: This is probably only going to break because a blank model is
38
+ # missing a primary key or something like that. Since we call this
39
+ # method SO much (and because that specific error is not subclassed
40
+ # by Sequel) no custom error handling here.
41
+ ''
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+
@@ -0,0 +1,27 @@
1
+ module Ramaze
2
+ module Helper
3
+ # Provides workflow links on a per-section basis
4
+ module Workflow
5
+ def workflows
6
+ @workflows
7
+ end
8
+
9
+ def workflow(name, href)
10
+ @workflows ||= []
11
+ @workflows << [name, href]
12
+ end
13
+
14
+ def workflowbox
15
+ if @workflows
16
+ b = '<div class="workflows">'
17
+ b << ' <ul>'
18
+ @workflows.each do |name, href|
19
+ b << " <li><a href=\"#{href}\">#{name}</a></li>"
20
+ end
21
+ b << ' </ul>'
22
+ b << '</div>'
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end