cortex-reaver 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
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