qcms 1.3.3

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 (53) hide show
  1. data/.gitignore +14 -0
  2. data/README +70 -0
  3. data/Rakefile +39 -0
  4. data/VERSION +1 -0
  5. data/app/controllers/admin/admin_controller.rb +12 -0
  6. data/app/controllers/admin/documents_controller.rb +133 -0
  7. data/app/controllers/admin/meta_definitions_controller.rb +36 -0
  8. data/app/controllers/documents_controller.rb +187 -0
  9. data/app/controllers/sendmail_controller.rb +87 -0
  10. data/app/helpers/admin/documents_helper.rb +71 -0
  11. data/app/helpers/documents_helper.rb +30 -0
  12. data/app/helpers/sendmail_helper.rb +2 -0
  13. data/app/models/document.rb +292 -0
  14. data/app/models/document_mailer.rb +13 -0
  15. data/app/models/document_sweeper.rb +28 -0
  16. data/app/models/meta_definition.rb +57 -0
  17. data/app/models/sendmail.rb +18 -0
  18. data/app/views/admin/admin/system.html.erb +34 -0
  19. data/app/views/admin/documents/_form.html.erb +60 -0
  20. data/app/views/admin/documents/default.edit.html.erb +10 -0
  21. data/app/views/admin/documents/default.new.html.erb +10 -0
  22. data/app/views/admin/documents/default.show.html.erb +77 -0
  23. data/app/views/admin/documents/index.html.erb +32 -0
  24. data/app/views/admin/documents/shared/_resource_link.html.erb +6 -0
  25. data/app/views/document_mailer/new_document.erb +12 -0
  26. data/app/views/layouts/admin.html.erb +43 -0
  27. data/app/views/layouts/application.html.erb +44 -0
  28. data/app/views/pages/404.html.erb +28 -0
  29. data/app/views/pages/contact.html.erb +42 -0
  30. data/app/views/pages/default.html.erb +12 -0
  31. data/app/views/pages/feed.rss.builder +17 -0
  32. data/app/views/pages/home.html.erb +5 -0
  33. data/app/views/pages/search.html.erb +19 -0
  34. data/app/views/pages/shared/_archived_pages.erb +16 -0
  35. data/app/views/pages/shared/_related_pages.html.erb +13 -0
  36. data/app/views/pages/sitemap.html.erb +9 -0
  37. data/app/views/pages/template.erb +51 -0
  38. data/app/views/pages/thank_you.html.erb +1 -0
  39. data/app/views/sendmail/default.erb +12 -0
  40. data/config/sitemap.example.yml +39 -0
  41. data/db/migrate/20090824150210_create_documents.rb +37 -0
  42. data/db/migrate/20091208124512_create_meta_definition.rb +26 -0
  43. data/init.rb +1 -0
  44. data/install.rb +1 -0
  45. data/lib/qcms.rb +4 -0
  46. data/lib/tasks/cms.rake +237 -0
  47. data/qcms.gemspec +91 -0
  48. data/rails/init.rb +3 -0
  49. data/tasks/qcms_tasks.rake +223 -0
  50. data/test/qwerty_test.rb +8 -0
  51. data/test/test_helper.rb +3 -0
  52. data/uninstall.rb +1 -0
  53. metadata +107 -0
@@ -0,0 +1,13 @@
1
+ class DocumentMailer < ActionMailer::Base
2
+
3
+ def new_document(document)
4
+ subject "[#{Settings.site.name}] New #{document.label}"
5
+ from Settings.mailer.from
6
+ recipients User.all.select { |u| u.has_role? 'admin'}.collect { |u| u.email }.join(', ')
7
+ body :document => document
8
+ content_type "text/html"
9
+ end
10
+
11
+
12
+
13
+ end
@@ -0,0 +1,28 @@
1
+ class DocumentSweeper < ActionController::Caching::Sweeper
2
+ observe Document
3
+
4
+ def after_save(document)
5
+ clear_document_cache(document)
6
+ end
7
+
8
+ def after_destroy(document)
9
+ clear_document_cache(document)
10
+ end
11
+
12
+ # We dont need to expire the cache for the parent as a document always
13
+ # touches its parent after_save, which will cause this method to be run
14
+ # for the parent as well.
15
+
16
+ def clear_document_cache(document)
17
+ expire_fragment :recent_posts
18
+ expire_fragment :menu
19
+
20
+ cache_paths = []
21
+ cache_paths << File.join(RAILS_ROOT, 'public', 'cache', document.path)
22
+
23
+ cache_paths.each do | cache_path |
24
+ Rails.logger.debug 'Deleting CACHE: ' + cache_path
25
+ FileUtils.rm_rf cache_path if File.exists? cache_path
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,57 @@
1
+ class MetaDefinition < ActiveRecord::Base
2
+ has_many :documents, :dependent => :destroy
3
+
4
+ validates_presence_of :label_path, :label
5
+ validates_uniqueness_of :label_path
6
+
7
+ acts_as_list
8
+ acts_as_tree
9
+ path_finder :uid => 'label', :column => 'label_path'
10
+
11
+ default_scope :order => 'position DESC'
12
+
13
+ named_scope :by_label, lambda { |label| { :conditions => ['label = ?', label] } }
14
+
15
+ before_save :nullify_empty_columns
16
+
17
+ serialize :autherisation, Hash
18
+ serialize :field_map, Hash
19
+ serialize :flash_messages, Hash
20
+
21
+
22
+ def autherisation
23
+ super || {}
24
+ end
25
+
26
+ def field_map
27
+ super || {}
28
+ end
29
+
30
+ def flash_messages
31
+ super || {}
32
+ end
33
+
34
+
35
+ def allowed?(user, action)
36
+ tokens = (autherisation[action] || Settings.documents.autherisation.send(action)).split(' ')
37
+ tokens.each do | token |
38
+ return true if token == 'all'
39
+ return true if token == 'author' && self.author == user
40
+ return true if user.has_role? token
41
+ end
42
+ false
43
+ end
44
+
45
+ # Used to find template named after label_path
46
+ # eg. blog.post.html.erb
47
+ def template_filename(include_extension = true)
48
+ label_path.gsub('/', '.') + (include_extension ? '.html.erb' : '')
49
+ end
50
+
51
+ private
52
+
53
+ # Prevent empty strings being saved
54
+ def nullify_empty_columns
55
+ %w(sort_by per_page).each { |column| self.send(column+'=', nil) if self.send(column) == '' }
56
+ end
57
+ end
@@ -0,0 +1,18 @@
1
+ class Sendmail < ActionMailer::Base
2
+
3
+ def form(params, meta, template)
4
+ subject meta[:subject]
5
+ from set_from(params, meta)
6
+ recipients meta[:recipients]
7
+ body :data => params
8
+ content_type "text/html"
9
+ template template
10
+ end
11
+
12
+ private
13
+
14
+ def set_from(params, meta)
15
+ params[:email].nil? ? params[:email] : meta[:from]
16
+ end
17
+
18
+ end
@@ -0,0 +1,34 @@
1
+ <style>
2
+ ul.info li { margin-left: 20px;
3
+ list-style: none;
4
+ padding: 5px;
5
+ background-color: #CFDBA0;
6
+ margin-bottom: 4px;
7
+ }
8
+ </style>
9
+
10
+ <h3>Qwerty</h3>
11
+ <ul class="info">
12
+ <li>Qcore: <%= Qcore::VERSION %></li>
13
+ <li>Qcms: <%= Qcms::VERSION %></li>
14
+ </ul>
15
+
16
+ <h3>Rails</h3>
17
+ <ul class="info">
18
+ <li>Version: <%= Rails.version %></li>
19
+ <li>User: <%= Etc.getpwuid(Process.euid).name %></li>
20
+ <li>Root: <%= RAILS_ROOT %></li>
21
+ <li>Env: <%= RAILS_ENV %></li>
22
+ </ul>
23
+
24
+ <h3>Gem</h3>
25
+ <ul class="info">
26
+ <li>Config: <%= Gem.config_file %></li>
27
+ <li>Default path: <%= Gem.default_path %></li>
28
+ </ul>
29
+
30
+ <h3>Ruby</h3>
31
+ <ul class="info">
32
+ <li>version <%= Gem.ruby_version.to_s %></li>
33
+ <li>path <%= Gem.ruby %></li>
34
+ </ul>
@@ -0,0 +1,60 @@
1
+ <p>Title<BR/>
2
+ <%= f.text_field :title %>
3
+ </p>
4
+
5
+ <p>Permalink<BR/>
6
+ <% if @document.new_record? %>
7
+ <%= f.text_field :permalink, :value => '' %>
8
+ <small>This will be generated automatically if left blank</small>
9
+ <% else %>
10
+ <%= f.text_field :permalink, :readonly => 'true' %>
11
+ <small>Not editable</small>
12
+ <% end %>
13
+ </p>
14
+
15
+ <p>State<BR/>
16
+ <%= f.select :state, [['Published','published'], ['Draft', 'draft']] %>
17
+ </p>
18
+
19
+ <p>Published <BR><%= f.date_select :published_at, :order => [:day, :month, :year] %></p>
20
+
21
+ <p>Body<BR/>
22
+ <%= f.text_area :body %>
23
+ </p>
24
+
25
+ <p>Summary<BR/>
26
+ <%= f.text_field :summary %>
27
+ <small>This will be generated automatically if left blank</small>
28
+ </p>
29
+
30
+ <p>Image<BR/>
31
+ <%= f.file_field :resource %>
32
+ <%= render :partial => 'admin/documents/shared/resource_link' %>
33
+ <% if @document.resource.exists? %>
34
+ <div>Delete image: <%= f.check_box :delete_resource %></div>
35
+ <% end %>
36
+ </p>
37
+
38
+ <p>
39
+ Image Description<br/>
40
+ <%= f.text_field :resource_description %>
41
+ </p>
42
+
43
+ <fieldset>
44
+ <legend>Meta</legend>
45
+ <p>Page Title<BR/>
46
+ <%= f.text_field :meta_title %>
47
+ </p>
48
+
49
+ <p>Description<BR/>
50
+ <%= f.text_field :meta_description %>
51
+ </p>
52
+
53
+ <p>Keywords<BR/>
54
+ <%= f.text_field :meta_keywords %>
55
+ </p>
56
+ </fieldset>
57
+
58
+ <%= f.hidden_field :parent_id %>
59
+ <%= f.hidden_field :label %>
60
+ <%= f.hidden_field :meta_definition_id %>
@@ -0,0 +1,10 @@
1
+ <h4>Edit <%= @document.label.titleize %></h4>
2
+ <%= error_messages_for :document %>
3
+ <% form_for @document.becomes(Document), :url => admin_document_path(@document.id), :html => { :multipart => true } do |f| %>
4
+ <%= render :partial => form_partial, :locals => { :f => f } %>
5
+ <%= f.submit 'Save' %> or <%= link_to 'Cancel', admin_cancel_document_path(@document), :class => 'button' %>
6
+ <% end %>
7
+
8
+ <% if session[:system] %>
9
+ <%= form_partial %>
10
+ <% end %>
@@ -0,0 +1,10 @@
1
+ <h4>New <%= @document.label.titleize %></h4>
2
+ <%= error_messages_for :document %>
3
+ <% form_for @document.becomes(Document), :url => admin_documents_path, :html => { :multipart => true } do |f| %>
4
+ <%= render :partial => form_partial, :locals => { :f => f } %>
5
+ <%= f.submit 'Save' %> or <%= link_to 'Cancel', admin_cancel_document_path(@document), :class => 'button' %>
6
+ <% end %>
7
+
8
+ <% if session[:system] %>
9
+ <%= form_partial %>
10
+ <% end %>
@@ -0,0 +1,77 @@
1
+ <h4><%= @document.title %></h4>
2
+
3
+ <div style="margin-bottom: 20px;"><%= textilize @document.summary %></div>
4
+
5
+ <% @document.meta_definition.children.each do |md| %>
6
+
7
+ <h4 style="margin-top: 20px; border-bottom: 1px solid #ADBCBC;"><%= md.label.titleize.pluralize.capitalize %></h4>
8
+
9
+ <% unless md.documents.empty? %>
10
+ <table>
11
+ <tr>
12
+ <% md.field_map.each do |k,v| %>
13
+ <td><%= k.titleize %></td>
14
+ <% end %>
15
+ <th>Title</th>
16
+ <th>State</th>
17
+ <th>Author</th>
18
+ <% if md.record_hits? %>
19
+ <th>Hits</th>
20
+ <% end %>
21
+ </tr>
22
+ <% documents = @document.children.by_label(md.label).order_by(md.sort_by).paginate(:per_page => 20, :page => params["#{md.label}_page".to_sym]) %>
23
+ <% documents.each do |page| %>
24
+ <tr>
25
+ <% md.field_map.each do |k,v| %>
26
+ <td><%= page.send(v) %></td>
27
+ <% end %>
28
+ <td><%= truncate(page.title, :length => 40) %></td>
29
+ <td>
30
+ <% form_for page.becomes(Document), :url => admin_document_path(page.id) do |f| %>
31
+ <%= f.select :state, [['Published','published'], ['Draft', 'draft'], ['Pending', 'pending']] %>
32
+ <%= f.submit 'Change' %>
33
+ <% end %>
34
+ </td>
35
+ <td><%= page.author.name %></td>
36
+ <% if md.record_hits? %>
37
+ <td><%= page.hits %></td>
38
+ <% end %>
39
+ <td>
40
+ <%= link_to 'Open', admin_document_path(page.id), :class => 'button' %>
41
+ </td>
42
+ <td><%= link_to 'Edit', edit_admin_document_path(page.id), :class => 'button' %></td>
43
+ <% if md.sort_by == 'position ASC' %>
44
+ <td>
45
+ <%= link_to 'Up', up_admin_document_path(page.id), :class => 'button' unless page.first? %>
46
+ <%= link_to 'Down', down_admin_document_path(page.id), :class => 'button' unless page.last? %>
47
+ </td>
48
+ <% end %>
49
+ <td>
50
+ <% unless page.system? %>
51
+ <%= link_to 'Delete', admin_document_path(page.id), :method => 'delete', :confirm => 'Are you sure?', :class => 'button' %>
52
+ <% end %>
53
+ </td>
54
+ </tr>
55
+ <% end %>
56
+ </table>
57
+ <%= will_paginate documents, :param_name => "#{md.label}_page".to_sym %>
58
+ <% else %>
59
+ <p>There are no <%= md.label.titleize.pluralize %> yet!</p>
60
+ <% end %>
61
+ <p><%= link_to 'New ', new_admin_document_path + '?parent=' + @document.id.to_s + '&label=' + md.label, :class => 'button' %></p>
62
+
63
+ <% form_for md, :url => admin_meta_definition_path(md.id) do | f | %>
64
+ <p><label>Sort by</label> <%= f.select :sort_by, sort_by_options, :include_blank => true %></p>
65
+ <p><label>Per page</label> <%= f.select :per_page, per_page_options, :include_blank => true %></p>
66
+ <input type="hidden" name="document_id" value ="<%= @document.id %>" />
67
+ <%= f.submit 'Save' %>
68
+ <% end %>
69
+ <% end %>
70
+
71
+
72
+
73
+ <style>
74
+ form.edit_meta_definition { font-size: 1em; }
75
+ </style>
76
+
77
+
@@ -0,0 +1,32 @@
1
+ <h2>Sections</h2>
2
+
3
+ <table>
4
+ <tr>
5
+ <th>Title</th>
6
+ <th></th>
7
+ <th></th>
8
+ </tr>
9
+ <% @documents.each do |document| %>
10
+ <tr>
11
+ <td>
12
+ <%= document.title %><br />
13
+ <small><%= truncate(document.summary, :length => 30) %></small>
14
+ </td>
15
+ <td>
16
+ <a href="<%= admin_document_path(document.id) %>" class="button">Open</a>
17
+ </td>
18
+ <td><a href="<%= edit_admin_document_path(document.id) %>" class="button">Edit</a></td>
19
+ <td><a href="<%= new_admin_document_path + '?parent_id=' + document.id.to_s %>" class="button">Add</a></td>
20
+ <td>
21
+ <%= link_to 'Up', up_admin_document_path(document.id), :class => 'button' unless document.first? %>
22
+ <%= link_to 'Down', down_admin_document_path(document.id), :class => 'button' unless document.last? %>
23
+ </td>
24
+ <td><%= link_to 'Delete', admin_document_path(document.id), :method => 'delete', :class => 'button' %></td>
25
+ <td><a href="<%= document_path(document) %>" class="button">Live</a></td>
26
+ </tr>
27
+ <% end %>
28
+ </table>
29
+
30
+ <p><%= link_to 'New Page', new_admin_document_path + '?label_path=page', :class => 'button' %>
31
+
32
+
@@ -0,0 +1,6 @@
1
+ <% resource ||= @document.resource if @document -%>
2
+ <% if resource.exists? %>
3
+ <p>Already uploaded: <a href="<%= resource.url %>"><%= resource.original_filename %></a></p>
4
+ <% else %>
5
+ <p>Nothing uploaded yet!</p>
6
+ <% end %>
@@ -0,0 +1,12 @@
1
+ <p>You have a new <%= @document.label %></p>
2
+
3
+ <% unless @document.published? %>
4
+ <p>This <%= @document.label %> is currently <%= @document.state.capitalize %></p>
5
+ <% end %>
6
+
7
+ <p><%= link_to 'Edit', 'http://' + Settings.domain + admin_document_path(@document.parent_id) %></p>
8
+
9
+
10
+
11
+
12
+
@@ -0,0 +1,43 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
4
+ <head>
5
+ <title><%= @page_title || 'untitled' %></title>
6
+ <meta http-equiv="content-type" content="text/xhtml; charset=utf-8" />
7
+ <link rel="stylesheet" href="/stylesheets/admin/styles.css" type="text/css" media="screen" />
8
+ <%= javascript_include_tag 'jquery-1.3.1.min.js' %>
9
+ <%= javascript_include_tag 'application' %>
10
+ <%= meta_tags -%>
11
+ <%= yield :head %>
12
+ </head>
13
+ <body>
14
+
15
+ <% if flash[:notice] %>
16
+ <div id="flash-notice"><%= flash[:notice] %> <a href="#">Close</a></div>
17
+ <% end %>
18
+
19
+ <div id="header">QWERTY+ Control Panel</div>
20
+
21
+ <ul id="top_menu">
22
+ <li><a href="<%= admin_dashboard_path %>">Dashboard</a></li>
23
+ <li><a href="<%= admin_users_path %>">Users</a></li>
24
+ <li><a href="<%= root_path %>">Site Homepage</a></li>
25
+ </ul>
26
+
27
+ <% if @document %>
28
+ <%= admin_bread_crumb(@document) %>
29
+ <% end %>
30
+
31
+ <div id="container">
32
+
33
+ <div id="content">
34
+ <%= yield %>
35
+ </div>
36
+
37
+ <div id="sidebar">
38
+ <%= yield :sidebar %>
39
+ </div>
40
+
41
+ </div> <!-- container -->
42
+ </body>
43
+ </html>
@@ -0,0 +1,44 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
4
+ <head>
5
+ <title><%= page_title %></title>
6
+ <meta http-equiv="content-type" content="text/xhtml; charset=utf-8" />
7
+ <link rel="stylesheet" href="/stylesheets/styles.css" type="text/css" media="screen" />
8
+ <%= javascript_include_tag 'jquery-1.3.1.min.js' %>
9
+ <%= javascript_include_tag 'application' %>
10
+ <%= meta_tags -%>
11
+ <%= yield :head %>
12
+ </head>
13
+ <body>
14
+ <div id="user_nav">
15
+ <% if current_user %>
16
+ <a href="<%= logout_path %>">Logout</a>
17
+ <a href="/admin">Admin</a>
18
+ <% else %>
19
+ <a href="<%= login_path %>">Login</a>
20
+ <% end %>
21
+ </div>
22
+
23
+ <% if flash[:notice] %>
24
+ <div id="flash-notice"><%= flash[:notice] %> <a href="#">Close</a></div>
25
+ <% end %>
26
+
27
+ <div id="header"></div>
28
+ <ul id="nav">
29
+ <% Document.public.roots.order_by('position').each do | doc | %>
30
+ <li style=""><a href="<%= document_path(doc) %>"><%= doc.title %></a></li>
31
+ <% end %>
32
+ </ul>
33
+ <div style="clear:both;"></div>
34
+ <div id="container">
35
+ <div id="content">
36
+ <%= yield %>
37
+ </div>
38
+
39
+ <div id="sidebar">
40
+ <%= yield :sidebar %>
41
+ </div>
42
+ </div> <!-- container -->
43
+ </body>
44
+ </html>