caboose-cms 0.0.2

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 (100) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +4 -0
  3. data/Rakefile +40 -0
  4. data/app/assets/javascripts/caboose/application.js +36 -0
  5. data/app/assets/javascripts/caboose/login.js +21 -0
  6. data/app/assets/javascripts/caboose/permissions.js +0 -0
  7. data/app/assets/javascripts/caboose/roles.js +35 -0
  8. data/app/assets/javascripts/caboose/users.js +38 -0
  9. data/app/assets/stylesheets/caboose/application.css +15 -0
  10. data/app/assets/stylesheets/caboose/caboose.css +28 -0
  11. data/app/controllers/caboose/admin_controller.rb +19 -0
  12. data/app/controllers/caboose/application_controller.rb +109 -0
  13. data/app/controllers/caboose/login_controller.rb +40 -0
  14. data/app/controllers/caboose/logout_controller.rb +9 -0
  15. data/app/controllers/caboose/pages_controller.rb +304 -0
  16. data/app/controllers/caboose/permissions_controller.rb +83 -0
  17. data/app/controllers/caboose/roles_controller.rb +109 -0
  18. data/app/controllers/caboose/users_controller.rb +117 -0
  19. data/app/helpers/caboose/application_helper.rb +4 -0
  20. data/app/helpers/caboose/permissions_helper.rb +4 -0
  21. data/app/models/caboose/approval_request.rb +13 -0
  22. data/app/models/caboose/asset.rb +23 -0
  23. data/app/models/caboose/caboose_plugin.rb +15 -0
  24. data/app/models/caboose/menu_block.rb +6 -0
  25. data/app/models/caboose/page.rb +329 -0
  26. data/app/models/caboose/page_bar_generator.rb +157 -0
  27. data/app/models/caboose/page_permission.rb +7 -0
  28. data/app/models/caboose/permission.rb +14 -0
  29. data/app/models/caboose/role.rb +50 -0
  30. data/app/models/caboose/std_class.rb +8 -0
  31. data/app/models/caboose/user.rb +47 -0
  32. data/app/views/caboose/admin/index.html.erb +5 -0
  33. data/app/views/caboose/application/show.html.erb +2 -0
  34. data/app/views/caboose/extras/error.html.erb +2 -0
  35. data/app/views/caboose/extras/error404.html.erb +0 -0
  36. data/app/views/caboose/login/index.html.erb +26 -0
  37. data/app/views/caboose/pages/edit.html.erb +45 -0
  38. data/app/views/caboose/pages/index.html.erb +34 -0
  39. data/app/views/caboose/pages/new.html.erb +23 -0
  40. data/app/views/caboose/pages/show.html.erb +2 -0
  41. data/app/views/caboose/pages/update_pic.html.erb +16 -0
  42. data/app/views/caboose/pages/update_resume.html.erb +14 -0
  43. data/app/views/caboose/permissions/edit.html.erb +6 -0
  44. data/app/views/caboose/permissions/index.html.erb +25 -0
  45. data/app/views/caboose/permissions/new.html.erb +5 -0
  46. data/app/views/caboose/permissions/show.html.erb +15 -0
  47. data/app/views/caboose/roles/edit.html.erb +36 -0
  48. data/app/views/caboose/roles/index.html.erb +17 -0
  49. data/app/views/caboose/roles/new.html.erb +16 -0
  50. data/app/views/caboose/roles/show.html.erb +20 -0
  51. data/app/views/caboose/users/edit.html.erb +45 -0
  52. data/app/views/caboose/users/index.html.erb +34 -0
  53. data/app/views/caboose/users/new.html.erb +22 -0
  54. data/app/views/caboose/users/update_pic.html.erb +16 -0
  55. data/app/views/caboose/users/update_resume.html.erb +14 -0
  56. data/app/views/layouts/caboose/application.html.erb +24 -0
  57. data/app/views/layouts/caboose/caboose.html.erb +24 -0
  58. data/app/views/layouts/caboose/error404.html.erb +2 -0
  59. data/app/views/layouts/caboose/station.html.erb +28 -0
  60. data/config/routes.rb +48 -0
  61. data/db/migrate/20130421000000_drop_all_caboose.rb +16 -0
  62. data/db/migrate/20130422000000_create_caboose.rb +147 -0
  63. data/lib/caboose.rb +26 -0
  64. data/lib/caboose/engine.rb +24 -0
  65. data/lib/caboose/version.rb +3 -0
  66. data/lib/tasks/caboose_tasks.rake +4 -0
  67. data/test/caboose_test.rb +7 -0
  68. data/test/dummy/README.rdoc +261 -0
  69. data/test/dummy/Rakefile +7 -0
  70. data/test/dummy/app/assets/javascripts/application.js +15 -0
  71. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  72. data/test/dummy/app/controllers/application_controller.rb +3 -0
  73. data/test/dummy/app/helpers/application_helper.rb +2 -0
  74. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  75. data/test/dummy/config.ru +4 -0
  76. data/test/dummy/config/application.rb +59 -0
  77. data/test/dummy/config/boot.rb +10 -0
  78. data/test/dummy/config/database.yml +25 -0
  79. data/test/dummy/config/environment.rb +5 -0
  80. data/test/dummy/config/environments/development.rb +37 -0
  81. data/test/dummy/config/environments/production.rb +67 -0
  82. data/test/dummy/config/environments/test.rb +37 -0
  83. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  84. data/test/dummy/config/initializers/inflections.rb +15 -0
  85. data/test/dummy/config/initializers/mime_types.rb +5 -0
  86. data/test/dummy/config/initializers/secret_token.rb +7 -0
  87. data/test/dummy/config/initializers/session_store.rb +8 -0
  88. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  89. data/test/dummy/config/locales/en.yml +5 -0
  90. data/test/dummy/config/routes.rb +4 -0
  91. data/test/dummy/db/test.sqlite3 +0 -0
  92. data/test/dummy/log/test.log +25 -0
  93. data/test/dummy/public/404.html +26 -0
  94. data/test/dummy/public/422.html +26 -0
  95. data/test/dummy/public/500.html +25 -0
  96. data/test/dummy/public/favicon.ico +0 -0
  97. data/test/dummy/script/rails +6 -0
  98. data/test/integration/navigation_test.rb +10 -0
  99. data/test/test_helper.rb +15 -0
  100. metadata +241 -0
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2013 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,4 @@
1
+ Caboose
2
+ =======
3
+
4
+ Ruby on rails content management system
data/Rakefile ADDED
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'Caboose'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+ APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
24
+ load 'rails/tasks/engine.rake'
25
+
26
+
27
+
28
+ Bundler::GemHelper.install_tasks
29
+
30
+ require 'rake/testtask'
31
+
32
+ Rake::TestTask.new(:test) do |t|
33
+ t.libs << 'lib'
34
+ t.libs << 'test'
35
+ t.pattern = 'test/**/*_test.rb'
36
+ t.verbose = false
37
+ end
38
+
39
+
40
+ task :default => :test
@@ -0,0 +1,36 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // the compiled file.
9
+ //
10
+ // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
11
+ // GO AFTER THE REQUIRES BELOW.
12
+ //
13
+ //= require caboose_before
14
+ //= require jquery
15
+ //= require jquery_ujs
16
+ //= require jquery-ui
17
+ //= require class
18
+ //= require model/model
19
+ //= require model/attribute
20
+ //= require model/form
21
+ //= require model/form/embedded
22
+ //= require model/attribute/checkbox-multiple
23
+ //= require model/attribute/checkbox
24
+ //= require model/attribute/date-time
25
+ //= require model/attribute/file
26
+ //= require model/attribute/hidden
27
+ //= require model/attribute/image
28
+ //= require model/attribute/password
29
+ //= require model/attribute/radio
30
+ //= require model/attribute/rich-text
31
+ //= require model/attribute/select
32
+ //= require model/attribute/texarea
33
+ //= require model/attribute/textjs
34
+ //= require model/attribute/time
35
+ //= require model/attribute/video
36
+ //= require caboose_after
@@ -0,0 +1,21 @@
1
+
2
+ function login()
3
+ {
4
+ $('#message').html("<p class='loading'>Logging in...</p>");
5
+
6
+ $.ajax({
7
+ url: '/login',
8
+ type: 'post',
9
+ data: $('#login_form').serialize(),
10
+ success: function(resp) {
11
+ if (resp.error)
12
+ $('#message').html("<p class='note error'>" + resp.error + "</p>");
13
+ else if (resp.redirect != false)
14
+ window.location = resp.redirect;
15
+ },
16
+ error: function() {
17
+ $('#message').html("<p class='note error'>Error</p>");
18
+ }
19
+ });
20
+ }
21
+
File without changes
@@ -0,0 +1,35 @@
1
+
2
+ Caboose.Role = function(){};
3
+
4
+ Caboose.Role.add = function()
5
+ {
6
+ $('#message').html("<p class='loading'>Adding role...</p>");
7
+
8
+ $.ajax({
9
+ url: '/roles',
10
+ type: 'post',
11
+ data: $('#new_role_form').serialize(),
12
+ success: Caboose.ajax_success,
13
+ error: Caboose.ajax_error
14
+ });
15
+ };
16
+
17
+ Caboose.Role.delete = function(role_id, confirm)
18
+ {
19
+ if (!confirm)
20
+ {
21
+ Caboose.confirm({
22
+ message: "Are you sure you want to delete the role? This can't be undone.",
23
+ yes: function() { Caboose.Role.delete(role_id, true) }
24
+ });
25
+ return;
26
+ }
27
+ $('#message').html("<p class='loading'>Deleting role...</p>");
28
+
29
+ $.ajax({
30
+ url: '/roles/' + role_id,
31
+ type: 'delete',
32
+ success: Caboose.ajax_success,
33
+ error: Caboose.ajax_error
34
+ });
35
+ };
@@ -0,0 +1,38 @@
1
+
2
+ /*
3
+ Nine
4
+ Caboose.User = function(){};
5
+
6
+ Caboose.User.add = function()
7
+ {
8
+ $('#message').html("<p class='loading'>Adding user...</p>");
9
+
10
+ $.ajax({
11
+ url: '/users',
12
+ type: 'post',
13
+ data: $('#new_user_form').serialize(),
14
+ success: Caboose.ajax_success,
15
+ error: Caboose.ajax_error
16
+ });
17
+ };
18
+
19
+ Caboose.User.delete = function(user_id, confirm)
20
+ {
21
+ if (!confirm)
22
+ {
23
+ Caboose.confirm({
24
+ message: "Are you sure you want to delete the user? This can't be undone.",
25
+ yes: function() { Caboose.User.delete(user_id, true) }
26
+ });
27
+ return;
28
+ }
29
+ $('#message').html("<p class='loading'>Deleting user...</p>");
30
+
31
+ $.ajax({
32
+ url: '/users/' + user_id,
33
+ type: 'delete',
34
+ success: Caboose.ajax_success,
35
+ error: Caboose.ajax_error
36
+ });
37
+ };
38
+ */
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the top of the
9
+ * compiled file, but it's generally better to create a new file per style scope.
10
+ *
11
+ *= require caboose_before
12
+ *= require model
13
+ *= require caboose/caboose
14
+ *= require caboose_after
15
+ */
@@ -0,0 +1,28 @@
1
+
2
+ body {
3
+ font-family: Helvetica, Tahoma, Arial;
4
+ }
5
+
6
+ #wrapper {
7
+ width: 960px;
8
+ }
9
+
10
+ .page_links {
11
+
12
+ }
13
+
14
+ .page_links a {
15
+ display: inline-block;
16
+ padding: 4px 8px;
17
+ border: #efefef 1px solid;
18
+ }
19
+
20
+ .page_links .middle_links a {
21
+
22
+ }
23
+
24
+ .page_links span.current_page {
25
+ display: inline-block;
26
+ padding: 4px 8px;
27
+ font-weight: bold;
28
+ }
@@ -0,0 +1,19 @@
1
+
2
+ module Caboose
3
+ class AdminController < ApplicationController
4
+
5
+ # GET /admin
6
+ def index
7
+ return if !user_is_allowed('admin', 'view')
8
+
9
+ @mods = [
10
+ { 'href' => '/admin/users' , 'text' => 'Users' },
11
+ { 'href' => '/admin/roles' , 'text' => 'Roles' },
12
+ { 'href' => '/admin/permissions' , 'text' => 'Permissions' }
13
+ ]
14
+ @mods = Caboose.plugin_hook('admin_nav', @mods)
15
+
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,109 @@
1
+ module Caboose
2
+ class ApplicationController < ActionController::Base
3
+
4
+ protect_from_forgery
5
+ before_filter :before_before_action
6
+
7
+ def before_before_action
8
+
9
+ # Try to find the page
10
+ @page = Page.page_with_uri(request.fullpath)
11
+
12
+ session['use_redirect_urls'] = true if session['use_redirect_urls'].nil?
13
+
14
+ @crumb_trail = Caboose::Page.crumb_trail(@page)
15
+ @subnav = {}
16
+ @actions = {}
17
+ @tasks = {}
18
+ @page_tasks = {}
19
+ @is_real_page = false
20
+
21
+ # Sets an instance variable of the logged in user
22
+ @logged_in_user = logged_in_user
23
+
24
+ before_action
25
+ end
26
+
27
+ # To be overridden by the child controllers
28
+ def before_action
29
+ end
30
+
31
+ # Logs in a user
32
+ def login_user(user)
33
+ session["app_user"] = user
34
+ end
35
+
36
+ # Returns whether or not a user is logged in
37
+ def logged_in?
38
+ #return true if !session["app_user"].nil? && session["app_user"].id != -1
39
+ validate_token
40
+ return true if !session["app_user"].nil? && session["app_user"].id != -1
41
+ return false
42
+ end
43
+
44
+ # Checks to see if a token is given. If so, it tries to validate the token
45
+ # and log the user in.
46
+ def validate_token
47
+ token = params[:token]
48
+ return false if token.nil?
49
+
50
+ user = User.validate_token(token)
51
+ return false if user.nil?
52
+
53
+ login_user(user)
54
+ return true
55
+ end
56
+
57
+ # Returns the currently logged in user
58
+ def logged_in_user
59
+ if (!logged_in?)
60
+ return User.find(User::LOGGED_OUT_USER_ID)
61
+ end
62
+ #return nil if !logged_in?
63
+ return session["app_user"]
64
+ end
65
+
66
+ # Checks to see if a user has permission to perform the given action
67
+ # on the given resource.
68
+ # Redirects to login if not logged in.
69
+ # Redirects to error page with message if not allowed.
70
+ def user_is_allowed(resource, action)
71
+ if (!logged_in?)
72
+ redirect_to "/login?return_url=" + URI.encode(request.fullpath)
73
+ return
74
+ end
75
+
76
+ @user = logged_in_user
77
+ if (!@user.is_allowed(resource, action))
78
+ @error = "You don't have permission to " + action + " " + resource
79
+ render :template => "caboose/extras/error"
80
+ return false
81
+ end
82
+
83
+ return true
84
+ end
85
+
86
+ # Removes a given parameter from a URL querystring
87
+ def reject_param(url, param)
88
+ arr = url.split('?')
89
+ return url if (arr.count == 1)
90
+ qs = arr[1].split('&').reject { |pair| pair.split(/[=;]/).first == param }
91
+ url2 = arr[0]
92
+ url2 += "?" + qs.join('&') if qs.count > 0
93
+ return url2
94
+ end
95
+
96
+ #def auth_or_error(message)
97
+ # if (!logged_in?)
98
+ # redirect_to "/login?return_url=#{request.request_uri}" and return false
99
+ # end
100
+ # redirect_to "/error?message=#{message}"
101
+ #end
102
+
103
+ def var(key)
104
+ v = Var.where(:key => key).first
105
+ return "" if v.nil?
106
+ return v.val
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,40 @@
1
+ module Caboose
2
+ class LoginController < Caboose::ApplicationController
3
+
4
+ # GET /login
5
+ def index
6
+ @return_url = params[:return_url].nil? ? "/" : params[:return_url];
7
+ redirect_to @return_url if logged_in?
8
+ end
9
+
10
+ # POST /login
11
+ def login
12
+
13
+ @resp = StdClass.new('error' => '', 'redirect' => '')
14
+ @return_url = params[:return_url].nil? ? "/" : params[:return_url]
15
+
16
+ if (logged_in?)
17
+ @resp.error = "Already logged in"
18
+ else
19
+ @username = params[:username]
20
+ @password = params[:password]
21
+
22
+ if (@username.nil? || @password.nil? || @password.strip.length == 0)
23
+ @resp.error = "Invalid credentials"
24
+ else
25
+
26
+ @password = Digest::SHA1.hexdigest(Caboose::salt + @password)
27
+ user = User.where(:username => @username, :password => @password).first
28
+
29
+ if (user.nil?)
30
+ @resp.error = "Invalid credentials"
31
+ else
32
+ login_user(user)
33
+ @resp.redirect = @return_url
34
+ end
35
+ end
36
+ end
37
+ render json: @resp
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,9 @@
1
+ module Caboose
2
+ class LogoutController < ApplicationController
3
+ # GET /logout
4
+ def index
5
+ reset_session
6
+ redirect_to "/"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,304 @@
1
+
2
+ module Caboose
3
+ class PagesController < ApplicationController
4
+
5
+ def before_action
6
+ @page = Page.page_with_uri('/admin')
7
+ end
8
+
9
+ # GET /pages
10
+ def index
11
+ end
12
+
13
+ # GET /pages/:id
14
+ def show
15
+
16
+ # Find the page with an exact URI match
17
+ page = Page.page_with_uri(request.fullpath, false)
18
+ Caboose.log(page)
19
+
20
+ if (!page)
21
+ asset
22
+ return
23
+ end
24
+
25
+ user = logged_in_user
26
+ if (!user.is_allowed(page, 'view'))
27
+ if (user.id == User.LOGGED_OUT_USER_ID)
28
+ redirect_to "/login?return_url=" + URI.encode(request.fullpath)
29
+ return
30
+ else
31
+ page.title = 'Access Denied'
32
+ page.content = "<p class='note error'>You do not have access to view this page.</p>"
33
+ end
34
+ end
35
+
36
+ if (session['use_redirect_urls'] && !page.redirect_url.nil? && page.redirect_url.strip.length > 0)
37
+ redirect_to page.redirect_url
38
+ return
39
+ end
40
+
41
+ page.content = Caboose.plugin_hook('page_content', page.content)
42
+ @page = page
43
+ @user = user
44
+ is_admin = @user.is_allowed('all', 'all')
45
+
46
+ @crumb_trail = Caboose::Page.crumb_trail(@page)
47
+ @subnav = Caboose::Page.subnav(@page, session['use_redirect_urls'], @user)
48
+ @actions = Caboose::Page.permissible_actions(@user.id, @page.id)
49
+ @tasks = {}
50
+ @page_tasks = {}
51
+
52
+ if (@actions.include?('edit') || is_admin)
53
+ @page_tasks["/pages/#{@page.id}/sitemap"] = 'Site Map This Page'
54
+ @page_tasks["/pages/#{@page.id}/edit"] = 'Edit Page Content'
55
+ @page_tasks["/pages/#{@page.id}/edit-settings"] = 'Edit Page Settings'
56
+ end
57
+ if (@user.is_allowed('pages', 'add') || is_admin)
58
+ @page_tasks["/pages/new?parent_id=#{@page.id}"] = 'New Page'
59
+ end
60
+
61
+ #@subnav.links = @tasks.collect {|href, task| {'href' => href, 'text' => task, 'is_current' => uri == href}}
62
+
63
+ end
64
+
65
+ def asset
66
+
67
+ uri = uri.to_s.gsub(/^(.*?)\?.*?$/, '\1')
68
+ uri.chop! if uri.end_with?('/')
69
+ uri[0] = '' if uri.starts_with?('/')
70
+
71
+ page = Page.page_with_uri(File.dirname(uri), false)
72
+ if (page.nil? || !page)
73
+ render :file => "caboose/extras/error404", :layout => "caboose/error404"
74
+ return
75
+ end
76
+
77
+ asset = Asset.where(:page_id => page.id, :filename => File.basename(uri)).first
78
+ if (asset.nil?)
79
+ render :file => "caboose/extras/error404", :layout => "caboose/error404"
80
+ return
81
+ end
82
+
83
+ user = logged_in_user
84
+ if (!Page.is_allowed(user, asset.page_id, 'view'))
85
+ render "caboose/pages/asset_no_permission"
86
+ return
87
+ end
88
+
89
+ Caboose.log(Caboose::assets_path, 'Caboose::assets_path')
90
+ path = Caboose::assets_path.join("#{asset.id}.#{asset.extension}")
91
+ Caboose.log("Sending asset #{path}")
92
+ #send_file(path)
93
+ #send_file(path, :filename => "your_document.pdf", :type => "application/pdf")
94
+
95
+ #
96
+ #$path = ASSETS_PATH ."/". $asset->id .".". $asset->extension
97
+ #
98
+ #$finfo = finfo_open(FILEINFO_MIME_TYPE) // return mime type ala mimetype extension
99
+ #$mime = finfo_file($finfo, $path)
100
+ #finfo_close($finfo)
101
+ #
102
+ #header("X-Sendfile: $path")
103
+ #header("Content-Type: $mime")
104
+ #header("Content-Disposition: inline filename=\"$asset->filename\"")
105
+
106
+ end
107
+
108
+ # GET /pages/new
109
+ def new
110
+ return if !user_is_allowed('pages', 'add')
111
+ @pages = Page.new
112
+ @parent_id = params[:parent_id].nil? ? params[:parent_id] : -1
113
+ render :layout => 'caboose/caboose'
114
+ end
115
+
116
+ # GET /pages/1/edit
117
+ def edit
118
+ return if !user_is_allowed('pages', 'edit')
119
+ @page = Page.find(params[:id])
120
+ render :layout => 'caboose/caboose'
121
+ end
122
+
123
+ # POST /pages
124
+ def create
125
+ return if !user_is_allowed('pages', 'add')
126
+
127
+ resp = Caboose::StdClass.new({
128
+ 'error' => nil,
129
+ 'redirect' => nil
130
+ })
131
+
132
+ parent_id = params[:parent_id]
133
+ title = params[:title]
134
+
135
+ if (title.strip.length == 0)
136
+ resp.error = "A page title is required."
137
+ elsif (!logged_in_user.is_allowed('all', 'all') &&
138
+ !Page.page_ids_with_permission(logged_in_user, 'edit' ).include?(parent_id) &&
139
+ !Page.page_ids_with_permission(logged_in_user, 'approve').include?(parent_id))
140
+ resp.error = "You don't have permission to add a page there."
141
+ end
142
+ if (!resp.error.nil?)
143
+ render json: resp
144
+ return
145
+ end
146
+
147
+ parent = Caboose::Page.find(parent_id)
148
+
149
+ page = Caboose::Page.new
150
+ page.title = title
151
+ page.parent_id = parent_id
152
+ page.hide = true
153
+ page.content_format = Caboose::Page::CONTENT_FORMAT_HTML
154
+
155
+ i = 0
156
+ begin
157
+ page.slug = Page.slug(page.title + (i > 0 ? " #{i}" : ""))
158
+ page.uri = parent.parent_id == -1 ? page.slug : "#{parent.uri}/#{page.slug}"
159
+ i = i+1
160
+ end while (Page.where(:uri => page.uri).count > 0 && i < 10)
161
+
162
+ page.save
163
+
164
+ # Set the new page's permissions
165
+ viewers = Caboose::PagePermission.where({ :page_id => parent.id, :action => 'view' }).pluck(:role_id)
166
+ editors = Caboose::PagePermission.where({ :page_id => parent.id, :action => 'edit' }).pluck(:role_id)
167
+ Caboose::Page.update_authorized_for_action(page.id, 'view', viewers)
168
+ Caboose::Page.update_authorized_for_action(page.id, 'edit', editors)
169
+
170
+ # Send back the response
171
+ resp.redirect = "/pages/#{page.id}/edit"
172
+ render json: resp
173
+ end
174
+
175
+ # PUT /pages/1
176
+ def update
177
+ return if !user_is_allowed('pages', 'edit')
178
+
179
+ resp = StdClass.new({'attributes' => {}})
180
+ page = Page.find(params[:id])
181
+
182
+ save = true
183
+ user = logged_in_user
184
+ params.each do |name,value|
185
+ case name
186
+ when 'parent_id'
187
+ if (page.id == value)
188
+ resp.error = "The page's parent cannot be itself."
189
+ elsif (Page.is_child(page.id, value))
190
+ resp.error = "You can't set the current page's parent to be one of its child pages."
191
+ elsif (value != page.parent_id)
192
+ p = Page.find(value)
193
+ if (!user.is_allowed(p, 'edit'))
194
+ resp.error = "You don't have access to put the current page there."
195
+ end
196
+ end
197
+ if (resp.error.length > 0)
198
+ save = false
199
+ else
200
+ parent = Page.find(value)
201
+ Page.update_parent(page.id, value)
202
+ resp.attributes['parent_id'] = { 'text' => parent.title }
203
+ end
204
+
205
+ when 'title', 'menu_title', 'alias', 'redirect_url', 'hide',
206
+ 'content_format', 'custom_css', 'custom_js', 'layout',
207
+ 'seo_title', 'meta_description', 'fb_description', 'gp_description', 'canonical_url'
208
+
209
+ page[name.to_sym] = value
210
+
211
+ when 'meta_robots'
212
+ if (value.include?('index') && value.include?('noindex'))
213
+ resp.error = "You can't have both index and noindex"
214
+ save = false
215
+ elsif (value.include?('follow') && value.include?('nofollow'))
216
+ resp.error = "You can't have both follow and nofollow"
217
+ save = false
218
+ else
219
+ page.meta_robots = value.join(', ')
220
+ resp.attributes['meta_robots'] = { 'text' => page.meta_robots }
221
+ end
222
+
223
+ when 'content'
224
+ page.content = value.strip.gsub(/<meta.*?>/, '').gsub(/<link.*?>/, '').gsub(/\<\!--[\S\s]*?--\>/, '')
225
+
226
+ when 'slug'
227
+ page.slug = Page.slug(value.strip.length > 0 ? value : page.title)
228
+ resp.attributes['slug'] = { 'value' => page.slug }
229
+
230
+ when 'custom_sort_children'
231
+ if (value == 0)
232
+ page.children.each do |p|
233
+ p.sort_order = 1
234
+ p.save
235
+ end
236
+ end
237
+ page.custom_sort_children = value
238
+
239
+ when 'viewers'
240
+ Page.update_authorized_for_action(page.id, 'view', value)
241
+ when 'editors'
242
+ Page.update_authorized_for_action(page.id, 'edit', value)
243
+ when 'approvers'
244
+ Page.update_authorized_for_action(page.id, 'approve', value)
245
+ end
246
+ end
247
+
248
+ resp.success = save && page.save
249
+ render json: resp
250
+ end
251
+
252
+ # DELETE /pages/1
253
+ def destroy
254
+ return if !user_is_allowed('pages', 'delete')
255
+ user = Page.find(params[:id])
256
+ user.destroy
257
+
258
+ resp = StdClass.new({
259
+ 'redirect' => '/pages'
260
+ })
261
+ render json: resp
262
+ end
263
+
264
+ def sitemap_options
265
+ parent_id = params[:parent_id]
266
+ top_page = Page.index_page
267
+ p = !parent_id.nil? ? Page.find(parent_id) : top_page
268
+ options = []
269
+ sitemap_helper(top_page, options)
270
+
271
+ render json: options
272
+ end
273
+
274
+ def sitemap_helper(page, options, prefix = '')
275
+ options << { 'value' => page.id, 'text' => prefix + page.title }
276
+ page.children.each do |kid|
277
+ sitemap_helper(kid, options, prefix + ' - ')
278
+ end
279
+ end
280
+
281
+ def robots_options
282
+ options = [
283
+ { 'value' => 'index' , 'text' => 'index' },
284
+ { 'value' => 'noindex' , 'text' => 'noindex' },
285
+ { 'value' => 'follow' , 'text' => 'follow' },
286
+ { 'value' => 'nofollow' , 'text' => 'nofollow' },
287
+ { 'value' => 'nosnippet' , 'text' => 'nosnippet' },
288
+ { 'value' => 'noodp' , 'text' => 'noodp' },
289
+ { 'value' => 'noarchive' , 'text' => 'noarchive' }
290
+ ]
291
+ render json: options
292
+ end
293
+
294
+ def content_format_options
295
+ options = [
296
+ { 'value' => 'html', 'text' => 'html' },
297
+ { 'value' => 'text', 'text' => 'text' },
298
+ { 'value' => 'ruby', 'text' => 'ruby' }
299
+ ]
300
+ render json: options
301
+ end
302
+
303
+ end
304
+ end