cortex-reaver 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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