gamification 0.0.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/gamification/application_controller.rb +1 -1
  3. data/app/controllers/gamification/rewards_controller.rb +46 -0
  4. data/app/helpers/gamification/application_helper.rb +24 -0
  5. data/app/helpers/gamification/rewards_helper.rb +20 -0
  6. data/app/models/gamification/goal.rb +5 -0
  7. data/app/models/gamification/medal.rb +5 -0
  8. data/app/models/gamification/reward.rb +5 -0
  9. data/app/uploaders/gamification/image_uploader.rb +47 -0
  10. data/app/views/gamification/rewards/_presentation.html.erb +7 -0
  11. data/app/views/gamification/rewards/_reward.html.erb +9 -0
  12. data/app/views/gamification/scorings/create.html.erb +2 -0
  13. data/config/initializers/routing.rb +15 -0
  14. data/config/locales/en.yml +3 -0
  15. data/config/locales/nb.yml +35 -0
  16. data/config/routes.rb +1 -0
  17. data/db/migrate/20140310081749_rename_everything.rb +10 -0
  18. data/db/migrate/20140313134259_create_gamification_medals.rb +11 -0
  19. data/db/migrate/20140314132611_add_description_to_gamification_medals.rb +5 -0
  20. data/db/migrate/20140315142524_rename_gamification_tasks_to_goals.rb +7 -0
  21. data/db/migrate/20140318220723_add_seen_at_to_gamification_rewards.rb +9 -0
  22. data/lib/gamification.rb +1 -0
  23. data/lib/gamification/activerecord.rb +13 -0
  24. data/lib/gamification/concerns.rb +2 -0
  25. data/lib/gamification/concerns/models.rb +3 -2
  26. data/lib/gamification/concerns/models/goal.rb +44 -0
  27. data/lib/gamification/concerns/models/medal.rb +13 -0
  28. data/lib/gamification/concerns/models/reward.rb +33 -0
  29. data/lib/gamification/concerns/rewardable.rb +12 -0
  30. data/lib/gamification/concerns/rewarding.rb +7 -0
  31. data/lib/gamification/engine.rb +10 -0
  32. data/lib/gamification/version.rb +1 -1
  33. data/spec/controllers/gamification/rewards_controller_spec.rb +57 -0
  34. data/spec/dummy/app/assets/javascripts/articles.js +2 -0
  35. data/spec/dummy/app/assets/stylesheets/articles.css +4 -0
  36. data/spec/dummy/app/controllers/articles_controller.rb +5 -0
  37. data/spec/dummy/app/helpers/articles_helper.rb +2 -0
  38. data/spec/dummy/app/models/article.rb +2 -2
  39. data/spec/dummy/app/models/user.rb +2 -2
  40. data/spec/dummy/app/views/articles/show.html.erb +1 -0
  41. data/spec/dummy/config/routes.rb +1 -0
  42. data/spec/dummy/db/development.sqlite3 +0 -0
  43. data/spec/dummy/db/schema.rb +25 -12
  44. data/spec/dummy/db/test.sqlite3 +0 -0
  45. data/spec/dummy/log/development.log +3893 -1707
  46. data/spec/dummy/log/test.log +22080 -2888
  47. data/spec/dummy/spec/controllers/articles_controller_spec.rb +15 -0
  48. data/spec/dummy/spec/helpers/articles_helper_spec.rb +14 -0
  49. data/spec/dummy/spec/models/article_spec.rb +0 -1
  50. data/spec/dummy/spec/models/user_spec.rb +0 -1
  51. data/spec/dummy/spec/views/articles/show.html.erb_spec.rb +4 -0
  52. data/spec/factories/gamification_goals.rb +14 -0
  53. data/spec/factories/gamification_medals.rb +10 -0
  54. data/spec/factories/gamification_rewards.rb +8 -0
  55. data/spec/helpers/gamification/application_helper_spec.rb +14 -0
  56. data/spec/helpers/gamification/rewards_helper_spec.rb +18 -0
  57. data/spec/lib/gamification/concerns/rewardable_spec.rb +17 -0
  58. data/spec/models/gamification/goal_spec.rb +65 -0
  59. data/spec/models/gamification/medal_spec.rb +6 -0
  60. data/spec/models/gamification/reward_spec.rb +102 -0
  61. data/spec/spec_helper.rb +2 -0
  62. data/spec/views/gamification/rewards/_presentation.html.erb_spec.rb +23 -0
  63. metadata +173 -28
  64. data/MIT-LICENSE +0 -20
  65. data/app/models/gamification/scoring.rb +0 -5
  66. data/app/models/gamification/task.rb +0 -5
  67. data/app/views/layouts/gamification/application.html.erb +0 -14
  68. data/lib/gamification/concerns/models/scoring.rb +0 -8
  69. data/lib/gamification/concerns/models/task.rb +0 -50
  70. data/spec/factories/gamification_scorings.rb +0 -8
  71. data/spec/factories/gamification_tasks.rb +0 -8
  72. data/spec/models/gamification/scoring_spec.rb +0 -7
  73. data/spec/models/gamification/task_spec.rb +0 -77
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ff0f5c1e1337b6cf63206c829cc642f095b94621
4
- data.tar.gz: c264313d9ed05c33287888e0e9e81ebc99ba4f58
3
+ metadata.gz: e19cbb64dd5e16388ffd8fd52c48622bc621569b
4
+ data.tar.gz: 07ebce2bd2b9751f6e21cd0dc6c5e59c5da9d33b
5
5
  SHA512:
6
- metadata.gz: fb23fabcb4db26e71e7001fb6f2c0e65c8fe2ebd2df47f0acf7b02c624a7b2ea9b3df665672094d1dc8e6b43e733fbd61221e13b07265dff1730d75a2313b6e3
7
- data.tar.gz: a344fdd6a6534e4065eaf6794d8e520bbf8ff9db4fd6e757f27a2834eb254928ac5b4b91b16f6516cd4798d6370f10870843575e2c668c0bebf60b62c07c160f
6
+ metadata.gz: 883c53868ccb30f0eced71df269ca966cd27d19f05e30cae810cd6458eb577ed35e0c9858992e21d4ab2f992e37991ab50979835bfccb1a66dcdbbf32021f65a
7
+ data.tar.gz: 1a34ab955a1a55eae840c0f2d5546f81cc2a7ee8605970b456642b73a6fcf309386c4322d493e49d4a40844ca117e9064ffaa8772de50817fae183b93159a97f
@@ -1,4 +1,4 @@
1
1
  module Gamification
2
- class ApplicationController < ActionController::Base
2
+ class ApplicationController < ::ApplicationController
3
3
  end
4
4
  end
@@ -0,0 +1,46 @@
1
+ require_dependency "gamification/application_controller"
2
+
3
+ module Gamification
4
+ class RewardsController < ApplicationController
5
+ def create
6
+ if rewarding.is_a? ::Gamification::Goal
7
+ rewarding.complete_for rewardable
8
+ else
9
+ rewarding.goals.each do |goal|
10
+ goal.complete_for rewardable
11
+ end
12
+ end
13
+
14
+ respond_to do |format|
15
+ format.json { render json: {}, status: :created }
16
+ format.html { redirect_to redirect_url }
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def redirect_url
23
+ params[:redirect_url] || request.env['HTTP_REFERER']
24
+ end
25
+
26
+ def rewarding
27
+ rewarding_model.find reward_params[:rewarding_id]
28
+ end
29
+
30
+ def rewardable
31
+ rewardable_model.find reward_params[:rewardable_id]
32
+ end
33
+
34
+ def rewarding_model
35
+ reward_params[:rewarding_type].constantize
36
+ end
37
+
38
+ def rewardable_model
39
+ reward_params[:rewardable_type].constantize
40
+ end
41
+
42
+ def reward_params
43
+ params.require(:reward).permit(:rewarding_type, :rewarding_id, :rewardable_type, :rewardable_id)
44
+ end
45
+ end
46
+ end
@@ -1,4 +1,28 @@
1
1
  module Gamification
2
2
  module ApplicationHelper
3
+
4
+ # Create a form to reward someone for something.
5
+ #
6
+ # rewardable - A model that is rewardable (e.g. a user)
7
+ # options - A Hash of options:
8
+ # :for - A model that is rewarding (e.g. an article)
9
+ # :redirect - A String describing a URL to redirect to.
10
+ def reward rewardable, options
11
+ rewarding = options[:for]
12
+ redirect = options[:redirect]
13
+
14
+ form_tag Gamification::Engine.routes.url_helpers.rewards_path, method: :post do
15
+ concat hidden_field_tag 'reward[rewarding_type]', rewarding.class.name
16
+ concat hidden_field_tag 'reward[rewarding_id]', rewarding.id
17
+ concat hidden_field_tag 'reward[rewardable_type]', rewardable.class.name
18
+ concat hidden_field_tag 'reward[rewardable_id]', rewardable.id
19
+
20
+ if redirect
21
+ concat hidden_field_tag 'redirect_url', redirect
22
+ end
23
+
24
+ concat submit_tag I18n.t 'gamification.complete'
25
+ end
26
+ end
3
27
  end
4
28
  end
@@ -0,0 +1,20 @@
1
+ module Gamification
2
+ module RewardsHelper
3
+
4
+ # Present unseen rewards for the given user.
5
+ #
6
+ # options - A Hash of options:
7
+ # for: A rewardable model.
8
+ #
9
+ # Returns HTML.
10
+ def present_rewards options
11
+ rewardable = options[:for]
12
+ rewards = rewardable.rewards.unseen
13
+ presentation = render partial: 'gamification/rewards/presentation', locals: { rewards: rewards }
14
+
15
+ rewards.see
16
+
17
+ presentation
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,5 @@
1
+ module Gamification
2
+ class Goal < ::ActiveRecord::Base
3
+ include Concerns::Models::Goal
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Gamification
2
+ class Medal < ::ActiveRecord::Base
3
+ include Concerns::Models::Medal
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Gamification
2
+ class Reward < ::ActiveRecord::Base
3
+ include Concerns::Models::Reward
4
+ end
5
+ end
@@ -0,0 +1,47 @@
1
+ # encoding: utf-8
2
+ require 'carrierwave'
3
+
4
+ class Gamification::ImageUploader < CarrierWave::Uploader::Base
5
+
6
+ # Include MiniMagick support
7
+ include CarrierWave::MiniMagick
8
+
9
+ # Override the directory where uploaded files will be stored.
10
+ # This is a sensible default for uploaders that are meant to be mounted:
11
+ def store_dir
12
+ "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
13
+ end
14
+
15
+ # Provide a default URL as a default if there hasn't been a file uploaded:
16
+ # def default_url
17
+ # # For Rails 3.1+ asset pipeline compatibility:
18
+ # # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_'))
19
+ #
20
+ # "/images/fallback/" + [version_name, "default.png"].compact.join('_')
21
+ # end
22
+
23
+ # Process files as they are uploaded:
24
+ # process :scale => [200, 300]
25
+ #
26
+ # def scale(width, height)
27
+ # # do something
28
+ # end
29
+
30
+ # Create different versions of your uploaded files:
31
+ version :small do
32
+ process :resize_to_fit => [150, 150]
33
+ end
34
+
35
+ # Add a white list of extensions which are allowed to be uploaded.
36
+ # For images you might use something like this:
37
+ # def extension_white_list
38
+ # %w(jpg jpeg gif png)
39
+ # end
40
+
41
+ # Override the filename of the uploaded files:
42
+ # Avoid using model.id or version_name here, see uploader/store.rb for details.
43
+ # def filename
44
+ # "something.jpg" if original_filename
45
+ # end
46
+
47
+ end
@@ -0,0 +1,7 @@
1
+ <% if rewards.any? %>
2
+ <div class="reward-presentation">
3
+ <% rewards.each do |reward| %>
4
+ <%= render reward %>
5
+ <% end %>
6
+ </div>
7
+ <% end %>
@@ -0,0 +1,9 @@
1
+ <% if reward.medal %>
2
+ <div class="medal">
3
+ <div class="image"><%= image_tag reward.medal.image %></div>
4
+ <div class="name"><%= reward.medal.name %></div>
5
+ <div class="description"><%= reward.medal.description %></div>
6
+ </div>
7
+ <% end %>
8
+
9
+ <div class="points"><%= reward.points %></div>
@@ -0,0 +1,2 @@
1
+ <h1>Scorings#create</h1>
2
+ <p>Find me in app/views/gamification/scorings/create.html.erb</p>
@@ -0,0 +1,15 @@
1
+ module Gamification
2
+ module ApplicationHelper
3
+
4
+ # Knowledge base uses the layout of the client application, which causes Rails' url helpers to get confused
5
+ # and require you to prepend 'main_app' to your own routes. This hack allows developers to keep referring to
6
+ # routes without a prefix by sending undefined routes to 'main_app' before failing.
7
+ def method_missing(method, *args, &block)
8
+ if (method.to_s.end_with?('_path') || method.to_s.end_with?('_url')) && main_app.respond_to?(method)
9
+ main_app.send(method, *args)
10
+ else
11
+ super
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ en:
2
+ gamification:
3
+ complete: 'Complete goals'
@@ -0,0 +1,35 @@
1
+ nb:
2
+ activerecord:
3
+ models:
4
+ gamification/goal:
5
+ one: Mål
6
+ other: Mål
7
+ gamification/reward:
8
+ one: Belønning
9
+ other: Belønninger
10
+ gamification/medal:
11
+ one: Medalje
12
+ other: Medaljer
13
+ attributes:
14
+ common: &common
15
+ created_at: Opprettet
16
+ updated_at: Sist oppdatert
17
+ gamification/goal:
18
+ <<: *common
19
+ rewarding: Mål for
20
+ rewarding_id: Mål for
21
+ rewarding_type: Mål for
22
+ points: Poeng
23
+ gamification/reward:
24
+ <<: *common
25
+ goal: Mål
26
+ rewardable: Mottaker
27
+ rewardable_id: Motakker
28
+ rewardable_type: Mottaker
29
+ seen_at: Sett
30
+ gamification/medal:
31
+ <<: *common
32
+ goal: Mål
33
+ name: Navn
34
+ image: Bilde
35
+ description: Beskrivelse
data/config/routes.rb CHANGED
@@ -1,2 +1,3 @@
1
1
  Gamification::Engine.routes.draw do
2
+ resources :rewards, only: [:create]
2
3
  end
@@ -0,0 +1,10 @@
1
+ class RenameEverything < ActiveRecord::Migration
2
+ def change
3
+ rename_table :gamification_scorings, :gamification_rewards
4
+ rename_column :gamification_rewards, :subjectable_id, :rewardable_id
5
+ rename_column :gamification_rewards, :subjectable_type, :rewardable_type
6
+
7
+ rename_column :gamification_tasks, :taskable_id, :rewarding_id
8
+ rename_column :gamification_tasks, :taskable_type, :rewarding_type
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ class CreateGamificationMedals < ActiveRecord::Migration
2
+ def change
3
+ create_table :gamification_medals do |t|
4
+ t.references :task, index: true
5
+ t.string :name
6
+ t.string :image
7
+
8
+ t.timestamps
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ class AddDescriptionToGamificationMedals < ActiveRecord::Migration
2
+ def change
3
+ add_column :gamification_medals, :description, :text
4
+ end
5
+ end
@@ -0,0 +1,7 @@
1
+ class RenameGamificationTasksToGoals < ActiveRecord::Migration
2
+ def change
3
+ rename_table :gamification_tasks, :gamification_goals
4
+ rename_column :gamification_rewards, :task_id, :goal_id
5
+ rename_column :gamification_medals, :task_id, :goal_id
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ class AddSeenAtToGamificationRewards < ActiveRecord::Migration
2
+ def change
3
+ change_table :gamification_rewards do |t|
4
+ t.datetime :seen_at
5
+ end
6
+
7
+ add_index :gamification_rewards, :seen_at, name: 'index_gamification_rewards_on_seen_at'
8
+ end
9
+ end
data/lib/gamification.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require "gamification/engine"
2
2
  require "gamification/concerns"
3
+ require "gamification/activerecord"
3
4
 
4
5
  module Gamification
5
6
  end
@@ -0,0 +1,13 @@
1
+ module Gamification::ActiveRecord
2
+ module Extensions
3
+ def rewarding
4
+ include Gamification::Concerns::Rewarding
5
+ end
6
+
7
+ def rewardable
8
+ include Gamification::Concerns::Rewardable
9
+ end
10
+ end
11
+ end
12
+
13
+ ::ActiveRecord::Base.send :extend, Gamification::ActiveRecord::Extensions if defined?(ActiveRecord)
@@ -1,3 +1,5 @@
1
1
  module Gamification::Concerns
2
2
  require "gamification/concerns/models"
3
+ require "gamification/concerns/rewarding"
4
+ require "gamification/concerns/rewardable"
3
5
  end
@@ -1,4 +1,5 @@
1
1
  module Gamification::Concerns::Models
2
- require "gamification/concerns/models/task"
3
- require "gamification/concerns/models/scoring"
2
+ require "gamification/concerns/models/goal"
3
+ require "gamification/concerns/models/reward"
4
+ require "gamification/concerns/models/medal"
4
5
  end
@@ -0,0 +1,44 @@
1
+ module Gamification::Concerns::Models::Goal
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ belongs_to :rewarding, polymorphic: true
6
+ has_one :medal, dependent: :destroy
7
+ has_many :rewards, dependent: :destroy
8
+
9
+ accepts_nested_attributes_for :medal, allow_destroy: true, reject_if: :all_blank
10
+
11
+ # TODO: These should be SQL. But that's hard.
12
+ scope :completed_by, ->(subject) { all.select { |goal| goal.completed_by? subject }}
13
+ scope :incomplete_by, ->(subject) { all.reject { |goal| goal.completed_by? subject }}
14
+
15
+ # Determine whether the given subject has completed the goal.
16
+ #
17
+ # subject - An ActiveRecord model that can receive rewards.
18
+ def completed_by? subject
19
+ !!reward_for(subject)
20
+ end
21
+
22
+ # Complete the goal for the given subject.
23
+ #
24
+ # subject - An ActiveRecord model that can receive rewards.
25
+ def complete_for subject
26
+ if completed_by? subject
27
+ raise Completed, "#{self} is already completed for #{subject}"
28
+ else
29
+ ::Gamification::Reward.create! goal: self, rewardable: subject
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ # Find the Reward for the given subject.
36
+ #
37
+ # subject - A rewardable model.
38
+ def reward_for rewardable
39
+ rewards.find_by rewardable: rewardable
40
+ end
41
+
42
+ class Completed < StandardError; end
43
+ end
44
+ end
@@ -0,0 +1,13 @@
1
+ require 'carrierwave'
2
+
3
+ module Gamification
4
+ module Concerns::Models::Medal
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ belongs_to :goal
9
+
10
+ mount_uploader :image, ::Gamification::ImageUploader
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,33 @@
1
+ module Gamification::Concerns::Models::Reward
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ belongs_to :goal, class_name: 'Gamification::Goal'
6
+ belongs_to :rewardable, polymorphic: true, inverse_of: :rewards
7
+
8
+ scope :unseen, -> { where seen_at: nil }
9
+ scope :seen, -> { where.not seen_at: nil }
10
+
11
+ scope :with_medals, -> { all.select &:medal }
12
+ scope :without_medals, -> { all.reject &:medal }
13
+
14
+ validates :rewardable_id, uniqueness: { scope: [:rewardable_type, :goal] }
15
+
16
+ delegate :points, to: :goal
17
+ delegate :medal, to: :goal
18
+
19
+ def see
20
+ touch :seen_at
21
+ end
22
+
23
+ def seen?
24
+ !!seen_at
25
+ end
26
+
27
+ class << self
28
+ def see
29
+ all.map { |reward| reward.see }
30
+ end
31
+ end
32
+ end
33
+ end