outpost-cms 0.0.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.
- data/MIT-LICENSE +20 -0
- data/README.md +295 -0
- data/Rakefile +26 -0
- data/app/assets/images/glyphicons-halflings-red.png +0 -0
- data/app/assets/javascripts/outpost/application.js +1 -0
- data/app/assets/javascripts/outpost/auto_slug_field.js.coffee +53 -0
- data/app/assets/javascripts/outpost/base.js.coffee +1 -0
- data/app/assets/javascripts/outpost/date_time_input.js.coffee +108 -0
- data/app/assets/javascripts/outpost/field_counter.js.coffee +93 -0
- data/app/assets/javascripts/outpost/field_manager.js.coffee +37 -0
- data/app/assets/javascripts/outpost/global_plugins.js.coffee +87 -0
- data/app/assets/javascripts/outpost/index_manager.js.coffee +88 -0
- data/app/assets/javascripts/outpost/notification.js.coffee +46 -0
- data/app/assets/javascripts/outpost/preview.js.coffee +60 -0
- data/app/assets/javascripts/outpost/templates/date_field.jst.eco +3 -0
- data/app/assets/javascripts/outpost/templates/loading.jst.eco +11 -0
- data/app/assets/javascripts/outpost/templates/slug_generate_button.jst.eco +1 -0
- data/app/assets/javascripts/outpost/templates/time_field.jst.eco +3 -0
- data/app/assets/javascripts/outpost/templates.js +1 -0
- data/app/assets/javascripts/outpost.js +32 -0
- data/app/assets/stylesheets/outpost/_base.css.scss +127 -0
- data/app/assets/stylesheets/outpost/_edit.css.scss +13 -0
- data/app/assets/stylesheets/outpost/_forms.css.scss +116 -0
- data/app/assets/stylesheets/outpost/_index.css.scss +68 -0
- data/app/assets/stylesheets/outpost/_utility.css.scss +16 -0
- data/app/assets/stylesheets/outpost/application.css.scss +1 -0
- data/app/assets/stylesheets/outpost/bootstrap/bootstrap.css.scss +49 -0
- data/app/assets/stylesheets/outpost/bootstrap/datepicker.css.scss +301 -0
- data/app/assets/stylesheets/outpost.css.scss +14 -0
- data/app/controllers/outpost/application_controller.rb +40 -0
- data/app/controllers/outpost/base_controller.rb +3 -0
- data/app/controllers/outpost/errors_controller.rb +9 -0
- data/app/controllers/outpost/home_controller.rb +2 -0
- data/app/controllers/outpost/resource_controller.rb +12 -0
- data/app/controllers/outpost/sessions_controller.rb +36 -0
- data/app/helpers/authorization_helper.rb +44 -0
- data/app/helpers/list_helper.rb +243 -0
- data/app/helpers/outpost_helper.rb +49 -0
- data/app/helpers/render_helper.rb +41 -0
- data/app/helpers/utility_helper.rb +136 -0
- data/app/inputs/date_time_input.rb +12 -0
- data/app/models/permission.rb +18 -0
- data/app/models/user_permission.rb +4 -0
- data/app/views/kaminari/bootstrap/_first_page.html.erb +3 -0
- data/app/views/kaminari/bootstrap/_gap.html.erb +3 -0
- data/app/views/kaminari/bootstrap/_last_page.html.erb +3 -0
- data/app/views/kaminari/bootstrap/_next_page.html.erb +3 -0
- data/app/views/kaminari/bootstrap/_page.html.erb +3 -0
- data/app/views/kaminari/bootstrap/_paginator.html.erb +17 -0
- data/app/views/kaminari/bootstrap/_prev_page.html.erb +3 -0
- data/app/views/layouts/outpost/application.html.erb +101 -0
- data/app/views/layouts/outpost/minimal.html.erb +26 -0
- data/app/views/outpost/errors/error_404.html.erb +1 -0
- data/app/views/outpost/errors/error_500.html.erb +8 -0
- data/app/views/outpost/home/dashboard.html.erb +1 -0
- data/app/views/outpost/resource/_errors.html.erb +11 -0
- data/app/views/outpost/resource/_extra_fields.html.erb +1 -0
- data/app/views/outpost/resource/_form_fields.html.erb +9 -0
- data/app/views/outpost/resource/edit.html.erb +44 -0
- data/app/views/outpost/resource/index.html.erb +22 -0
- data/app/views/outpost/resource/new.html.erb +21 -0
- data/app/views/outpost/resource/search.html.erb +1 -0
- data/app/views/outpost/resource/show.html.erb +1 -0
- data/app/views/outpost/sessions/new.html.erb +16 -0
- data/app/views/outpost/shared/_add_link.html.erb +1 -0
- data/app/views/outpost/shared/_breadcrumbs.html.erb +15 -0
- data/app/views/outpost/shared/_cancel_link.html.erb +1 -0
- data/app/views/outpost/shared/_columns.html.erb +5 -0
- data/app/views/outpost/shared/_filters.html.erb +16 -0
- data/app/views/outpost/shared/_flash_messages.html.erb +6 -0
- data/app/views/outpost/shared/_form_block.html.erb +18 -0
- data/app/views/outpost/shared/_form_nav.html.erb +12 -0
- data/app/views/outpost/shared/_headers.html.erb +16 -0
- data/app/views/outpost/shared/_index_header.html.erb +4 -0
- data/app/views/outpost/shared/_list_table.html.erb +7 -0
- data/app/views/outpost/shared/_modal.html.erb +16 -0
- data/app/views/outpost/shared/_navigation.html.erb +31 -0
- data/app/views/outpost/shared/_notice.html.erb +1 -0
- data/app/views/outpost/shared/_pagination.html.erb +2 -0
- data/app/views/outpost/shared/_preview_errors.html.erb +9 -0
- data/app/views/outpost/shared/_submit_row.html.erb +50 -0
- data/config/routes.rb +4 -0
- data/lib/action_view/helpers/form_builder.rb +71 -0
- data/lib/outpost/breadcrumbs.rb +73 -0
- data/lib/outpost/config.rb +63 -0
- data/lib/outpost/controller/actions.rb +72 -0
- data/lib/outpost/controller/authentication.rb +34 -0
- data/lib/outpost/controller/authorization.rb +28 -0
- data/lib/outpost/controller/callbacks.rb +14 -0
- data/lib/outpost/controller/custom_errors.rb +41 -0
- data/lib/outpost/controller/filtering.rb +22 -0
- data/lib/outpost/controller/helpers.rb +52 -0
- data/lib/outpost/controller/ordering.rb +46 -0
- data/lib/outpost/controller/preferences.rb +71 -0
- data/lib/outpost/controller.rb +123 -0
- data/lib/outpost/engine.rb +10 -0
- data/lib/outpost/helpers/naming.rb +22 -0
- data/lib/outpost/helpers.rb +6 -0
- data/lib/outpost/hook.rb +35 -0
- data/lib/outpost/list/base.rb +78 -0
- data/lib/outpost/list/column.rb +24 -0
- data/lib/outpost/list/filter.rb +37 -0
- data/lib/outpost/list.rb +15 -0
- data/lib/outpost/model/authentication.rb +34 -0
- data/lib/outpost/model/authorization.rb +32 -0
- data/lib/outpost/model/identifier.rb +39 -0
- data/lib/outpost/model/methods.rb +23 -0
- data/lib/outpost/model/naming.rb +63 -0
- data/lib/outpost/model/routing.rb +138 -0
- data/lib/outpost/model/serializer.rb +27 -0
- data/lib/outpost/model.rb +22 -0
- data/lib/outpost/test.rb +21 -0
- data/lib/outpost/version.rb +3 -0
- data/lib/outpost-cms.rb +2 -0
- data/lib/outpost.rb +80 -0
- data/lib/tasks/outpost_tasks.rake +7 -0
- data/spec/controllers/authentication_spec.rb +62 -0
- data/spec/controllers/sessions_controller_spec.rb +99 -0
- data/spec/factories.rb +31 -0
- data/spec/helpers/authorization_helper_spec.rb +47 -0
- data/spec/helpers/list_helper_spec.rb +74 -0
- data/spec/helpers/outpost_helper_spec.rb +5 -0
- data/spec/helpers/render_helper_spec.rb +19 -0
- data/spec/helpers/utility_helper_spec.rb +53 -0
- data/spec/internal/app/controllers/application_controller.rb +3 -0
- data/spec/internal/app/controllers/outpost/people_controller.rb +23 -0
- data/spec/internal/app/controllers/outpost/pidgeons_controller.rb +5 -0
- data/spec/internal/app/controllers/people_controller.rb +9 -0
- data/spec/internal/app/controllers/pidgeons_controller.rb +3 -0
- data/spec/internal/app/models/person.rb +10 -0
- data/spec/internal/app/models/pidgeon.rb +3 -0
- data/spec/internal/app/models/post.rb +4 -0
- data/spec/internal/app/models/user.rb +4 -0
- data/spec/internal/app/views/people/index.html.erb +7 -0
- data/spec/internal/app/views/people/show.html.erb +1 -0
- data/spec/internal/config/database.yml +3 -0
- data/spec/internal/config/initializers/configuration.rb +3 -0
- data/spec/internal/config/initializers/outpost.rb +6 -0
- data/spec/internal/config/routes.rb +16 -0
- data/spec/internal/db/combustion_test.sqlite +0 -0
- data/spec/internal/db/schema.rb +44 -0
- data/spec/internal/db/seeds.rb +14 -0
- data/spec/internal/log/test.log +59277 -0
- data/spec/internal/public/favicon.ico +0 -0
- data/spec/lib/breadcrumbs_spec.rb +54 -0
- data/spec/lib/config_spec.rb +76 -0
- data/spec/lib/controller/actions_spec.rb +5 -0
- data/spec/lib/controller/authorization_spec.rb +4 -0
- data/spec/lib/controller/callbacks_spec.rb +31 -0
- data/spec/lib/controller/helpers_spec.rb +33 -0
- data/spec/lib/controller_spec.rb +25 -0
- data/spec/lib/helpers/naming_spec.rb +10 -0
- data/spec/lib/hook_spec.rb +13 -0
- data/spec/lib/list/base_spec.rb +96 -0
- data/spec/lib/list/column_spec.rb +46 -0
- data/spec/lib/list/filter_spec.rb +44 -0
- data/spec/lib/model/authentication_spec.rb +29 -0
- data/spec/lib/model/authorization_spec.rb +66 -0
- data/spec/lib/model/identifier_spec.rb +51 -0
- data/spec/lib/model/methods_spec.rb +8 -0
- data/spec/lib/model/naming_spec.rb +55 -0
- data/spec/lib/model/routing_spec.rb +166 -0
- data/spec/lib/model/serializer_spec.rb +13 -0
- data/spec/lib/outpost_spec.rb +34 -0
- data/spec/models/permission_spec.rb +10 -0
- data/spec/models/user_permission_spec.rb +4 -0
- data/spec/spec_helper.rb +22 -0
- metadata +411 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
##
|
|
2
|
+
# Filter
|
|
3
|
+
#
|
|
4
|
+
module Outpost
|
|
5
|
+
module List
|
|
6
|
+
class Filter
|
|
7
|
+
BOOLEAN_COLLECT = [["Yes", 1], ["No", 0]]
|
|
8
|
+
|
|
9
|
+
attr_accessor :attribute, :collection, :title, :list
|
|
10
|
+
|
|
11
|
+
def initialize(attribute, list, options={})
|
|
12
|
+
@attribute = attribute.to_s
|
|
13
|
+
@list = list
|
|
14
|
+
@title = options[:title] || @attribute.titleize
|
|
15
|
+
|
|
16
|
+
collection = options[:collection]
|
|
17
|
+
@collection = begin
|
|
18
|
+
case collection
|
|
19
|
+
when NilClass
|
|
20
|
+
# TODO Automatically detect column type
|
|
21
|
+
when Proc
|
|
22
|
+
collection
|
|
23
|
+
when Symbol
|
|
24
|
+
send "_#{collection}_collection"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def _boolean_collection
|
|
33
|
+
-> { BOOLEAN_COLLECT }
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
data/lib/outpost/list.rb
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module Outpost
|
|
2
|
+
module Model
|
|
3
|
+
module Authentication
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
included do
|
|
7
|
+
has_secure_password
|
|
8
|
+
|
|
9
|
+
before_validation :downcase_email, if: -> { self.email_changed? }
|
|
10
|
+
validates :name, presence: true
|
|
11
|
+
validates Outpost.config.authentication_attribute, presence: true, uniqueness: true
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
module ClassMethods
|
|
15
|
+
def authenticate(login, unencrypted_password)
|
|
16
|
+
if user = self.send("find_by_#{Outpost.config.authentication_attribute}", login)
|
|
17
|
+
user.authenticate(unencrypted_password)
|
|
18
|
+
else
|
|
19
|
+
false
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Private: Downcase the user's e-mail
|
|
25
|
+
#
|
|
26
|
+
# Returns String of the e-mail
|
|
27
|
+
def downcase_email
|
|
28
|
+
if self.email.present?
|
|
29
|
+
self.email = self.email.downcase
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module Outpost
|
|
2
|
+
module Model
|
|
3
|
+
module Authorization
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
included do
|
|
7
|
+
has_many :user_permissions
|
|
8
|
+
has_many :permissions, through: :user_permissions
|
|
9
|
+
end
|
|
10
|
+
# Check if a user can manage the passed-in resource(s)
|
|
11
|
+
#
|
|
12
|
+
# If multiple resources are passed in, a user must be
|
|
13
|
+
# allowed to manage ALL of them in order for this to
|
|
14
|
+
# return true.
|
|
15
|
+
#
|
|
16
|
+
# Constants must be passed in.
|
|
17
|
+
#
|
|
18
|
+
def can_manage?(*resources)
|
|
19
|
+
self.is_superuser? or (allowed_resources & resources) == resources
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
#
|
|
23
|
+
|
|
24
|
+
def allowed_resources
|
|
25
|
+
@allowed_resources ||= begin
|
|
26
|
+
p = self.is_superuser? ? Permission.all : self.permissions
|
|
27
|
+
p.map { |p| p.resource.safe_constantize }.compact
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
##
|
|
2
|
+
# Identifier
|
|
3
|
+
#
|
|
4
|
+
# Some unique keys which can be used for routing
|
|
5
|
+
# and APIs
|
|
6
|
+
module Outpost
|
|
7
|
+
module Model
|
|
8
|
+
module Identifier
|
|
9
|
+
extend ActiveSupport::Concern
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
module ClassMethods
|
|
13
|
+
def content_key
|
|
14
|
+
if self.respond_to? :table_name
|
|
15
|
+
self.table_name.gsub(/_/, "/")
|
|
16
|
+
else
|
|
17
|
+
self.name.tableize
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Wrappers for ActiveModel::Naming
|
|
22
|
+
# NewsStory => news_stories
|
|
23
|
+
def route_key
|
|
24
|
+
ActiveModel::Naming.route_key(self)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# NewsStory => news_story
|
|
28
|
+
def singular_route_key
|
|
29
|
+
ActiveModel::Naming.singular_route_key(self)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Default obj_key pattern
|
|
34
|
+
def obj_key
|
|
35
|
+
@obj_key ||= [self.class.content_key,self.id || "new"].join(":")
|
|
36
|
+
end
|
|
37
|
+
end # Identifier
|
|
38
|
+
end # Model
|
|
39
|
+
end # Outpost
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
##
|
|
2
|
+
# Outpost::Model::Methods
|
|
3
|
+
#
|
|
4
|
+
# This could be renamed to something more specific
|
|
5
|
+
module Outpost
|
|
6
|
+
module Model
|
|
7
|
+
module Methods
|
|
8
|
+
extend ActiveSupport::Concern
|
|
9
|
+
|
|
10
|
+
def persisted_record
|
|
11
|
+
@persisted_record ||= begin
|
|
12
|
+
# If this record isn't persisted, return nil
|
|
13
|
+
return nil if !self.persisted?
|
|
14
|
+
|
|
15
|
+
# If attributes have been changed, then fetch
|
|
16
|
+
# the persisted record from the database
|
|
17
|
+
# Otherwise just use self
|
|
18
|
+
self.changed? ? self.class.find(self.id) : self
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end # Methods
|
|
22
|
+
end # Model
|
|
23
|
+
end # Outpost
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
##
|
|
2
|
+
# Naming
|
|
3
|
+
#
|
|
4
|
+
# Some methods for naming things, and stuff
|
|
5
|
+
module Outpost
|
|
6
|
+
module Model
|
|
7
|
+
module Naming
|
|
8
|
+
extend ActiveSupport::Concern
|
|
9
|
+
|
|
10
|
+
module ClassMethods
|
|
11
|
+
# NewsStory => News Story
|
|
12
|
+
def to_title
|
|
13
|
+
self.name.demodulize.titleize
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Convert any AR object into a human-readable title
|
|
18
|
+
# Tries the attributes in config.title_attributes
|
|
19
|
+
# And falls back to "BlogEntry #99"
|
|
20
|
+
#
|
|
21
|
+
# This allows us to get a human-readable title regardless
|
|
22
|
+
# of what an object's "title" attribute happens to be.
|
|
23
|
+
#
|
|
24
|
+
# To define your own set of attributes, do so with the config
|
|
25
|
+
#
|
|
26
|
+
# Outpost.config.title_attributes = [:title, :full_name]
|
|
27
|
+
#
|
|
28
|
+
# The :simple_title method will automatically be added to the array
|
|
29
|
+
# and acts as the fallback.
|
|
30
|
+
#
|
|
31
|
+
# Usage:
|
|
32
|
+
#
|
|
33
|
+
# story = NewsStory.last #=> NewsStory(id: 900, title: "Cool Story, Bro")
|
|
34
|
+
# blog = Blog.last #=> Blog(id: 5, name: "Some Blog")
|
|
35
|
+
# photo = Photo.last #=> Photo(id: 10, url: "http://photos.com/kitty")
|
|
36
|
+
#
|
|
37
|
+
# story.to_title #=> "Cool Story, Bro"
|
|
38
|
+
# blog.to_title #=> "Some Blog"
|
|
39
|
+
# photo.to_title #=> "Photo #10"
|
|
40
|
+
#
|
|
41
|
+
def title_method
|
|
42
|
+
@title_method ||= begin
|
|
43
|
+
attributes = Outpost.config.title_attributes
|
|
44
|
+
attributes.find { |a| self.respond_to?(a) }
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def to_title
|
|
49
|
+
@to_title ||= self.send(self.title_method)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def simple_title
|
|
53
|
+
@simple_title ||= begin
|
|
54
|
+
if self.new_record?
|
|
55
|
+
"New #{self.class.to_title}"
|
|
56
|
+
else
|
|
57
|
+
"#{self.class.to_title} ##{self.id}"
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end # Naming
|
|
62
|
+
end # Model
|
|
63
|
+
end # Outpost
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
module Outpost
|
|
2
|
+
module Model
|
|
3
|
+
# Routing
|
|
4
|
+
#
|
|
5
|
+
# Provides easy access to any object's admin paths,
|
|
6
|
+
# and any class's admin paths.
|
|
7
|
+
#
|
|
8
|
+
# These methods are just delegations to your app's routes.
|
|
9
|
+
#
|
|
10
|
+
# Provides alias methods for non-GET routes:
|
|
11
|
+
#
|
|
12
|
+
# * admin_index_path => admin_create_path
|
|
13
|
+
# * admin_show_path => admin_update_path, admin_destroy_path
|
|
14
|
+
#
|
|
15
|
+
# So you can do, for example:
|
|
16
|
+
#
|
|
17
|
+
# POST admin_create_path
|
|
18
|
+
#
|
|
19
|
+
# Which would make more sense than `POST admin_index_path`,
|
|
20
|
+
# even though they are the same path.
|
|
21
|
+
module Routing
|
|
22
|
+
extend ActiveSupport::Concern
|
|
23
|
+
|
|
24
|
+
module ClassMethods
|
|
25
|
+
# /outpost/blog_entries/new
|
|
26
|
+
def admin_new_path
|
|
27
|
+
collection_route("new_outpost_#{self.singular_route_key}_path")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# http://kpcc.org/outpost/blog_entries/new
|
|
31
|
+
def admin_new_url
|
|
32
|
+
collection_route("new_outpost_#{self.singular_route_key}_url")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# /outpost/blog_entries
|
|
37
|
+
def admin_index_path
|
|
38
|
+
collection_route("outpost_#{self.route_key}_path")
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
alias_method :admin_create_path, :admin_index_path
|
|
42
|
+
|
|
43
|
+
# http://kpcc.org/outpost/blog_entries
|
|
44
|
+
def admin_index_url
|
|
45
|
+
collection_route("outpost_#{self.route_key}_url")
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
alias_method :admin_create_url, :admin_index_url
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def collection_route(name)
|
|
54
|
+
Rails.application.routes.url_helpers.send(name)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
# /outpost/blog_entries/20/edit
|
|
60
|
+
def admin_edit_path
|
|
61
|
+
member_route("edit_outpost_#{self.class.singular_route_key}_path")
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# http://kpcc.org/outpost/blog_entries/20/edit
|
|
65
|
+
def admin_edit_url
|
|
66
|
+
member_route("edit_outpost_#{self.class.singular_route_key}_url")
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
# /outpost/blog_entries/20
|
|
71
|
+
def admin_show_path
|
|
72
|
+
member_route("outpost_#{self.class.singular_route_key}_path")
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
alias_method :admin_update_path, :admin_show_path
|
|
76
|
+
alias_method :admin_destroy_path, :admin_show_path
|
|
77
|
+
|
|
78
|
+
# http://kpcc.org/outpost/blog_entries/20
|
|
79
|
+
def admin_show_url
|
|
80
|
+
member_route("outpost_#{self.class.singular_route_key}_url")
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
alias_method :admin_update_url, :admin_show_url
|
|
84
|
+
alias_method :admin_destroy_url, :admin_show_url
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
# Uses self.class::ROUTE_KEY to generate
|
|
88
|
+
# the front-end path to this object
|
|
89
|
+
# If an object doesn't have a front-end path,
|
|
90
|
+
# do not define a ROUTE_KEY on the class.
|
|
91
|
+
#
|
|
92
|
+
# If the object isn't public, then leave route_hash
|
|
93
|
+
# empty as well.
|
|
94
|
+
def public_path(options={})
|
|
95
|
+
if self.route_hash.present? && defined?(self.class::ROUTE_KEY)
|
|
96
|
+
Rails.application.routes.url_helpers.send(
|
|
97
|
+
"#{self.class::ROUTE_KEY}_path", options.merge!(self.route_hash))
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
alias_method :link_path, :public_path
|
|
102
|
+
deprecate link_path: :public_path
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
# Override this method manually for each model.
|
|
106
|
+
# If the object isn't public, then don't override
|
|
107
|
+
# this method. #public_path checks for the presence
|
|
108
|
+
# of this object. By leaving it blank, you're also
|
|
109
|
+
# telling #public_path to be nil.
|
|
110
|
+
def route_hash
|
|
111
|
+
{}
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
# http://scpr.org/blogs/2012/...
|
|
116
|
+
def public_url(options={})
|
|
117
|
+
if path = self.public_path(options)
|
|
118
|
+
File.join(
|
|
119
|
+
"http://#{Rails.application.default_url_options[:host]}", path)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
alias_method :remote_link_path, :public_url
|
|
124
|
+
deprecate remote_link_path: :public_url
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
private
|
|
128
|
+
|
|
129
|
+
# Don't try to build a route if the ID is nil.
|
|
130
|
+
# Should we instead be checking persistence?
|
|
131
|
+
def member_route(name)
|
|
132
|
+
if self.id
|
|
133
|
+
Rails.application.routes.url_helpers.send(name, self.id)
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end # Routing
|
|
137
|
+
end # Model
|
|
138
|
+
end # Outpost
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Outpost
|
|
2
|
+
module Model
|
|
3
|
+
module Serializer
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
# This method should be overridden
|
|
7
|
+
# Don't override as_json unless you don't
|
|
8
|
+
# want its baked-in goodies
|
|
9
|
+
def json
|
|
10
|
+
{}
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Define some defaults for as_json
|
|
14
|
+
# Override +#json+ to add attributes
|
|
15
|
+
# or override any of these.
|
|
16
|
+
def as_json(*args)
|
|
17
|
+
super.merge({
|
|
18
|
+
"id" => self.obj_key,
|
|
19
|
+
"obj_key" => self.obj_key,
|
|
20
|
+
"link_path" => self.public_path,
|
|
21
|
+
"to_title" => self.to_title,
|
|
22
|
+
"edit_path" => self.admin_edit_path
|
|
23
|
+
}).merge(self.json.stringify_keys!)
|
|
24
|
+
end
|
|
25
|
+
end # JSON
|
|
26
|
+
end # Model
|
|
27
|
+
end # Outpost
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
##
|
|
2
|
+
# Outpost::Model
|
|
3
|
+
module Outpost
|
|
4
|
+
module Model
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
extend ActiveSupport::Autoload
|
|
7
|
+
|
|
8
|
+
autoload :Authentication
|
|
9
|
+
autoload :Authorization
|
|
10
|
+
autoload :Methods
|
|
11
|
+
autoload :Identifier
|
|
12
|
+
autoload :Routing
|
|
13
|
+
autoload :Naming
|
|
14
|
+
autoload :Serializer
|
|
15
|
+
|
|
16
|
+
module ClassMethods
|
|
17
|
+
def outpost_model
|
|
18
|
+
include Methods, Identifier, Routing, Naming, Serializer
|
|
19
|
+
end
|
|
20
|
+
end # ClassMethods
|
|
21
|
+
end # Model
|
|
22
|
+
end # Outpost
|
data/lib/outpost/test.rb
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Some test helpers
|
|
2
|
+
|
|
3
|
+
module Outpost
|
|
4
|
+
module Test
|
|
5
|
+
extend self
|
|
6
|
+
|
|
7
|
+
# Populate the permissions table.
|
|
8
|
+
# Especially useful when using truncation strategy.
|
|
9
|
+
def create_permissions
|
|
10
|
+
created = []
|
|
11
|
+
|
|
12
|
+
Outpost.config.registered_models.each do |model|
|
|
13
|
+
if !Permission.exists?(resource: model)
|
|
14
|
+
created << Permission.create(resource: model)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
created
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
data/lib/outpost-cms.rb
ADDED
data/lib/outpost.rb
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
require "outpost/engine"
|
|
2
|
+
|
|
3
|
+
require 'active_record'
|
|
4
|
+
require 'action_controller'
|
|
5
|
+
require 'action_view'
|
|
6
|
+
require 'action_view/helpers/form_builder'
|
|
7
|
+
|
|
8
|
+
require 'outpost/config'
|
|
9
|
+
|
|
10
|
+
module Outpost
|
|
11
|
+
extend ActiveSupport::Autoload
|
|
12
|
+
|
|
13
|
+
OBJ_KEY_REGEX = %r{([^:]+):(\d+)}
|
|
14
|
+
|
|
15
|
+
autoload :Controller
|
|
16
|
+
autoload :Model
|
|
17
|
+
autoload :Hook
|
|
18
|
+
autoload :Helpers
|
|
19
|
+
autoload :List
|
|
20
|
+
autoload :Breadcrumb, 'outpost/breadcrumbs'
|
|
21
|
+
autoload :Breadcrumbs
|
|
22
|
+
|
|
23
|
+
class << self
|
|
24
|
+
attr_writer :config
|
|
25
|
+
def config
|
|
26
|
+
@config ||= Outpost::Config.new
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# TODO can we cache this in development?
|
|
30
|
+
def user_class
|
|
31
|
+
config.user_class.constantize
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
#--------------------
|
|
35
|
+
# Convert key from "app/model:id" to AppModel.find_by_id(id)
|
|
36
|
+
def obj_by_key(key)
|
|
37
|
+
if match = match_key(key)
|
|
38
|
+
model = model_classes[match[1]]
|
|
39
|
+
model.find_by_id(match[2]) if model
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
#--------------------
|
|
44
|
+
# Same as #obj_by_key, but raises ActiveRecord::RecordNotFound
|
|
45
|
+
# if no object is found or if key doesn't match.
|
|
46
|
+
def obj_by_key!(key)
|
|
47
|
+
obj_by_key(key) or raise ActiveRecord::RecordNotFound
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def match_key(key)
|
|
54
|
+
key.to_s.match(OBJ_KEY_REGEX)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
#--------------------
|
|
58
|
+
|
|
59
|
+
def model_classes
|
|
60
|
+
@model_classes ||= begin
|
|
61
|
+
klasses = {}
|
|
62
|
+
|
|
63
|
+
Outpost.config.registered_models.each do |name|
|
|
64
|
+
klass = name.constantize
|
|
65
|
+
klasses.merge!(klass.content_key => klass)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
klasses
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
if defined?(ActiveRecord::Base)
|
|
75
|
+
ActiveRecord::Base.send :include, Outpost::Model
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
if defined?(ActionController::Base)
|
|
79
|
+
ActionController::Base.send :include, Outpost::Controller
|
|
80
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Outpost::PeopleController do
|
|
4
|
+
describe "current_user" do
|
|
5
|
+
it "looks up the ID stored in the session" do
|
|
6
|
+
user = create :user
|
|
7
|
+
controller.session[:user_id] = user.id
|
|
8
|
+
controller.current_user.should eq user
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it "only finds user where can_login is true" do
|
|
12
|
+
user = create :user, can_login: true
|
|
13
|
+
controller.session[:user_id] = user.id
|
|
14
|
+
controller.current_user.should eq user
|
|
15
|
+
|
|
16
|
+
controller.instance_variable_set(:@current_user, nil)
|
|
17
|
+
nologin_user = create :user, can_login: false
|
|
18
|
+
controller.session[:user_id] = nologin_user.id
|
|
19
|
+
controller.current_user.should eq nil
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "returns nil if session is blank" do
|
|
23
|
+
controller.session[:user_id] = nil
|
|
24
|
+
controller.current_user.should eq nil
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "unsets the session and returns false if the user isn't found" do
|
|
28
|
+
controller.session[:user_id] = 999
|
|
29
|
+
controller.current_user.should eq nil
|
|
30
|
+
controller.session[:user_id].should eq nil
|
|
31
|
+
controller.instance_variable_get(:@current_user).should eq nil
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
#-----------------
|
|
36
|
+
|
|
37
|
+
describe "require_login" do
|
|
38
|
+
context "current_user true" do
|
|
39
|
+
it "returns nil" do
|
|
40
|
+
user = create :user
|
|
41
|
+
controller.stub(:current_user) { user }
|
|
42
|
+
controller.require_login.should eq nil
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
context "current_user false" do
|
|
47
|
+
before :each do
|
|
48
|
+
controller.stub(:current_user) { nil }
|
|
49
|
+
controller.request.stub(:fullpath) { "/home" }
|
|
50
|
+
get :index
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it "sets the return_to to the request path" do
|
|
54
|
+
controller.session[:return_to].should eq "/home"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "redirects to login path if current_user is false" do
|
|
58
|
+
controller.response.should redirect_to outpost_login_path
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|