cortex-reaver 0.0.7 → 0.0.8

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 (45) hide show
  1. data/bin/cortex_reaver +3 -0
  2. data/lib/cortex_reaver.rb +12 -6
  3. data/lib/cortex_reaver/controller/admin.rb +16 -1
  4. data/lib/cortex_reaver/controller/comment.rb +6 -2
  5. data/lib/cortex_reaver/controller/documentation.rb +3 -0
  6. data/lib/cortex_reaver/controller/journal.rb +8 -1
  7. data/lib/cortex_reaver/controller/main.rb +19 -7
  8. data/lib/cortex_reaver/controller/page.rb +8 -1
  9. data/lib/cortex_reaver/controller/photograph.rb +9 -2
  10. data/lib/cortex_reaver/controller/project.rb +8 -1
  11. data/lib/cortex_reaver/controller/user.rb +6 -1
  12. data/lib/cortex_reaver/helper/attachments.rb +5 -2
  13. data/lib/cortex_reaver/helper/auth.rb +24 -10
  14. data/lib/cortex_reaver/helper/crud.rb +36 -21
  15. data/lib/cortex_reaver/helper/feeds.rb +3 -3
  16. data/lib/cortex_reaver/helper/navigation.rb +6 -6
  17. data/lib/cortex_reaver/migrations/010_pageparents.rb +3 -2
  18. data/lib/cortex_reaver/migrations/011_user_roles.rb +19 -0
  19. data/lib/cortex_reaver/migrations/012_created_by_edited_by.rb +23 -0
  20. data/lib/cortex_reaver/model/comment.rb +4 -2
  21. data/lib/cortex_reaver/model/journal.rb +2 -1
  22. data/lib/cortex_reaver/model/page.rb +2 -1
  23. data/lib/cortex_reaver/model/photograph.rb +2 -1
  24. data/lib/cortex_reaver/model/project.rb +2 -1
  25. data/lib/cortex_reaver/model/user.rb +87 -9
  26. data/lib/cortex_reaver/support/comments.rb +1 -1
  27. data/lib/cortex_reaver/version.rb +1 -1
  28. data/lib/cortex_reaver/view/admin/index.rhtml +1 -0
  29. data/lib/cortex_reaver/view/adminbox.rhtml +5 -3
  30. data/lib/cortex_reaver/view/comments/comment.rhtml +3 -1
  31. data/lib/cortex_reaver/view/comments/post_form.rhtml +1 -1
  32. data/lib/cortex_reaver/view/documentation/users.rhtml +21 -0
  33. data/lib/cortex_reaver/view/error.rhtml +1 -1
  34. data/lib/cortex_reaver/view/journals/journal.rhtml +5 -3
  35. data/lib/cortex_reaver/view/pages/list.rhtml +6 -2
  36. data/lib/cortex_reaver/view/photographs/show.rhtml +1 -1
  37. data/lib/cortex_reaver/view/projects/list.rhtml +6 -2
  38. data/lib/cortex_reaver/view/projects/show.rhtml +4 -2
  39. data/lib/cortex_reaver/view/tags/list.rhtml +7 -3
  40. data/lib/cortex_reaver/view/tags/show.rhtml +3 -1
  41. data/lib/cortex_reaver/view/text_layout.rhtml +1 -1
  42. data/lib/cortex_reaver/view/users/form.rhtml +4 -1
  43. data/lib/cortex_reaver/view/users/list.rhtml +6 -2
  44. data/lib/cortex_reaver/view/users/show.rhtml +2 -5
  45. metadata +5 -2
data/bin/cortex_reaver CHANGED
@@ -162,8 +162,11 @@ module CortexReaver
162
162
  when :migrate
163
163
  version = @values[:schema_version]
164
164
 
165
+ # Get ready
165
166
  reload_config
166
167
  setup_db false
168
+ init
169
+
167
170
  puts "Using database #{config[:database][:host]}/#{config[:database][:database]}."
168
171
 
169
172
  current_version = Sequel::Migrator.get_current_migration_version(db)
data/lib/cortex_reaver.rb CHANGED
@@ -180,14 +180,20 @@ module CortexReaver
180
180
  # Shutdown callback
181
181
  at_exit do
182
182
  # Unlink templates
183
- Find.find(config[:view_root]) do |path|
184
- if File.symlink? path # TODO: identify link target
185
- begin
186
- File.delete path
187
- rescue => e
188
- Ramaze::Log.error "Unable to unlink symlinked view #{path}: #{e}"
183
+ begin
184
+ if config[:view_root]
185
+ Find.find(config[:view_root]) do |path|
186
+ if File.symlink? path # TODO: identify link target
187
+ begin
188
+ File.delete path
189
+ rescue => e
190
+ Ramaze::Log.error "Unable to unlink symlinked view #{path}: #{e}"
191
+ end
192
+ end
189
193
  end
190
194
  end
195
+ rescue => e2
196
+ Ramaze::Log.error "Unable to unlink symlinked views in #{config[:view_root]}: #{e}"
191
197
  end
192
198
 
193
199
  # Remove pidfile
@@ -8,11 +8,26 @@ module CortexReaver
8
8
  helper :error,
9
9
  :auth,
10
10
  :form,
11
- :workflow
11
+ :workflow,
12
+ :aspect
12
13
 
14
+ before_all do
15
+ require_roles :admin
16
+ end
17
+
13
18
  def index
14
19
  end
15
20
 
21
+ # Recalculate comment counts
22
+ def update_comments
23
+ [Journal, Page, Project, Photograph].each do |klass|
24
+ klass.refresh_comment_counts
25
+ end
26
+
27
+ flash[:notice] = "Comment counts updated."
28
+ redirect Rs()
29
+ end
30
+
16
31
  # Recalculate tag counts and vacuum unused tags
17
32
  def update_tags
18
33
  @updated = Tag.refresh_counts
@@ -34,7 +34,7 @@ module CortexReaver
34
34
  # User-specific properties
35
35
  if session[:user]
36
36
  # A user is logged in.
37
- comment.user = session[:user]
37
+ comment.creator = session[:user]
38
38
  else
39
39
  # Save the anonymous comment.
40
40
  comment.name = request[:name].blank? ? nil : request[:name]
@@ -43,6 +43,10 @@ module CortexReaver
43
43
  end
44
44
  end
45
45
 
46
+ on_update do |journal, request|
47
+ journal.updater = session[:user]
48
+ end
49
+
46
50
  for_feed do |comment, x|
47
51
  x.content comment.body_cache, :type => 'html'
48
52
  end
@@ -84,7 +88,7 @@ module CortexReaver
84
88
 
85
89
  if session[:user]
86
90
  # A user is logged in. Use their account.
87
- @comment.user = session[:user]
91
+ @comment.creator = session[:user]
88
92
  else
89
93
  # Use anonymous info, if it won't conflict.
90
94
  if User.filter(:email => request[:email]).count > 0
@@ -6,5 +6,8 @@ module CortexReaver
6
6
 
7
7
  def formatting
8
8
  end
9
+
10
+ def users
11
+ end
9
12
  end
10
13
  end
@@ -34,7 +34,14 @@ module CortexReaver
34
34
  on_save do |journal, request|
35
35
  journal.title = request[:title]
36
36
  journal.name = Journal.canonicalize(request[:name], :id => journal.id)
37
- journal.user = session[:user]
37
+ end
38
+
39
+ on_create do |journal, request|
40
+ journal.creator = session[:user]
41
+ end
42
+
43
+ on_update do |journal, request|
44
+ journal.updater = session[:user]
38
45
  end
39
46
 
40
47
  for_feed do |journal, x|
@@ -24,9 +24,13 @@ module CortexReaver
24
24
  if not ids.empty? and @page = Page.get(ids)
25
25
  # Render that page.
26
26
  @title = @page.title
27
-
28
- workflow "Edit this page", R(PageController, :edit, @page.id)
29
- workflow "Delete this page", R(PageController, :delete, @page.id)
27
+
28
+ if user.can_edit? Page.new
29
+ workflow "Edit this page", R(PageController, :edit, @page.id)
30
+ end
31
+ if user.can_delete? Page.new
32
+ workflow "Delete this page", R(PageController, :delete, @page.id)
33
+ end
30
34
 
31
35
  render_template 'pages/show'
32
36
  elsif not ids.empty?
@@ -42,10 +46,18 @@ module CortexReaver
42
46
  @sidebar.unshift render_template('photographs/sidebar.rhtml')
43
47
  end
44
48
 
45
- workflow "New Journal", R(JournalController, :new)
46
- workflow "New Page", R(PageController, :new)
47
- workflow "New Photograph", R(PhotographController, :new)
48
- workflow "New Project", R(ProjectController, :new)
49
+ if user.can_create? Journal.new
50
+ workflow "New Journal", R(JournalController, :new)
51
+ end
52
+ if user.can_create? Page.new
53
+ workflow "New Page", R(PageController, :new)
54
+ end
55
+ if user.can_create? Photograph.new
56
+ workflow "New Photograph", R(PhotographController, :new)
57
+ end
58
+ if user.can_create? Project.new
59
+ workflow "New Project", R(ProjectController, :new)
60
+ end
49
61
 
50
62
  feed 'Photographs', Rs(PhotographController, :atom)
51
63
  feed 'Journals', Rs(JournalController, :atom)
@@ -30,7 +30,14 @@ module CortexReaver
30
30
  page.page_id = request[:page_id]
31
31
  page.name = Page.canonicalize request[:name], :id => page.id, :page_id => page.page_id
32
32
  page.body = request[:body]
33
- page.user = session[:user]
33
+ end
34
+
35
+ on_create do |page, request|
36
+ page.creator = session[:user]
37
+ end
38
+
39
+ on_update do |page, request|
40
+ page.updater = session[:user]
34
41
  end
35
42
  end
36
43
  end
@@ -31,7 +31,6 @@ module CortexReaver
31
31
  on_save do |photograph, request|
32
32
  photograph.title = request[:title]
33
33
  photograph.name = Photograph.canonicalize request[:name], :id => photograph.id
34
- photograph.user = session[:user]
35
34
  end
36
35
 
37
36
  on_second_save do |photograph, request|
@@ -39,7 +38,15 @@ module CortexReaver
39
38
  photograph.image = request[:image][:tempfile] if request[:image]
40
39
  photograph.infer_date_from_exif! if request[:infer_date]
41
40
 
42
- MainController.action_cache.clear
41
+ MainController.send(:action_cache).clear
42
+ end
43
+
44
+ on_create do |photograph, request|
45
+ photograph.creator = session[:user]
46
+ end
47
+
48
+ on_update do |photograph, request|
49
+ photograph.updater = session[:user]
43
50
  end
44
51
 
45
52
  for_feed do |photograph, x|
@@ -33,7 +33,14 @@ module CortexReaver
33
33
  project.description = request[:description]
34
34
  project.name = Project.canonicalize request[:name], :id => project.id
35
35
  project.body = request[:body]
36
- project.user = session[:user]
36
+ end
37
+
38
+ on_create do |project, request|
39
+ project.creator = session[:user]
40
+ end
41
+
42
+ on_update do |project, request|
43
+ project.updater = session[:user]
37
44
  end
38
45
 
39
46
  for_feed do |project, x|
@@ -25,6 +25,9 @@ module CortexReaver
25
25
  user.http = request[:http]
26
26
  user.email = request[:email]
27
27
  user.admin = request[:admin] || false
28
+ user.editor = request[:editor] || false
29
+ user.contributor = request[:contributor] || false
30
+ user.moderator = request[:moderator] || false
28
31
 
29
32
  unless request[:password].blank? and request[:password_confirmation].blank?
30
33
  # Set password
@@ -35,7 +38,9 @@ module CortexReaver
35
38
 
36
39
  # Listing users outright is a little dodgy.
37
40
  before :index do
38
- require_admin
41
+ for_auth do |u|
42
+ u.admin?
43
+ end
39
44
  end
40
45
 
41
46
  def login
@@ -6,13 +6,16 @@ module Ramaze
6
6
 
7
7
  # Deletes an attachment on a model identified by id.
8
8
  def delete_attachment(id, name)
9
- require_admin
10
-
11
9
  unless @model = model_class.get(id)
12
10
  flash[:error] = "No such #{model_class.to_s.downcase} (#{h id}) exists."
13
11
  redirect Rs()
14
12
  end
15
13
 
14
+ # You need to be able to edit the model before removing attachments!
15
+ for_auth do |u|
16
+ u.can_edit? @model
17
+ end
18
+
16
19
  unless attachment = @model.attachment(name)
17
20
  flash[:error] = "No such attachment (#{h name}) exists."
18
21
  redirect @model.url
@@ -7,6 +7,20 @@ module Ramaze
7
7
  u = session[:user] and u.admin?
8
8
  end
9
9
 
10
+ def for_auth(&block)
11
+ unless yield user
12
+ # Failed block
13
+ if session[:user]
14
+ flash[:error] = "You don't have permission to do this."
15
+ redirect :/
16
+ else
17
+ flash[:notice] = "Please log in first."
18
+ session[:target_uri] = request.request_uri
19
+ redirect R('/users', :login)
20
+ end
21
+ end
22
+ end
23
+
10
24
  # Tries to log in a user by login and password. If successful, sets
11
25
  # session[:user] to the user and returns that user. Otherwise returns
12
26
  # false.
@@ -24,19 +38,19 @@ module Ramaze
24
38
  session.delete :user
25
39
  end
26
40
 
27
- def require_admin
28
- if session[:user] and session[:user].admin?
29
- true
30
- elsif session[:user]
31
- flash[:error] = "You must have administrative privileges to do this."
32
- redirect :/
33
- else
34
- flash[:notice] = "Please log in first."
35
- session[:target_uri] = request.request_uri
36
- redirect R('/users', :login)
41
+ def require_roles(*roles)
42
+ for_auth do |u|
43
+ roles.any? do |role|
44
+ u.send role
45
+ end
37
46
  end
38
47
  end
39
48
 
49
+ # Shortcut for current user or an anonymous proxy
50
+ def user
51
+ session[:user] || CortexReaver::User.new(:name => 'Anonymous')
52
+ end
53
+
40
54
  def error_403
41
55
  respond 'Forbidden', 403
42
56
  end
@@ -94,7 +94,10 @@ module Ramaze
94
94
 
95
95
  # This action can't be in the normal module body, or it breaks things.
96
96
  def new
97
- require_admin
97
+ # You need to be able to create one of these.
98
+ for_auth do |u|
99
+ u.can_create? model_class.new
100
+ end
98
101
 
99
102
  @title = "New #{h model_class.to_s.demodulize.titleize}"
100
103
  @form_action = :new
@@ -174,9 +177,11 @@ module Ramaze
174
177
  end
175
178
 
176
179
  def delete(id)
177
- require_admin
178
-
179
180
  if @model = model_class[id]
181
+ for_auth do |u|
182
+ u.can_edit? @model
183
+ end
184
+
180
185
  if @model.destroy
181
186
  flash[:notice] = "#{model_class.to_s.demodulize.downcase} #{h @model.to_s} deleted."
182
187
  redirect Rs()
@@ -191,9 +196,11 @@ module Ramaze
191
196
  end
192
197
 
193
198
  def edit(id = nil)
194
- require_admin
195
-
196
199
  if @model = model_class[id]
200
+ for_auth do |u|
201
+ u.can_edit? @model
202
+ end
203
+
197
204
  @title = "Edit #{model_class.to_s.demodulize.downcase} #{h @model.to_s}"
198
205
  @form_action = "edit/#{@model.id}"
199
206
 
@@ -270,7 +277,9 @@ module Ramaze
270
277
 
271
278
  set_plural_model_var @models
272
279
 
273
- workflow "New #{model_class.to_s.demodulize}", Rs(:new)
280
+ if user.can_create? model_class.new
281
+ workflow "New #{model_class.to_s.demodulize}", Rs(:new)
282
+ end
274
283
 
275
284
  render_template :list
276
285
  end
@@ -284,24 +293,30 @@ module Ramaze
284
293
  @title = h @model.to_s
285
294
  set_singular_model_var @model
286
295
 
287
- # Retrieve pending comment from session, if applicable.
288
- if comment = session[:pending_comment] and comment.parent == @model
289
- @new_comment = session.delete :pending_comment
290
- else
291
- # Create a comment to be posted
292
- @new_comment = CortexReaver::Comment.new
293
- @new_comment.send("#{model_class.to_s.demodulize.underscore.downcase}=", @model)
294
- end
296
+ if @model.class.associations.include? :comments
297
+ # Retrieve pending comment from session, if applicable.
298
+ if comment = session[:pending_comment] and comment.parent == @model
299
+ @new_comment = session.delete :pending_comment
300
+ else
301
+ # Create a comment to be posted
302
+ @new_comment = CortexReaver::Comment.new
303
+ @new_comment.send("#{model_class.to_s.demodulize.underscore.downcase}=", @model)
304
+ end
295
305
 
296
- if session[:user]
297
- @new_comment.user = session[:user]
306
+ if session[:user]
307
+ @new_comment.creator = session[:user]
308
+ end
298
309
  end
299
310
 
300
- # ID component of edit/delete links
301
-
302
- workflow "New #{model_class.to_s.demodulize}", Rs(:new)
303
- workflow "Edit this #{model_class.to_s.demodulize}", Rs(:edit, @model.id)
304
- workflow "Delete this #{model_class.to_s.demodulize}", Rs(:delete, @model.id)
311
+ if user.can_create? model_class.new
312
+ workflow "New #{model_class.to_s.demodulize}", Rs(:new)
313
+ end
314
+ if user.can_edit? @model
315
+ workflow "Edit this #{model_class.to_s.demodulize}", Rs(:edit, @model.id)
316
+ end
317
+ if user.can_delete? @model
318
+ workflow "Delete this #{model_class.to_s.demodulize}", Rs(:delete, @model.id)
319
+ end
305
320
 
306
321
  render_template :show
307
322
  elsif id
@@ -77,10 +77,10 @@ module Ramaze
77
77
  x.link :href => (url_base + model.url), :rel => 'alternate'
78
78
 
79
79
  x.author do
80
- x.name model.user.name
80
+ x.name model.creator.name
81
81
 
82
- if model.user.http
83
- x.uri model.user.http
82
+ if model.creator.http
83
+ x.uri model.creator.http
84
84
  end
85
85
  end
86
86
 
@@ -121,15 +121,15 @@ module Ramaze
121
121
  end
122
122
 
123
123
  # Returns a link to a user.
124
- def user_link(x)
124
+ def user_link(x, who=:creator)
125
125
  case x
126
126
  when CortexReaver::User
127
127
  name = x.name || x.login
128
128
  A(name, :href => x.url)
129
129
  when CortexReaver::Comment
130
- if x.user
131
- # Use attached user
132
- user_link x.user
130
+ if x.send(who)
131
+ # Use attached creator/whoever
132
+ user_link x.send(who)
133
133
  else
134
134
  # Use anonymous info
135
135
  name = x.name || x.email || 'Anonymous'
@@ -146,8 +146,8 @@ module Ramaze
146
146
  end
147
147
  end
148
148
  else
149
- if x.respond_to? :user
150
- user_link x.user
149
+ if x.respond_to? who
150
+ user_link x.send(who)
151
151
  else
152
152
  raise ArgumentError.new("don't know how to make a user link to #{x.inspect}")
153
153
  end
@@ -2,8 +2,9 @@ module CortexReaver
2
2
  class PageparentsSchema < Sequel::Migration
3
3
  def down
4
4
  alter_table :pages do
5
- drop_index :page_id
6
- drop_column :page_id
5
+ # Can't undo this cleanly yet. Fracking mysql. :/
6
+ # drop_index :page_id
7
+ # drop_column :page_id
7
8
  end
8
9
  end
9
10
 
@@ -0,0 +1,19 @@
1
+ module CortexReaver
2
+ class UserrolesSchema < Sequel::Migration
3
+ def down
4
+ alter_table :users do
5
+ drop_column :contributor
6
+ drop_column :editor
7
+ drop_column :moderator
8
+ end
9
+ end
10
+
11
+ def up
12
+ alter_table :users do
13
+ add_column :contributor, :boolean, :default => false
14
+ add_column :editor, :boolean, :default => false
15
+ add_column :moderator, :boolean, :default => false
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,23 @@
1
+ module CortexReaver
2
+ class CreatedbyeditedbySchema < Sequel::Migration
3
+ def down
4
+ [:journals, :comments, :pages, :photographs, :projects].each do |table|
5
+ alter_table table do
6
+ rename_column :created_by, :user_id, :type => :integer
7
+ # Can't do this yet.
8
+ # drop_column :updated_by
9
+ end
10
+ end
11
+ end
12
+
13
+ def up
14
+ [:journals, :comments, :pages, :photographs, :projects].each do |table|
15
+ alter_table table do
16
+ rename_column :user_id, :created_by, :type => :integer
17
+ add_foreign_key :updated_by, :users, :key => :id
18
+ add_index :updated_by
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -6,7 +6,8 @@ module CortexReaver
6
6
  include CortexReaver::Model::Comments
7
7
  include CortexReaver::Model::Sequenceable
8
8
 
9
- belongs_to :user, :class => 'CortexReaver::User'
9
+ belongs_to :creator, :class => 'CortexReaver::User', :key => 'created_by'
10
+ belongs_to :updater, :class => 'CortexReaver::User', :key => 'updated_by'
10
11
  belongs_to :journal, :class => 'CortexReaver::Journal'
11
12
  belongs_to :project, :class => 'CortexReaver::Project'
12
13
  belongs_to :photograph, :class => 'CortexReaver::Photograph'
@@ -65,7 +66,8 @@ module CortexReaver
65
66
  parent.skip_timestamp_update = true
66
67
  parent.save
67
68
  end
68
- after_save(:refresh_parent_comment_count) do
69
+
70
+ after_create(:increment_parent_comment_count) do
69
71
  # WARNING: If we *reparent* comments as opposed to just posting, this will break.
70
72
  parent = self.parent
71
73
  parent.comment_count += 1
@@ -10,7 +10,8 @@ module CortexReaver
10
10
  include CortexReaver::Model::Sequenceable
11
11
 
12
12
  many_to_many :tags, :class => 'CortexReaver::Tag'
13
- belongs_to :user, :class => 'CortexReaver::User'
13
+ belongs_to :creator, :class => 'CortexReaver::User', :key => 'created_by'
14
+ belongs_to :updater, :class => 'CortexReaver::User', :key => 'updated_by'
14
15
  has_many :comments, :class => 'CortexReaver::Comment'
15
16
 
16
17
  validates do
@@ -11,7 +11,8 @@ module CortexReaver
11
11
 
12
12
  belongs_to :page, :class => 'CortexReaver::Page'
13
13
  has_many :pages, :class => 'CortexReaver::Page'
14
- belongs_to :user, :class => 'CortexReaver::User'
14
+ belongs_to :creator, :class => 'CortexReaver::User', :key => 'created_by'
15
+ belongs_to :updater, :class => 'CortexReaver::User', :key => 'updated_by'
15
16
  has_many :comments, :class => 'CortexReaver::Comment'
16
17
  many_to_many :tags, :class => 'CortexReaver::Tag'
17
18
 
@@ -18,7 +18,8 @@ module CortexReaver
18
18
  }
19
19
 
20
20
  many_to_many :tags, :class => 'CortexReaver::Tag'
21
- belongs_to :user, :class => 'CortexReaver::User'
21
+ belongs_to :creator, :class => 'CortexReaver::User', :key => 'created_by'
22
+ belongs_to :updater, :class => 'CortexReaver::User', :key => 'updated_by'
22
23
  has_many :comments, :class => 'CortexReaver::Comment'
23
24
 
24
25
  validates do
@@ -10,7 +10,8 @@ module CortexReaver
10
10
  include CortexReaver::Model::Sequenceable
11
11
 
12
12
  many_to_many :tags, :class => 'CortexReaver::Tag'
13
- belongs_to :user, :class => 'CortexReaver::User'
13
+ belongs_to :creator, :class => 'CortexReaver::User', :key => 'created_by'
14
+ belongs_to :updater, :class => 'CortexReaver::User', :key => 'updated_by'
14
15
  has_many :comments, :class => 'CortexReaver::Comment'
15
16
 
16
17
  validates do
@@ -5,11 +5,16 @@ module CortexReaver
5
5
  include CortexReaver::Model::Timestamps
6
6
  include CortexReaver::Model::Sequenceable
7
7
 
8
- has_many :comments, :class => 'CortexReaver::Comment'
9
- has_many :journals, :class => 'CortexReaver::Journal'
10
- has_many :pages, :class => 'CortexReaver::Page'
11
- has_many :photographs, :class => 'CortexReaver::Photograph'
12
- has_many :projects, :class => 'CortexReaver::Project'
8
+ has_many :created_comments, :key => 'created_by', :class => 'CortexReaver::Comment'
9
+ has_many :created_journals, :key => 'created_by', :class => 'CortexReaver::Journal'
10
+ has_many :created_pages, :key => 'created_by', :class => 'CortexReaver::Page'
11
+ has_many :created_photographs, :key => 'created_by', :class => 'CortexReaver::Photograph'
12
+ has_many :created_projects, :key => 'created_by', :class => 'CortexReaver::Project'
13
+ has_many :updated_comments, :key => 'updated_by', :class => 'CortexReaver::Comment'
14
+ has_many :updated_journals, :key => 'updated_by', :class => 'CortexReaver::Journal'
15
+ has_many :updated_pages, :key => 'updated_by', :class => 'CortexReaver::Page'
16
+ has_many :updated_photographs, :key => 'updated_by', :class => 'CortexReaver::Photograph'
17
+ has_many :updated_projects, :key => 'updated_by', :class => 'CortexReaver::Project'
13
18
 
14
19
  validates do
15
20
  uniqueness_of :login
@@ -29,10 +34,9 @@ module CortexReaver
29
34
  end
30
35
  end
31
36
 
32
- # Ensure an administrator is always available. TODO: This is probably
33
- # subject to a race condition, especially between servers. Backup plan?
37
+ # Ensure an administrator is always available.
34
38
  validates_each :admin do |object, attribute, value|
35
- if User.filter(:admin => true).count == 1 and not value
39
+ if admins = User.filter(:admin => true) and admins.size == 1 and admins.first.id == self.id and not value
36
40
  object.errors[attribute] << "can't be unset; only one administrator left!"
37
41
  end
38
42
  end
@@ -48,7 +52,7 @@ module CortexReaver
48
52
  nil
49
53
  end
50
54
  end
51
-
55
+
52
56
  # CRUD uses this to construct URLs. Even though we don't need the full
53
57
  # power of Canonical, CRUD is pretty useful. :)
54
58
  def self.canonical_name_attr
@@ -74,6 +78,80 @@ module CortexReaver
74
78
  end
75
79
  end
76
80
 
81
+ def can_create?(other)
82
+ if admin?
83
+ # Administrators may create anything
84
+ true
85
+ elsif contributor?
86
+ # Contributors may create anything but users
87
+ case other
88
+ when User
89
+ false
90
+ else
91
+ true
92
+ end
93
+ else
94
+ # Anyone may create a comment.
95
+ case other
96
+ when Comment
97
+ true
98
+ else
99
+ false
100
+ end
101
+ end
102
+ end
103
+
104
+ def can_delete?(other)
105
+ if admin?
106
+ # Administrators may delete anything
107
+ true
108
+ elsif other.respond_to? :created_by and other.created_by == self.id
109
+ # Anybody may delete their own records.
110
+ true
111
+ elsif editor? and not User === other
112
+ # Editors may delete anything but users.
113
+ true
114
+ elsif moderator? and Comment === other
115
+ # Moderators may delete comments.
116
+ true
117
+ else
118
+ false
119
+ end
120
+ end
121
+
122
+ def can_edit?(other)
123
+ if admin?
124
+ # Administrators may edit anything
125
+ true
126
+ elsif other.respond_to? :created_by and other.created_by == self.id
127
+ # Anybody may edit their own records
128
+ true
129
+ elsif editor? and not User === other
130
+ # Editors may edit anything but other users.
131
+ true
132
+ elsif moderator and Comment === other
133
+ # Moderators may edit comments
134
+ true
135
+ else
136
+ false
137
+ end
138
+ end
139
+
140
+ # Returns true if user is a contributor
141
+ def contributor?
142
+ self.contributor
143
+ end
144
+
145
+ # Returns true if user is an editor
146
+ def editor?
147
+ self.editor
148
+ end
149
+
150
+ # Returns true if user is a moderator
151
+ def moderator?
152
+ self.moderator
153
+ end
154
+
77
155
  # Set user password
78
156
  def password=(password)
79
157
  self.salt ||= self.class.new_salt
@@ -5,7 +5,7 @@ module CortexReaver
5
5
  def self.included(base)
6
6
  base.class_eval do
7
7
  # When we delete a model that has comments, remove the comments too.
8
- before_delete(:drop_comments) do
8
+ before_destroy(:drop_comments) do
9
9
  comments = self.comments
10
10
  remove_all_comments
11
11
  comments.each do |comment|
@@ -1,6 +1,6 @@
1
1
  module CortexReaver
2
2
  APP_NAME = 'Cortex Reaver'
3
- APP_VERSION = '0.0.7'
3
+ APP_VERSION = '0.0.8'
4
4
  APP_AUTHOR = 'aphyr'
5
5
  APP_EMAIL = 'aphyr@aphyr.com'
6
6
  APP_URL = 'http://aphyr.com'
@@ -1,5 +1,6 @@
1
1
  <h2>Administration</h2>
2
2
 
3
3
  <ul>
4
+ <li><%= A('Update comment counts', :href => Rs(:update_comments)) %></li>
4
5
  <li><%= A('Update tags', :href => Rs(:update_tags)) %></li>
5
6
  </ul>
@@ -1,5 +1,5 @@
1
1
  <div id="adminbox">
2
- <% if admin? %>
2
+ <% if user.admin? or user.contributor? or user.editor? or user.moderator? %>
3
3
  <table class="actions-table">
4
4
  <tr>
5
5
  <td class="title">Sections</td>
@@ -11,8 +11,10 @@
11
11
  <li><a href="/photographs">Photographs</a></li>
12
12
  <li><a href="/comments">Comments</a></li>
13
13
  <li><a href="/tags">Tags</a></li>
14
- <li><a href="/users">Users</a></li>
15
- <li><a href="/admin">Admin</a></li>
14
+ <% if user.admin? %>
15
+ <li><a href="/users">Users</a></li>
16
+ <li><a href="/admin">Admin</a></li>
17
+ <% end %>
16
18
  </ul>
17
19
  </td>
18
20
  </tr>
@@ -14,10 +14,12 @@
14
14
  <img src="/images/comment.gif" class="icon" alt="comment" />
15
15
  <%= @comment.comment_count %> <%= @comment.comment_count == 1 ? 'comment' : 'comments' %>
16
16
  </a></li>
17
- <% if admin? %>
17
+ <% if user.can_edit? @comment %>
18
18
  <li><a href="/comments/edit/<%= @comment.id %>">
19
19
  <img src="/images/edit.gif" class="icon" alt="edit" /> Edit
20
20
  </a></li>
21
+ <% end %>
22
+ <% if user.can_delete? @comment %>
21
23
  <li>
22
24
  <%= A '<img src="/images/delete.gif" class="icon" alt="delete" /> Delete', :href => "/comments/delete/#{@comment.id}", :onclick => "return confirm('Are you sure you wish to delete this comment?');" %></li>
23
25
  <% end %>
@@ -26,7 +26,7 @@
26
26
  <textarea name="comment" id="comment"></textarea>
27
27
  </p>
28
28
 
29
- <% unless @new_comment.user %>
29
+ <% unless @new_comment.creator %>
30
30
  <%= form_p :name, :model => @new_comment %>
31
31
  <%= form_p :email, :model => @new_comment %>
32
32
  <%= form_p :http, :model => @new_comment %>
@@ -0,0 +1,21 @@
1
+ <div class="documentation">
2
+ <h2>Cortex Reaver Users</h2>
3
+
4
+ <p>Cortex Reaver has several roles which may apply to any user. These roles control what actions a user may perform.</p>
5
+
6
+ <dl>
7
+ <dt>Admin</dt>
8
+ <dd>Administrators may do anything: create, read, edit, and delete any post, journal, page, photograph, comment, or user, as well as performing maintenance.</dd>
9
+
10
+ <dt>Contributor</dt>
11
+ <dd>Contributors may create journals, pages, posts, etc., but can not affect users or site settings. They are also prohibited from editing or deleting work they did not create.
12
+
13
+ <dt>Editor</dt>
14
+ <dd>Editors review site content. They have permission to edit and delete any journal, page, post, etc. They cannot manage users or site settings.</dd>
15
+
16
+ <dt>Moderator</dt>
17
+ <dd>Moderators may edit and delete comments, to facilitate discussion.</dd>
18
+ </dl>
19
+
20
+ <p>All users may read content, post comments, and edit their own created material.</p>
21
+ </div>
@@ -1,4 +1,4 @@
1
- <% if admin? %>
1
+ <% if user.admin? %>
2
2
  <link rel="stylesheet" href="/css/ramaze_error.css" />
3
3
  <script type="text/javascript" src="/js/jquery.js"></script>
4
4
 
@@ -2,7 +2,7 @@
2
2
  <h2><a id="journal_<%= @journal.name %>" href="<%= @journal.url %>"><%=h @journal.title %></a></h2>
3
3
  <div class="byline">
4
4
  <span class="written">
5
- <%= user_link @journal.user %> on <%= date_line @journal %>
5
+ <%= user_link @journal.creator %> on <%= date_line @journal %>
6
6
  </span>
7
7
  <%= tags_on @journal %>
8
8
  </div>
@@ -16,11 +16,13 @@
16
16
  <img src="/images/comment.gif" class="icon" alt="comment" />
17
17
  <%= @journal.comment_count %> <%= @journal.comment_count == 1 ? 'comment' : 'comments' %>
18
18
  </a></li>
19
- <% if admin? %>
19
+ <% if user.can_edit? @journal %>
20
20
  <li><a class="edit-link" href="/journals/edit/<%= @journal.id %>">
21
21
  <img src="/images/edit.gif" class="icon" alt="edit" /> Edit
22
22
  </a></li>
23
- <li >
23
+ <% end %>
24
+ <% if user.can_delete? @journal %>
25
+ <li>
24
26
  <%= A '<img src="/images/delete.gif" class="icon" alt="delete" /> Delete', :href => "/journals/delete/#{@journal.id}", :onclick => "return confirm('Are you sure you want to delete this journal?');" %>
25
27
  </li>
26
28
  <% end %>
@@ -4,8 +4,10 @@
4
4
  <tr>
5
5
  <th>Name</th>
6
6
  <th>Title</th>
7
- <% if admin? %>
7
+ <% if user.can_edit? CortexReaver::Page.new %>
8
8
  <th></th>
9
+ <% end %>
10
+ <% if user.can_delete? CortexReaver::Page.new %>
9
11
  <th></th>
10
12
  <% end %>
11
13
  </tr>
@@ -15,8 +17,10 @@
15
17
  <tr>
16
18
  <td><%= A(page.name, :href => page.url) %></td>
17
19
  <td><%= page.title %></td>
18
- <% if admin? %>
20
+ <% if user.can_edit? page %>
19
21
  <td><a href="/pages/edit/<%= page.id %>">Edit</a></td>
22
+ <% end %>
23
+ <% if user.can_delete? page %>
20
24
  <td><%= A 'Delete', :href => "/pages/delete/#{page.id}", :onclick => "return confirm('Are you sure you want to delete this page?');" %></td>
21
25
  <% end %>
22
26
  </tr>
@@ -18,7 +18,7 @@
18
18
  <li>
19
19
  <a href="<%= @photograph.absolute_window_url %>">Back to Thumbnails</a>
20
20
  </li>
21
- <% if admin? %>
21
+ <% if user.can_edit? @photograph %>
22
22
  <li>
23
23
  <%= A('Edit', :href => Rs(:edit, @photograph.id)) %>
24
24
  </li>
@@ -5,8 +5,10 @@
5
5
  <tr>
6
6
  <th>Title</th>
7
7
  <th>Description</th>
8
- <% if admin? %>
8
+ <% if user.can_edit? CortexReaver::Project.new %>
9
9
  <th></th>
10
+ <% end %>
11
+ <% if user.can_delete? CortexReaver::Project.new %>
10
12
  <th></th>
11
13
  <% end %>
12
14
  </tr>
@@ -16,8 +18,10 @@
16
18
  <tr>
17
19
  <td><%= A(project.title, :href => project.url) %></td>
18
20
  <td><%= project.description %></td>
19
- <% if admin? %>
21
+ <% if user.can_edit? project %>
20
22
  <td><a href="/projects/edit/<%= project.name %>">Edit</a></td>
23
+ <% end %>
24
+ <% if user.can_delete? project %>
21
25
  <td><%= A 'Delete', :href => "/projects/delete/#{project.name}", :onclick => "return confirm('Are you sure you want to delete this project?');" %></td>
22
26
  <% end %>
23
27
  </tr>
@@ -2,7 +2,7 @@
2
2
  <h2><a id="project_<%= @project.name %>" href="<%= @project.url %>"><%=h @project.title %></a></h2>
3
3
  <div class="byline">
4
4
  <span class="written">
5
- <%= user_link @project.user %> on <%= date_line @project %>
5
+ <%= user_link @project.creator %> on <%= date_line @project %>
6
6
  </span>
7
7
  <%= tags_on @project %>
8
8
  </div>
@@ -17,10 +17,12 @@
17
17
  <img src="/images/comment.gif" class="icon" alt="comment" />
18
18
  <%= @project.comment_count %> <%= @project.comment_count == 1 ? 'comment' : 'comments' %>
19
19
  </a></li>
20
- <% if admin? %>
20
+ <% if user.can_edit? @project %>
21
21
  <li><a href="/projects/edit/<%= @project.id %>">
22
22
  <img src="/images/edit.gif" class="icon" alt="edit" /> Edit
23
23
  </a></li>
24
+ <% end %>
25
+ <% if user.can_delete? @project %>
24
26
  <li><%= A '<img src="/images/delete.gif" class="icon" alt="delete" /> Delete', :href => "/projects/delete/#{@project.id}", :onclick => "return confirm('Are you sure you want to delete this project?');" %></li>
25
27
  <% end %>
26
28
  </ul>
@@ -4,8 +4,10 @@
4
4
  <thead>
5
5
  <tr>
6
6
  <th>Tag</th>
7
- <% if admin? %>
7
+ <% if user.can_edit? CortexReaver::Tag.new %>
8
8
  <th></th>
9
+ <% end %>
10
+ <% if user.can_delete? CortexReaver::Tag.new %>
9
11
  <th></th>
10
12
  <% end %>
11
13
  <th>Popularity</th>
@@ -17,8 +19,10 @@
17
19
  <% @tags.each do |tag| %>
18
20
  <tr>
19
21
  <td class="title"><%= A(tag.title, :href => tag.url) %></td>
20
- <% if admin? %>
21
- <td><a href="/tags/edit/<%= tag.id %>">Edit</a></td>
22
+ <% if user.can_edit? tag %>
23
+ <td><a href="/tags/edit/<%= tag.id %>">Edit</a></td>
24
+ <% end %>
25
+ <% if user.can_delete? tag %>
22
26
  <td><%= A 'Delete', :href => "/tags/delete/#{tag.id}", :onclick => "return confirm('Are you sure you want to delete this tag?');" %></td>
23
27
  <% end %>
24
28
  <td class="count" style="width: <%= admin? ? 60 : 80 %>%"><div class="percent-bar" style="width: <%= tag.count.to_f / max_count * 100 %>%"><%= tag.count %></div></td>
@@ -40,10 +40,12 @@
40
40
  </div>
41
41
  <div class="footer">
42
42
  <ul class="actions">
43
- <% if admin? and @tags.size == 1 %>
43
+ <% if @tags.size == 1 and user.can_edit? @tags.first %>
44
44
  <li><a href="/tags/edit/<%= @tags.first.id %>">
45
45
  <img src="/images/edit.gif" class="icon" alt="comment" /> Edit
46
46
  </a></li>
47
+ <% end %>
48
+ <% if @tags.size == 1 and user.can_delete? @tags.first %>
47
49
  <li><%= A '<img src="/images/delete.gif" class="icon" alt="delete" /> Delete', :href => "/tags/delete/#{@tags.first.id}", :onclick => "return confirm('Are you sure you want to delete this tag?');" %></li>
48
50
  <% end %>
49
51
  </ul>
@@ -30,7 +30,7 @@
30
30
  <script type="text/javascript" src="/js/jquery.js"></script>
31
31
  <script type="text/javascript" defer="defer" src="/js/cookie.js"></script>
32
32
  <script type="text/javascript" defer="defer" src="/js/admin.js"></script>
33
- <% if admin? %>
33
+ <% if user.admin? or user.contributor? or user.editor? or user.moderator? %>
34
34
  <script type="text/javascript" defer="defer" src="/js/autocompletefb.js"></script>
35
35
  <% end %>
36
36
 
@@ -9,7 +9,10 @@
9
9
  <%= form_p 'email', :description => 'E-mail', :model => @user %>
10
10
  <%= form_p 'password', :type => 'password' %>
11
11
  <%= form_p 'password_confirmation', :type => 'password', :description => 'Confirm' %>
12
- <%= form_p :admin, :model => @user, :type => 'checkbox', :description => 'Admin?' %>
12
+ <%= form_p :admin, :model => @user, :type => 'checkbox', :description => 'Administrator' %>
13
+ <%= form_p :editor, :model => @user, :type => 'checkbox', :description => 'Editor' %>
14
+ <%= form_p :contributor, :model => @user, :type => 'checkbox', :description => 'Contributor' %>
15
+ <%= form_p :moderator, :model => @user, :type => 'checkbox', :description => 'Moderator' %>
13
16
  <p>
14
17
  <input type="submit" />
15
18
  </p>
@@ -7,8 +7,10 @@
7
7
  <tr>
8
8
  <th>Login</th>
9
9
  <th>Name</th>
10
- <% if admin? %>
10
+ <% if user.can_edit? CortexReaver::User.new %>
11
11
  <th></th>
12
+ <% end %>
13
+ <% if user.can_delete? CortexReaver::User.new %>
12
14
  <th></th>
13
15
  <% end %>
14
16
  </tr>
@@ -18,12 +20,14 @@
18
20
  <tr>
19
21
  <td><%= A(user.login, :href => user.url) %></td>
20
22
  <td><%= h user.name %></td>
21
- <% if admin? %>
23
+ <% if session[:user].can_edit? user %>
22
24
  <td>
23
25
  <a class="edit-link" href="/users/edit/<%= user.id %>">
24
26
  <img src="/images/edit.gif" class="icon" alt="edit" /> Edit
25
27
  </a>
26
28
  </td>
29
+ <% end %>
30
+ <% if session[:user].can_delete? user %>
27
31
  <td>
28
32
  <%= A '<img src="/images/delete.gif" class="icon" alt="delete" /> Delete', :href => "/users/delete/#{user.id}", :onclick => "return confirm('Are you sure you want to delete this user?');" %>
29
33
  </td>
@@ -1,9 +1,6 @@
1
1
  <div class="user">
2
2
  <h2><a id="user_<%= @user.login %>" href="<%= @user.url %>">User <%=h @user.name %></a></h2>
3
3
  <div class="byline">
4
- <% if @user.admin %>
5
- Administrator,
6
- <% end %>
7
4
  Created on <%= date_line @user %>
8
5
  </div>
9
6
  <div class="body">
@@ -26,8 +23,8 @@
26
23
  </div>
27
24
  <div class="footer">
28
25
  <ul class="actions">
29
- <% if admin? %>
30
- <li><a href="/users/edit/<%= @user.login %>">
26
+ <% if user.can_edit? @user %>
27
+ <li><a href="/users/edit/<%= @user.id %>">
31
28
  <img src="/images/edit.gif" class="icon" alt="comment" /> Edit
32
29
  </a></li>
33
30
  <li><%= A '<img src="/images/delete.gif" class="icon" alt="delete" /> Delete', :href => "/users/delete/#{@user.login}", :onclick => "return confirm('Are you sure you want to delete this user?');" %></li>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cortex-reaver
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - aphyr
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-03-18 00:00:00 -05:00
12
+ date: 2009-03-23 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -203,6 +203,7 @@ files:
203
203
  - lib/cortex_reaver/view/journals/form.rhtml
204
204
  - lib/cortex_reaver/view/blank_layout.rhtml
205
205
  - lib/cortex_reaver/view/documentation
206
+ - lib/cortex_reaver/view/documentation/users.rhtml
206
207
  - lib/cortex_reaver/view/documentation/formatting.rhtml
207
208
  - lib/cortex_reaver/plugin.rb
208
209
  - lib/cortex_reaver/model
@@ -264,6 +265,7 @@ files:
264
265
  - lib/cortex_reaver/snippets/array.rb
265
266
  - lib/cortex_reaver/migrations
266
267
  - lib/cortex_reaver/migrations/004_photographs.rb
268
+ - lib/cortex_reaver/migrations/011_user_roles.rb
267
269
  - lib/cortex_reaver/migrations/002_pages.rb
268
270
  - lib/cortex_reaver/migrations/005_projects.rb
269
271
  - lib/cortex_reaver/migrations/006_tags.rb
@@ -272,6 +274,7 @@ files:
272
274
  - lib/cortex_reaver/migrations/007_comments.rb
273
275
  - lib/cortex_reaver/migrations/009_mysql.rb
274
276
  - lib/cortex_reaver/migrations/001_users.rb
277
+ - lib/cortex_reaver/migrations/012_created_by_edited_by.rb
275
278
  - lib/cortex_reaver/migrations/003_journals.rb
276
279
  - lib/cortex_reaver/version.rb
277
280
  - lib/cortex_reaver.rb