dune-admin 1.0.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.
Files changed (89) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.gitmodules +3 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +18 -0
  6. data/CHANGELOG.md +5 -0
  7. data/Gemfile +14 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +74 -0
  10. data/Rakefile +14 -0
  11. data/app/assets/images/dune/admin/.gitkip +0 -0
  12. data/app/assets/javascripts/dune-admin.js +2 -0
  13. data/app/assets/javascripts/dune/admin/admin.js.coffee +11 -0
  14. data/app/assets/javascripts/dune/admin/channels/new.js.coffee +14 -0
  15. data/app/assets/javascripts/dune/admin/modules/sort.js.coffee +44 -0
  16. data/app/assets/stylesheets/dune/admin/.gitkip +0 -0
  17. data/app/assets/stylesheets/dune/admin/admin.sass +37 -0
  18. data/app/assets/stylesheets/neighborly-admin.sass +1 -0
  19. data/app/controllers/dune/admin/base_controller.rb +25 -0
  20. data/app/controllers/dune/admin/channels/members_controller.rb +46 -0
  21. data/app/controllers/dune/admin/channels_controller.rb +49 -0
  22. data/app/controllers/dune/admin/contacts_controller.rb +9 -0
  23. data/app/controllers/dune/admin/contributions_controller.rb +33 -0
  24. data/app/controllers/dune/admin/dashboard_controller.rb +8 -0
  25. data/app/controllers/dune/admin/financials_controller.rb +33 -0
  26. data/app/controllers/dune/admin/press_assets_controller.rb +26 -0
  27. data/app/controllers/dune/admin/projects_controller.rb +80 -0
  28. data/app/controllers/dune/admin/reports/base_controller.rb +8 -0
  29. data/app/controllers/dune/admin/reports/contribution_reports_controller.rb +8 -0
  30. data/app/controllers/dune/admin/reports/funding_raised_per_project_reports_controller.rb +4 -0
  31. data/app/controllers/dune/admin/reports/statistics_controller.rb +5 -0
  32. data/app/controllers/dune/admin/tags_controller.rb +35 -0
  33. data/app/controllers/dune/admin/users_controller.rb +27 -0
  34. data/app/models/dune/admin/.gitkip +0 -0
  35. data/app/models/dune/admin/contribution_concern.rb +23 -0
  36. data/app/models/dune/admin/funding_raised_per_project_report.rb +5 -0
  37. data/app/models/dune/admin/project_concern.rb +41 -0
  38. data/app/models/dune/admin/statistics.rb +5 -0
  39. data/app/models/dune/admin/user_concern.rb +13 -0
  40. data/app/policies/dune/admin/admin_policy.rb +7 -0
  41. data/app/views/dune/admin/.gitkip +0 -0
  42. data/app/views/dune/admin/channels/_form.html.slim +98 -0
  43. data/app/views/dune/admin/channels/edit.html.slim +7 -0
  44. data/app/views/dune/admin/channels/index.html.slim +58 -0
  45. data/app/views/dune/admin/channels/members/index.html.slim +38 -0
  46. data/app/views/dune/admin/channels/members/new.html.slim +11 -0
  47. data/app/views/dune/admin/channels/new.html.slim +7 -0
  48. data/app/views/dune/admin/contacts/index.html.slim +32 -0
  49. data/app/views/dune/admin/contacts/show.html.slim +34 -0
  50. data/app/views/dune/admin/contributions/index.html.slim +138 -0
  51. data/app/views/dune/admin/dashboard/index.html.slim +65 -0
  52. data/app/views/dune/admin/financials/index.html.slim +88 -0
  53. data/app/views/dune/admin/layouts/_menu.html.slim +11 -0
  54. data/app/views/dune/admin/press_assets/_form.html.slim +11 -0
  55. data/app/views/dune/admin/press_assets/edit.html.slim +9 -0
  56. data/app/views/dune/admin/press_assets/index.html.slim +32 -0
  57. data/app/views/dune/admin/press_assets/new.html.slim +9 -0
  58. data/app/views/dune/admin/projects/index.html.slim +151 -0
  59. data/app/views/dune/admin/projects/populate_contribution.html.slim +48 -0
  60. data/app/views/dune/admin/tags/_form.html.slim +4 -0
  61. data/app/views/dune/admin/tags/edit.html.slim +7 -0
  62. data/app/views/dune/admin/tags/index.html.slim +44 -0
  63. data/app/views/dune/admin/tags/new.html.slim +7 -0
  64. data/app/views/dune/admin/users/index.html.slim +68 -0
  65. data/bin/rails +8 -0
  66. data/config/locales/en.yml +274 -0
  67. data/config/routes.rb +47 -0
  68. data/db/migrate/20141005184741_create_dune_admin_funding_raised_per_project_reports.rb +21 -0
  69. data/db/migrate/20141005191509_create_dune_admin_statistics.rb +55 -0
  70. data/dune-admin.gemspec +27 -0
  71. data/lib/dune/admin.rb +10 -0
  72. data/lib/dune/admin/engine.rb +13 -0
  73. data/lib/dune/admin/version.rb +5 -0
  74. data/spec/controllers/dune/admin/channels/members_controller_spec.rb +119 -0
  75. data/spec/controllers/dune/admin/channels_controller_spec.rb +161 -0
  76. data/spec/controllers/dune/admin/contacts_controller_spec.rb +23 -0
  77. data/spec/controllers/dune/admin/cotributions_controller_spec.rb +130 -0
  78. data/spec/controllers/dune/admin/dasboard_controller_spec.rb +18 -0
  79. data/spec/controllers/dune/admin/financials_controller_spec.rb +45 -0
  80. data/spec/controllers/dune/admin/press_assets_controller_spec.rb +138 -0
  81. data/spec/controllers/dune/admin/projects_controller_spec.rb +201 -0
  82. data/spec/controllers/dune/admin/tags_controller_spec.rb +137 -0
  83. data/spec/controllers/dune/admin/users_controller_spec.rb +30 -0
  84. data/spec/models/dune/admin/contribution_concern_spec.rb +19 -0
  85. data/spec/models/dune/admin/project_concern_spec.rb +56 -0
  86. data/spec/models/dune/admin/user_concern_spec.rb +65 -0
  87. data/spec/policies/dune/admin/admin_policy_spec.rb +22 -0
  88. data/spec/spec_helper.rb +40 -0
  89. metadata +237 -0
@@ -0,0 +1,9 @@
1
+ module Dune::Admin
2
+ class ContactsController < BaseController
3
+ actions :index, :show
4
+
5
+ def collection
6
+ @contacts ||= apply_scopes(end_of_association_chain).order('created_at desc').page(params[:page])
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,33 @@
1
+ module Dune::Admin
2
+ class ContributionsController < BaseController
3
+ has_scope :by_user_id, :by_key, :user_name_contains, :user_email_contains, :payer_email_contains, :project_name_contains, :confirmed, :with_state, :by_value
4
+ has_scope :credits, type: :boolean
5
+ has_scope :between_values, using: [ :start_at, :ends_at ], allow_blank: true
6
+
7
+ def self.contribution_actions
8
+ %w[confirm pendent refund hide cancel push_to_trash].each do |action|
9
+ define_method action do
10
+ resource.send(action)
11
+ flash.notice = I18n.t("dune.admin.contributions.messages.successful.#{action}")
12
+ redirect_to contributions_path(params[:local_params])
13
+ end
14
+ end
15
+ end
16
+ contribution_actions
17
+
18
+ def change_reward
19
+ resource.change_reward! params[:reward_id]
20
+ flash.notice = I18n.t('dune.admin.contributions.messages.successful.change_reward')
21
+ redirect_to contributions_path(params[:local_params])
22
+ end
23
+
24
+ protected
25
+ def collection
26
+ @contributions = apply_scopes(end_of_association_chain).without_state('deleted').order("contributions.created_at DESC").page(params[:page])
27
+ end
28
+
29
+ def permitted_params
30
+ params.permit({ contribution: Contribution.attribute_names.map(&:to_sym) })
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,8 @@
1
+ module Dune::Admin
2
+ class DashboardController < BaseController
3
+ inherit_resources
4
+ defaults resource_class: Statistics
5
+ actions :index
6
+ end
7
+ end
8
+
@@ -0,0 +1,33 @@
1
+ module Dune::Admin
2
+ class FinancialsController < BaseController
3
+ inherit_resources
4
+ defaults resource_class: Project, collection_name: 'projects', instance_name: 'project'
5
+
6
+ has_scope :by_permalink, :name_contains, :user_name_contains, :financial, :with_state, :by_progress
7
+ has_scope :between_expires_at, using: [ :start_at, :ends_at ], allow_blank: true
8
+
9
+ respond_to :html, :csv
10
+
11
+ actions :index
12
+
13
+ def index
14
+ respond_to do |format|
15
+ format.html { collection }
16
+ format.csv do
17
+ render csv: (collection.map do |resource|
18
+ ProjectFinancial.new(resource)
19
+ end)
20
+ end
21
+ end
22
+ end
23
+
24
+ protected
25
+ def projects
26
+ apply_scopes(Project).includes(:user).order("CASE state WHEN 'successful' THEN 1 WHEN 'waiting_funds' THEN 2 ELSE 3 END, (projects.expires_at)::date DESc")
27
+ end
28
+
29
+ def collection
30
+ @projects ||= projects.page(params[:page])
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,26 @@
1
+ module Dune::Admin
2
+ class PressAssetsController < BaseController
3
+ actions :all, except: [:show]
4
+
5
+ def create
6
+ create! { press_assets_path }
7
+ end
8
+
9
+ def update
10
+ update! { press_assets_path }
11
+ end
12
+
13
+ def destroy
14
+ destroy! { press_assets_path }
15
+ end
16
+
17
+ protected
18
+ def collection
19
+ @press_assets ||= apply_scopes(end_of_association_chain).page(params[:page])
20
+ end
21
+
22
+ def permitted_params
23
+ params.permit({ press_asset: PressAsset.attribute_names.map(&:to_sym) })
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,80 @@
1
+ module Dune::Admin
2
+ class ProjectsController < BaseController
3
+ defaults finder: :find_by_permalink!
4
+
5
+ has_scope :by_user_email, :by_id, :pg_search, :user_name_contains, :with_state, :by_category_id, :order_by
6
+ has_scope :between_created_at, :between_expires_at, :between_online_date, :between_updated_at, :goal_between, using: [ :start_at, :ends_at ]
7
+
8
+ before_filter do
9
+ @total_projects = Project.count
10
+ end
11
+
12
+ [:launch, :reject, :push_to_draft, :approve].each do |name|
13
+ define_method name do
14
+ @project = Project.find_by_permalink params[:id]
15
+ @project.send("#{name.to_s}!")
16
+ redirect_to :back
17
+ end
18
+ end
19
+
20
+ def populate
21
+ if params[:user][:id].present?
22
+ @user = User.find(params[:user][:id])
23
+ else
24
+ @user = create_user
25
+ end
26
+
27
+ @contribution = build_contribution(@user)
28
+
29
+ if @user.valid? and @contribution.valid?
30
+ @user.save!
31
+ @contribution.save!
32
+ redirect_to populate_contribution_project_path(resource), flash: { success: 'Success!' }
33
+ else
34
+ flash.alert = (@user.errors.full_messages +
35
+ @contribution.errors.full_messages).to_sentence
36
+ render :populate_contribution
37
+ end
38
+ end
39
+
40
+ def destroy
41
+ resource.push_to_trash! if resource.can_push_to_trash?
42
+ redirect_to projects_path
43
+ end
44
+
45
+ protected
46
+ def collection
47
+ @projects = apply_scopes(end_of_association_chain).order('projects.created_at desc').without_state('deleted').page(params[:page])
48
+ end
49
+
50
+ def create_user
51
+ password = Devise.friendly_token
52
+ user = User.new(user_params[:user])
53
+ user.email = "#{Devise.friendly_token}@populate.user"
54
+ user.password = password
55
+ user.password_confirmation = password
56
+ user.profile_type = user_params[:user][:profile_type]
57
+ user
58
+ end
59
+
60
+ def build_contribution(user)
61
+ contribution = resource.contributions.new(contribution_params[:contribution])
62
+ contribution.payment_method = 'PrePopulate'
63
+ contribution.state = 'confirmed'
64
+ contribution.user = user
65
+ contribution
66
+ end
67
+
68
+ def user_params
69
+ params.permit({ user: User.attribute_names.map(&:to_sym) })
70
+ end
71
+
72
+ def contribution_params
73
+ params.permit({ contribution: Contribution.attribute_names.map(&:to_sym) })
74
+ end
75
+
76
+ def permitted_params
77
+ params.permit({ project: Project.attribute_names.map(&:to_sym) })
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,8 @@
1
+ module Dune::Admin
2
+ class Reports::BaseController < BaseController
3
+ inherit_resources
4
+ responders :csv
5
+ respond_to :csv
6
+ actions :index
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Dune::Admin
2
+ class Reports::ContributionReportsController < Reports::BaseController
3
+ def index
4
+ project = Project.find(params[:project_id])
5
+ render csv: ContributionReport.per_project(project)
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,4 @@
1
+ module Dune::Admin
2
+ class Reports::FundingRaisedPerProjectReportsController < Reports::BaseController
3
+ end
4
+ end
@@ -0,0 +1,5 @@
1
+ module Dune::Admin
2
+ class Reports::StatisticsController < Reports::BaseController
3
+ defaults resource_class: Statistics
4
+ end
5
+ end
@@ -0,0 +1,35 @@
1
+ module Dune::Admin
2
+ class TagsController < BaseController
3
+ actions :all, except: [:show]
4
+ has_scope :popular, type: :boolean
5
+
6
+ def create
7
+ create! { tags_path }
8
+ end
9
+
10
+ def update
11
+ update! do |format|
12
+ if resource.errors.empty?
13
+ format.html { redirect_to tags_path }
14
+ format.json { respond_with_bip(resource) }
15
+ else
16
+ format.html { render action: 'edit' }
17
+ format.json { respond_with_bip(resource) }
18
+ end
19
+ end
20
+ end
21
+
22
+ def destroy
23
+ destroy! { tags_path }
24
+ end
25
+
26
+ protected
27
+ def collection
28
+ @tags ||= apply_scopes(end_of_association_chain).order('created_at desc').page(params[:page])
29
+ end
30
+
31
+ def permitted_params
32
+ params.permit({ tag: Tag.attribute_names.map(&:to_sym) })
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,27 @@
1
+ module Dune::Admin
2
+ class UsersController < BaseController
3
+ inherit_resources
4
+ before_filter :set_title
5
+ before_filter :set_totals
6
+
7
+ has_scope :by_id, :by_name, :by_email, :by_key, :has_credits, :has_credits_difference, only: :index
8
+
9
+ protected
10
+ def set_totals
11
+ totals = end_of_association_chain.contribution_totals
12
+ @total_users = totals[:users].to_i
13
+ @total_contributions = totals[:contributions]
14
+ @total_contributed = totals[:contributed]
15
+ @total_credits = totals[:credits]
16
+ end
17
+
18
+ def set_title
19
+ @title = t("admin.users.index.title")
20
+ end
21
+
22
+ def collection
23
+ @users ||= apply_scopes(end_of_association_chain).order_by(params[:order_by] || 'created_at DESC').includes(:user_total).page(params[:page])
24
+ end
25
+ end
26
+ end
27
+
File without changes
@@ -0,0 +1,23 @@
1
+ module Dune::Admin::ContributionConcern
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ scope :by_id, ->(id) { where(id: id) }
6
+ scope :by_key, ->(key) { where(key: key) }
7
+ scope :by_user_id, ->(user_id) { where(user_id: user_id) }
8
+ scope :user_name_contains, ->(term) { joins(:user).where("unaccent(upper(users.name)) LIKE ('%'||unaccent(upper(?))||'%')", term) }
9
+ scope :user_email_contains, ->(term) { joins(:user).where("unaccent(upper(users.email)) LIKE ('%'||unaccent(upper(?))||'%')", term) }
10
+ scope :payer_email_contains, ->(term) { where("unaccent(upper(payer_email)) LIKE ('%'||unaccent(upper(?))||'%')", term) }
11
+ scope :project_name_contains, ->(term) { joins(:project).where("unaccent(upper(projects.name)) LIKE ('%'||unaccent(upper(?))||'%')", term) }
12
+
13
+ def self.between_values(start_at, ends_at)
14
+ return all unless start_at.present? && ends_at.present?
15
+ where("value between ? and ?", start_at, ends_at)
16
+ end
17
+
18
+ def change_reward!(reward)
19
+ self.reward_id = reward
20
+ self.save
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,5 @@
1
+ module Dune::Admin
2
+ class FundingRaisedPerProjectReport < ActiveRecord::Base
3
+ acts_as_copy_target
4
+ end
5
+ end
@@ -0,0 +1,41 @@
1
+ module Dune::Admin::ProjectConcern
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ scope :by_progress, ->(progress) do
6
+ projects = select { |project|
7
+ project.project_total.pledged >= project.goal * (progress / 100.0)
8
+ }
9
+ where(id: projects)
10
+ end
11
+
12
+ scope :by_user_email, ->(email) do
13
+ joins('JOIN users as u ON u.id = projects.user_id').
14
+ where("u.email = ?", email)
15
+ end
16
+
17
+ scope :by_category_id, ->(id) do
18
+ where(category_id: id)
19
+ end
20
+
21
+ scope :name_contains, ->(term) do
22
+ where("unaccent(upper(name)) LIKE ('%'||unaccent(upper(?))||'%')", term)
23
+ end
24
+
25
+ scope :goal_between, ->(starts_at, ends_at) do
26
+ where("goal BETWEEN ? AND ?", starts_at, ends_at)
27
+ end
28
+
29
+ [:between_created_at, :between_expires_at, :between_online_date, :between_updated_at].each do |name|
30
+ define_singleton_method name do |starts_at, ends_at|
31
+ between_dates name.to_s.gsub('between_',''), starts_at, ends_at
32
+ end
33
+ end
34
+
35
+ private
36
+ def self.between_dates(attribute, starts_at, ends_at)
37
+ return all unless starts_at.present? && ends_at.present?
38
+ where("projects.#{attribute}::date between to_date(?, 'dd/mm/yyyy') and to_date(?, 'dd/mm/yyyy')", starts_at, ends_at)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,5 @@
1
+ module Dune::Admin
2
+ class Statistics < ActiveRecord::Base
3
+ acts_as_copy_target
4
+ end
5
+ end
@@ -0,0 +1,13 @@
1
+ module Dune::Admin::UserConcern
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ scope :by_email, ->(email){ where('email ~* ?', email) }
6
+ scope :by_name, ->(name){ where('users.name ~* ?', name) }
7
+ scope :by_id, ->(id){ where(id: id) }
8
+ scope :by_key, ->(key){ where('EXISTS(SELECT true FROM contributions WHERE contributions.user_id = users.id AND contributions.key ~* ?)', key) }
9
+ scope :has_credits, -> { joins(:user_total).where('user_totals.credits > 0') }
10
+ scope :order_by, ->(sort_field){ order(sort_field) }
11
+ end
12
+ end
13
+
@@ -0,0 +1,7 @@
1
+ module Dune::Admin
2
+ class AdminPolicy < ::ApplicationPolicy
3
+ def access?
4
+ is_admin?
5
+ end
6
+ end
7
+ end
File without changes
@@ -0,0 +1,98 @@
1
+ = simple_form_for resource, url: (resource.persisted? ? channel_path(resource) : channels_path) do |form|
2
+ - resource.build_user unless resource.user.present?
3
+
4
+ - unless resource.persisted?
5
+ .row
6
+ .large-6.columns.existing-user
7
+ .row
8
+ .large-12.columns
9
+ h5 = t('.associate_existing_user')
10
+ = form.input :user_id, as: :integer, required: false
11
+
12
+ .large-6.columns.new-user
13
+ = form.fields_for :user do |uf|
14
+ .row
15
+ .large-12.columns
16
+ h5 = t('.create_new_channel_user')
17
+ = uf.input :email, as: :string, required: false
18
+ .large-12.columns
19
+ = uf.input :password, as: :password
20
+
21
+
22
+ .row
23
+ .large-10.columns
24
+ = form.input :permalink, as: :string
25
+ .large-2.columns
26
+ br/
27
+ = form.input :accepts_projects
28
+ = form.input :name, as: :string
29
+ .row
30
+ .large-9.columns
31
+ = form.input :description, as: :text
32
+ .large-3.columns
33
+ = form.input :image, as: :file
34
+ - if resource.image.present?
35
+ p= image_tag(resource.image.thumb.url)
36
+ .row
37
+ - if resource.persisted?
38
+ .large-6.small-6.columns
39
+ = form.fields_for :user do |uf|
40
+ = uf.input :email, as: :string
41
+ .large-6.small-6.columns
42
+ = form.input :video_url, as: :string
43
+ .row
44
+ .large-4.columns
45
+ .row.collapse
46
+ .small-3.large-2.columns
47
+ span class="prefix"
48
+ i.icon-et-facebook
49
+ .small-9.large-10.columns
50
+ = form.fields_for :user do |uf|
51
+ = uf.input :facebook_url, input_html: { class: "with-prefix" }, label: false, as: :string
52
+ .large-4.columns
53
+ .row.collapse
54
+ .small-3.large-2.columns
55
+ span class="prefix"
56
+ i.icon-et-twitter
57
+ .small-9.large-10.columns
58
+ = form.fields_for :user do |uf|
59
+ = uf.input :twitter_url, input_html: { class: "with-prefix" }, label: false, as: :string
60
+ .large-4.columns
61
+ .row.collapse
62
+ .small-3.large-2.columns
63
+ span class="prefix"
64
+ i.icon-et-globe
65
+ .small-9.large-10.columns
66
+ = form.fields_for :user do |uf|
67
+ = uf.input :other_url, input_html: { class: "with-prefix" }, label: false, as: :string
68
+
69
+ = form.input :submit_your_project_text, as: :text, input_html: {rows: 20, class: 'small markdown-editor'}
70
+ = form.input :how_it_works, as: :text, input_html: {rows: 20, class: 'markdown-editor'}
71
+
72
+ fieldset
73
+ h3 = t('.start_content')
74
+ = form.simple_fields_for :start_content, OpenStruct.new(resource.start_content) do |fs|
75
+ = form.input :start_hero_image, as: :file
76
+ = fs.input :title
77
+ = fs.input :subtitle
78
+
79
+ - for step in [:first, :second, :third]
80
+ .row
81
+ .large-4.columns
82
+ = fs.input "#{step}_step_icon"
83
+ .large-4.columns
84
+ = fs.input "#{step}_step_title"
85
+ .large-4.columns
86
+ = fs.input "#{step}_step_description"
87
+
88
+ = fs.input :start_primary_content, as: :text, input_html: {rows: 20, class: 'markdown-editor'}
89
+ = fs.input :start_secondary_content, as: :text, input_html: {rows: 20, class: 'markdown-editor'}
90
+
91
+ fieldset
92
+ h3 = t('.success_content')
93
+ = form.simple_fields_for :success_content, OpenStruct.new(resource.success_content) do |fs|
94
+ = fs.input :main_text, as: :text, input_html: {rows: 20, class: 'markdown-editor'}
95
+ = fs.input :button_text
96
+ = fs.input :button_link
97
+
98
+ = form.button :submit, class: 'button', data: { disable_with: t('words.sending') }