adminpanel 2.1.7 → 2.2.0
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.
- checksums.yaml +4 -4
- data/.travis.yml +11 -3
- data/Gemfile +3 -27
- data/adminpanel.gemspec +24 -23
- data/app/assets/images/adminpanel/loguito.png +0 -0
- data/app/assets/javascripts/adminpanel/bootstrap-wysihtml5-4pre.js +120 -120
- data/app/assets/javascripts/adminpanel/spinner.js.coffee +6 -6
- data/app/assets/stylesheets/adminpanel/bootstrap-wysihtml5.css +21 -75
- data/app/controllers/adminpanel/analytics_controller.rb +34 -2
- data/app/controllers/adminpanel/application_controller.rb +7 -6
- data/app/controllers/adminpanel/categories_controller.rb +0 -1
- data/app/controllers/adminpanel/galleries_controller.rb +0 -1
- data/app/controllers/adminpanel/permissions_controller.rb +14 -0
- data/app/controllers/adminpanel/rols_controller.rb +10 -0
- data/app/controllers/adminpanel/sections_controller.rb +11 -14
- data/app/controllers/adminpanel/sessions_controller.rb +45 -11
- data/app/controllers/adminpanel/users_controller.rb +2 -4
- data/app/controllers/concerns/adminpanel/analytics/instagram_analytics.rb +31 -0
- data/app/controllers/concerns/adminpanel/analytics/twitter_analytics.rb +25 -0
- data/app/controllers/concerns/adminpanel/facebook_actions.rb +7 -5
- data/app/controllers/concerns/adminpanel/rest_actions.rb +12 -0
- data/app/controllers/concerns/adminpanel/twitter_actions.rb +40 -0
- data/app/helpers/adminpanel/adminpanel_form_builder.rb +21 -14
- data/app/helpers/adminpanel/analytics_helper.rb +22 -2
- data/app/helpers/adminpanel/application_helper.rb +2 -2
- data/app/helpers/adminpanel/breadcrumbs_helper.rb +8 -6
- data/app/helpers/adminpanel/router_helper.rb +4 -0
- data/app/helpers/adminpanel/sessions_helper.rb +2 -2
- data/app/helpers/adminpanel/shared_pages_helper.rb +3 -3
- data/{lib/generators/adminpanel/initialize/templates → app/models}/ability.rb +18 -6
- data/app/models/adminpanel/analytic.rb +1 -0
- data/app/models/adminpanel/auth.rb +4 -1
- data/app/models/adminpanel/permission.rb +52 -0
- data/app/models/adminpanel/rol.rb +35 -0
- data/app/models/adminpanel/user.rb +8 -8
- data/app/models/concerns/adminpanel/base.rb +4 -0
- data/app/models/concerns/adminpanel/facebook.rb +1 -1
- data/app/models/concerns/adminpanel/twitter.rb +27 -0
- data/app/views/adminpanel/analytics/{_widget_task_statistics.html.erb → _fb_statistic_widget.html.erb} +0 -0
- data/app/views/adminpanel/analytics/_header.html.erb +8 -2
- data/app/views/adminpanel/analytics/_instagram_details_modal.html.erb +55 -0
- data/app/views/adminpanel/analytics/_instagram_media.html.erb +25 -0
- data/app/views/adminpanel/analytics/_tweet.html.erb +32 -0
- data/app/views/adminpanel/analytics/_twitter_reply_modal.html.erb +41 -0
- data/app/views/adminpanel/analytics/fb.html.erb +6 -6
- data/app/views/adminpanel/analytics/instagram.html.erb +65 -0
- data/app/views/adminpanel/analytics/twitter.html.erb +89 -0
- data/app/views/adminpanel/sections/edit.html.erb +2 -5
- data/app/views/layouts/_side_menu.html.erb +3 -3
- data/app/views/layouts/admin.html.erb +2 -2
- data/app/views/shared/_delete_icon_button.html.erb +1 -1
- data/app/views/shared/_edit_icon_button.html.erb +1 -1
- data/app/views/shared/_fb_icon_button.html.erb +1 -1
- data/app/views/shared/_form_fields.html.erb +1 -1
- data/app/views/shared/_new_resource_button.html.erb +1 -2
- data/app/views/shared/_twitter_icon_button.html.erb +26 -0
- data/app/views/shared/_twitter_publish_modal.html.erb +40 -0
- data/app/views/shared/index.html.erb +5 -3
- data/app/views/shared/show.html.erb +7 -3
- data/config/initializers/twitter-oauth.rb +15 -0
- data/config/locales/en.yml +1 -1
- data/config/locales/es.yml +20 -1
- data/config/routes.rb +25 -5
- data/lib/adminpanel.rb +3 -0
- data/lib/adminpanel/engine.rb +19 -5
- data/lib/adminpanel/version.rb +1 -1
- data/lib/generators/adminpanel/initialize/initialize_generator.rb +0 -11
- data/lib/generators/adminpanel/initialize/templates/adminpanel_setup.rb +12 -0
- data/lib/generators/adminpanel/initialize/templates/create_adminpanel_tables.rb +74 -46
- data/lib/generators/adminpanel/resource/resource_generator_helper.rb +1 -1
- data/lib/generators/adminpanel/resource/templates/adminpanel_resource_template.rb +1 -1
- data/lib/tasks/adminpanel/adminpanel.rake +5 -5
- data/test/dummy/app/models/adminpanel/item.rb +1 -1
- data/test/dummy/app/models/adminpanel/mug.rb +1 -0
- data/test/dummy/app/models/adminpanel/photo.rb +4 -0
- data/test/dummy/app/models/adminpanel/product.rb +7 -1
- data/test/dummy/app/models/adminpanel/salesman.rb +1 -0
- data/test/dummy/app/views/layouts/application.html.erb +0 -1
- data/test/dummy/db/schema.rb +9 -2
- data/test/dummy/test/fixtures/adminpanel/permissions.yml +42 -0
- data/test/dummy/test/fixtures/adminpanel/rols.yml +28 -0
- data/test/dummy/test/fixtures/adminpanel/salesmen.yml +1 -0
- data/test/dummy/test/fixtures/adminpanel/users.yml +49 -1
- data/test/features/shared/resource/index_test.rb +1 -0
- data/test/features/shared/ui/action_exclution_test.rb +1 -0
- data/test/helpers/breadcrumbs_helper_test.rb +34 -0
- data/test/helpers/router_helper_test.rb +21 -0
- data/test/helpers/shared_pages_helper_test.rb +35 -0
- data/test/models/ability_test.rb +52 -0
- data/test/models/adminpanel/gallery_test.rb +0 -2
- data/test/models/adminpanel/user_test.rb +1 -1
- data/test/support/shared_database.rb +11 -0
- data/test/support/view_case.rb +34 -0
- data/test/tasks/adminpanel_rake_test.rb +5 -2
- data/test/test_helper.rb +1 -41
- metadata +191 -200
- data/app/assets/javascripts/adminpanel/jquery.facybox.js +0 -395
- data/app/assets/stylesheets/adminpanel/facybox.css +0 -146
- data/app/models/adminpanel/group.rb +0 -6
- data/test/dummy/Rakefile +0 -7
- data/test/dummy/app/models/ability.rb +0 -31
- data/test/dummy/test/fixtures/adminpanel/groups.yml +0 -4
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
module Adminpanel
|
|
2
2
|
class AdminpanelFormBuilder < ActionView::Helpers::FormBuilder
|
|
3
|
-
|
|
3
|
+
include ApplicationHelper
|
|
4
4
|
alias_method :text_field_original, :text_field
|
|
5
5
|
alias_method :radio_button_original, :radio_button
|
|
6
6
|
alias_method :text_area_original, :text_area
|
|
@@ -10,11 +10,11 @@ module Adminpanel
|
|
|
10
10
|
alias_method :file_field_original, :file_field
|
|
11
11
|
# alias_method :select_original, :select
|
|
12
12
|
|
|
13
|
-
def text_field
|
|
14
|
-
base_layout
|
|
13
|
+
def text_field name, *args
|
|
14
|
+
base_layout name, *args, 'text_field_original'
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
def file_field
|
|
17
|
+
def file_field name, *args
|
|
18
18
|
image_input = base_layout(name, *args, 'file_field_original')
|
|
19
19
|
|
|
20
20
|
if !object.nil? && !object.new_record? #if not new record
|
|
@@ -24,20 +24,20 @@ module Adminpanel
|
|
|
24
24
|
end
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
-
def gallery_field
|
|
28
|
-
base_layout
|
|
27
|
+
def gallery_field name, *args
|
|
28
|
+
base_layout name, *args, 'gallery_base'
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
def wysiwyg_field
|
|
31
|
+
def wysiwyg_field name, *args
|
|
32
32
|
|
|
33
33
|
options = args.extract_options!
|
|
34
34
|
options.reverse_merge! class: 'wysihtml5 span7'
|
|
35
35
|
|
|
36
|
-
base_layout
|
|
36
|
+
base_layout name, options, 'text_area_original'
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
-
def text_area
|
|
40
|
-
base_layout
|
|
39
|
+
def text_area name, *args
|
|
40
|
+
base_layout name, *args, 'text_area_original'
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
# def radio_button_group(name, buttons, options)
|
|
@@ -55,7 +55,7 @@ module Adminpanel
|
|
|
55
55
|
# end
|
|
56
56
|
# end
|
|
57
57
|
|
|
58
|
-
def checkbox
|
|
58
|
+
def checkbox checkbox_object, form_object_name, relationship
|
|
59
59
|
@template.content_tag(
|
|
60
60
|
:label,
|
|
61
61
|
@template.check_box_tag(
|
|
@@ -67,8 +67,16 @@ module Adminpanel
|
|
|
67
67
|
)
|
|
68
68
|
end
|
|
69
69
|
|
|
70
|
-
def boolean
|
|
71
|
-
base_layout
|
|
70
|
+
def boolean name, *args
|
|
71
|
+
base_layout name, *args, 'boolean_base'
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def enum_field name, *args
|
|
75
|
+
select name, self.object.class.actions.map{|action, value| [I18n.t("enum.#{action}"), action]}, *args
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def resource_select name, *args
|
|
79
|
+
select name, Adminpanel.displayable_resources.map{|resource| [symbol_class(resource).display_name, resource.to_s]}, *args
|
|
72
80
|
end
|
|
73
81
|
|
|
74
82
|
def select(name, select_options, *args)
|
|
@@ -103,7 +111,6 @@ module Adminpanel
|
|
|
103
111
|
super(name, *args << options)
|
|
104
112
|
end
|
|
105
113
|
|
|
106
|
-
|
|
107
114
|
def datepicker(name, *args)
|
|
108
115
|
base_layout( name, *args, 'datepickerize_base' )
|
|
109
116
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
module Adminpanel
|
|
2
2
|
module AnalyticsHelper
|
|
3
|
-
def first_fb_value
|
|
3
|
+
def first_fb_value metric
|
|
4
4
|
total = 0.0
|
|
5
5
|
# metric.first['values'].each do |value|
|
|
6
6
|
# if value['value'] != []
|
|
@@ -23,7 +23,7 @@ module Adminpanel
|
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
def divide_metrics
|
|
26
|
+
def divide_metrics metric_1, metric_2
|
|
27
27
|
if first_fb_value(metric_2) != 0.0
|
|
28
28
|
return first_fb_value(metric_1) / first_fb_value(metric_2)
|
|
29
29
|
else
|
|
@@ -41,5 +41,25 @@ module Adminpanel
|
|
|
41
41
|
def metric(metric)
|
|
42
42
|
metric.first['name']
|
|
43
43
|
end
|
|
44
|
+
|
|
45
|
+
def tweet_link(tweet)
|
|
46
|
+
"http://www.twitter.com/#{tweet.user.screen_name}/status/#{tweet.id}"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def exist_instagram_account?
|
|
50
|
+
if @instagram_token.nil?
|
|
51
|
+
false
|
|
52
|
+
else
|
|
53
|
+
true
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def exist_twitter_account?
|
|
58
|
+
if @twitter_token.nil? || @twitter_secret.nil?
|
|
59
|
+
false
|
|
60
|
+
else
|
|
61
|
+
true
|
|
62
|
+
end
|
|
63
|
+
end
|
|
44
64
|
end
|
|
45
65
|
end
|
|
@@ -44,8 +44,8 @@ module Adminpanel
|
|
|
44
44
|
model_name.pluralize.downcase
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
-
def symbol_class(
|
|
48
|
-
"adminpanel/#{
|
|
47
|
+
def symbol_class(symbol_model)
|
|
48
|
+
"adminpanel/#{symbol_model.to_s.singularize}".classify.constantize
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
def main_root_path
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
module Adminpanel
|
|
2
2
|
module BreadcrumbsHelper
|
|
3
3
|
|
|
4
|
-
def initialize_breadcrumb
|
|
5
|
-
@breadcrumb ||= [:title => 'Inicio', :url => root_url]
|
|
6
|
-
end
|
|
7
|
-
|
|
8
4
|
def breadcrumb_add(title, url)
|
|
9
|
-
initialize_breadcrumb << { :
|
|
5
|
+
initialize_breadcrumb << { title: title, url: url }
|
|
10
6
|
end
|
|
11
7
|
|
|
12
8
|
def render_breadcrumb(divider)
|
|
13
|
-
render :
|
|
9
|
+
render partial: 'shared/breadcrumb', locals: { nav: initialize_breadcrumb, divider: divider }
|
|
14
10
|
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
def initialize_breadcrumb
|
|
14
|
+
@breadcrumb ||= [{ title: 'Inicio', url: adminpanel.root_url }, ]
|
|
15
|
+
end
|
|
16
|
+
|
|
15
17
|
end
|
|
16
18
|
end
|
|
@@ -2,7 +2,7 @@ module Adminpanel
|
|
|
2
2
|
module SessionsHelper
|
|
3
3
|
|
|
4
4
|
def sign_in(user)
|
|
5
|
-
cookies.
|
|
5
|
+
cookies.signed[:remember_token] = user.remember_token
|
|
6
6
|
self.current_user = user
|
|
7
7
|
end
|
|
8
8
|
|
|
@@ -15,7 +15,7 @@ module Adminpanel
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def current_user
|
|
18
|
-
@current_user ||= User.find_by_remember_token(cookies[:remember_token])
|
|
18
|
+
@current_user ||= User.find_by_remember_token(cookies.signed[:remember_token])
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def sign_out
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
module Adminpanel
|
|
2
2
|
module SharedPagesHelper
|
|
3
|
-
def
|
|
3
|
+
def belong_to_object_name(resource, belong_to_assoc_name)
|
|
4
4
|
@model.reflect_on_all_associations.each do |association|
|
|
5
|
-
if association.
|
|
6
|
-
if !resource.send(association.name).nil?
|
|
5
|
+
if association.name.to_s == belong_to_assoc_name.to_s
|
|
6
|
+
if !resource.send(association.name.to_s).nil? #if there's something in the association
|
|
7
7
|
return resource.send(association.name).name
|
|
8
8
|
else
|
|
9
9
|
return "N/A #{association.klass.to_s}"
|
|
@@ -1,16 +1,28 @@
|
|
|
1
1
|
class Ability
|
|
2
2
|
include CanCan::Ability
|
|
3
|
+
include Adminpanel::ApplicationHelper
|
|
3
4
|
|
|
4
5
|
def initialize(user)
|
|
5
6
|
|
|
6
|
-
if user.
|
|
7
|
+
if user.nil?
|
|
8
|
+
elsif user.rol.name == 'Admin'
|
|
7
9
|
can :manage, :all
|
|
8
10
|
else
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
user.rol.permissions.each do |permission|
|
|
12
|
+
if permission.to_read?
|
|
13
|
+
can :read, symbol_class(permission.resource)
|
|
14
|
+
elsif permission.to_publish?
|
|
15
|
+
can :publish, symbol_class(permission.resource)
|
|
16
|
+
elsif permission.to_create?
|
|
17
|
+
can :create, symbol_class(permission.resource)
|
|
18
|
+
elsif permission.to_update?
|
|
19
|
+
can :update, symbol_class(permission.resource)
|
|
20
|
+
elsif permission.to_destroy?
|
|
21
|
+
can :destroy, symbol_class(permission.resource)
|
|
22
|
+
elsif permission.to_manage?
|
|
23
|
+
can :manage, symbol_class(permission.resource)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
14
26
|
end
|
|
15
27
|
|
|
16
28
|
# The first argument to `can` is the action you are giving the user
|
|
@@ -20,13 +20,16 @@ module Adminpanel
|
|
|
20
20
|
{
|
|
21
21
|
'key' => {
|
|
22
22
|
'type' => 'text_field',
|
|
23
|
-
'show' => 'show',
|
|
24
23
|
'label' => 'Llave'
|
|
25
24
|
}
|
|
26
25
|
}
|
|
27
26
|
]
|
|
28
27
|
end
|
|
29
28
|
|
|
29
|
+
def self.routes_options
|
|
30
|
+
{ except: [:edit, :update ], path: display_name.pluralize(I18n.default_locale).downcase }
|
|
31
|
+
end
|
|
32
|
+
|
|
30
33
|
def self.icon
|
|
31
34
|
'cubes'
|
|
32
35
|
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
module Adminpanel
|
|
2
|
+
class Permission < ActiveRecord::Base
|
|
3
|
+
include Adminpanel::Base
|
|
4
|
+
include ApplicationHelper
|
|
5
|
+
|
|
6
|
+
enum action: [ :to_read, :to_publish, :to_create, :to_update,
|
|
7
|
+
:to_destroy, :to_manage ]
|
|
8
|
+
|
|
9
|
+
belongs_to :rol
|
|
10
|
+
|
|
11
|
+
def name
|
|
12
|
+
"#{I18n.t('enum.' + action.to_s)} #{symbol_class(self.resource).display_name}"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.form_attributes
|
|
16
|
+
[
|
|
17
|
+
{
|
|
18
|
+
'rol_id' => {
|
|
19
|
+
'type' => 'belongs_to',
|
|
20
|
+
'label' => 'rol',
|
|
21
|
+
'placeholder' => 'rol',
|
|
22
|
+
'model' => 'Adminpanel::Rol',
|
|
23
|
+
# 'remote_resource' => false
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
'action' => {
|
|
28
|
+
'type' => 'enum_field',
|
|
29
|
+
'label' => 'action',
|
|
30
|
+
'placeholder' => 'action',
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
'resource' => {
|
|
35
|
+
'type' => 'resource_select',
|
|
36
|
+
'label' => 'resource',
|
|
37
|
+
'placeholder' => 'resource',
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def self.display_name
|
|
45
|
+
'Permiso' #singular
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.icon
|
|
49
|
+
"gavel" # fa-{icon}
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module Adminpanel
|
|
2
|
+
class Rol < ActiveRecord::Base
|
|
3
|
+
include Adminpanel::Base
|
|
4
|
+
has_many :permissions
|
|
5
|
+
validates_presence_of :name
|
|
6
|
+
validates_uniqueness_of :name
|
|
7
|
+
|
|
8
|
+
def self.form_attributes
|
|
9
|
+
[
|
|
10
|
+
{
|
|
11
|
+
'name' => {
|
|
12
|
+
'type' => 'text_field',
|
|
13
|
+
'label' => 'Nombre',
|
|
14
|
+
'placeholder' => 'Community Manager'
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
'permissions' => {
|
|
19
|
+
'type' => 'has_many',
|
|
20
|
+
'model' => "Adminpanel::Permission",
|
|
21
|
+
'label' => 'Permisos'
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.display_name
|
|
28
|
+
'Rol'
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.icon
|
|
32
|
+
'ticket'
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -2,10 +2,10 @@ module Adminpanel
|
|
|
2
2
|
class User < ActiveRecord::Base
|
|
3
3
|
include Adminpanel::Base
|
|
4
4
|
has_secure_password
|
|
5
|
-
belongs_to :
|
|
5
|
+
belongs_to :rol
|
|
6
6
|
|
|
7
|
-
#
|
|
8
|
-
validates_presence_of :
|
|
7
|
+
#rol validation
|
|
8
|
+
validates_presence_of :rol_id
|
|
9
9
|
|
|
10
10
|
#name validations
|
|
11
11
|
validates_presence_of :name
|
|
@@ -65,12 +65,12 @@ module Adminpanel
|
|
|
65
65
|
}
|
|
66
66
|
},
|
|
67
67
|
{
|
|
68
|
-
'
|
|
68
|
+
'rol_id' => {
|
|
69
69
|
'type' => 'belongs_to',
|
|
70
|
-
'model' => 'Adminpanel::
|
|
71
|
-
'remote_resource' => false,
|
|
72
|
-
'placeholder' => I18n.t('model.attributes.
|
|
73
|
-
'label' => I18n.t('model.attributes.
|
|
70
|
+
'model' => 'Adminpanel::Rol',
|
|
71
|
+
# 'remote_resource' => false,
|
|
72
|
+
'placeholder' => I18n.t('model.attributes.rol_id'),
|
|
73
|
+
'label' => I18n.t('model.attributes.rol_id')
|
|
74
74
|
}
|
|
75
75
|
},
|
|
76
76
|
]
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Adminpanel
|
|
2
|
+
module Twitter
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
included do
|
|
5
|
+
attr_accessor :twitter_message
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def share_link
|
|
9
|
+
'http://www.google.com'
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def has_valid_tweet?
|
|
13
|
+
if self.twitter_message.length <= 140
|
|
14
|
+
true
|
|
15
|
+
else
|
|
16
|
+
false
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# static(class) methods
|
|
21
|
+
module ClassMethods
|
|
22
|
+
def twitter_share?
|
|
23
|
+
true
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|