diff options
| -rw-r--r-- | users/app/controllers/v1/messages_controller.rb | 28 | ||||
| -rw-r--r-- | users/app/designs/message/by_user_ids_to_show.js | 7 | ||||
| -rw-r--r-- | users/app/designs/message/by_user_ids_to_show_and_created_at.js | 9 | ||||
| -rw-r--r-- | users/app/designs/user/by_created_at_and_one_month_warning_not_sent.js | 5 | ||||
| -rw-r--r-- | users/app/models/message.rb | 16 | ||||
| -rw-r--r-- | users/app/models/user.rb | 36 | ||||
| -rw-r--r-- | users/config/locales/en.yml | 1 | ||||
| -rw-r--r-- | users/config/routes.rb | 1 | ||||
| -rw-r--r-- | users/lib/tasks/leap_web_users_tasks.rake | 6 | ||||
| -rw-r--r-- | users/test/functional/v1/messages_controller_test.rb | 57 | 
10 files changed, 166 insertions, 0 deletions
| diff --git a/users/app/controllers/v1/messages_controller.rb b/users/app/controllers/v1/messages_controller.rb new file mode 100644 index 0000000..1b994ca --- /dev/null +++ b/users/app/controllers/v1/messages_controller.rb @@ -0,0 +1,28 @@ +module V1 +  class MessagesController < ApplicationController + +    skip_before_filter :verify_authenticity_token +    before_filter :authorize + +    respond_to :json + +    def index +      render json: (current_user ? current_user.messages : [] ) +    end + +    def update +      message = Message.find(params[:id]) +      if (message and current_user) +        message.user_ids_to_show.delete(current_user.id) +        # is it necessary to keep track of what users have already seen it? +        message.user_ids_have_shown << current_user.id if !message.user_ids_have_shown.include?(current_user.id) +        # TODO: is it quicker to call uniq! after adding rather than check if it is already included? +        message.save +        render json: true +      else +        render json: false +      end +    end + +  end +end diff --git a/users/app/designs/message/by_user_ids_to_show.js b/users/app/designs/message/by_user_ids_to_show.js new file mode 100644 index 0000000..95ccd0d --- /dev/null +++ b/users/app/designs/message/by_user_ids_to_show.js @@ -0,0 +1,7 @@ +function (doc) { +  if (doc.type === 'Message' && doc.user_ids_to_show && Array.isArray(doc.user_ids_to_show)) { +    doc.user_ids_to_show.forEach(function (userIdsToShow) { +      emit(userIdsToShow, 1); +    }); +  } +}
\ No newline at end of file diff --git a/users/app/designs/message/by_user_ids_to_show_and_created_at.js b/users/app/designs/message/by_user_ids_to_show_and_created_at.js new file mode 100644 index 0000000..18969b8 --- /dev/null +++ b/users/app/designs/message/by_user_ids_to_show_and_created_at.js @@ -0,0 +1,9 @@ +// not using at moment +// call with something like Message.by_user_ids_to_show_and_created_at.startkey([user_id, start_date]).endkey([user_id,end_date]) +function (doc) { +  if (doc.type === 'Message' && doc.user_ids_to_show && Array.isArray(doc.user_ids_to_show)) { +    doc.user_ids_to_show.forEach(function (userIdsToShow) { +      emit([userIdsToShow, doc.created_at], 1); +    }); +  } +}
\ No newline at end of file diff --git a/users/app/designs/user/by_created_at_and_one_month_warning_not_sent.js b/users/app/designs/user/by_created_at_and_one_month_warning_not_sent.js new file mode 100644 index 0000000..53a95de --- /dev/null +++ b/users/app/designs/user/by_created_at_and_one_month_warning_not_sent.js @@ -0,0 +1,5 @@ +function (doc) { +  if ((doc['type'] == 'User') && (doc['created_at'] != null) && (doc['one_month_warning_sent'] == null)) { +    emit(doc['created_at'], 1); +  }     +} diff --git a/users/app/models/message.rb b/users/app/models/message.rb new file mode 100644 index 0000000..d9ccee8 --- /dev/null +++ b/users/app/models/message.rb @@ -0,0 +1,16 @@ +class Message < CouchRest::Model::Base + +  use_database :messages + +  property :text, String +  property :user_ids_to_show, [String] +  property :user_ids_have_shown, [String] # is this necessary to store? + +  timestamps! + +  design do +    own_path = Pathname.new(File.dirname(__FILE__)) +    load_views(own_path.join('..', 'designs', 'message')) +  end + +end diff --git a/users/app/models/user.rb b/users/app/models/user.rb index 720f5a9..c297ac8 100644 --- a/users/app/models/user.rb +++ b/users/app/models/user.rb @@ -13,6 +13,8 @@ class User < CouchRest::Model::Base    property :desired_service_level_code, Integer, :accessible => true    property :effective_service_level_code, Integer, :accessible => true +  property :one_month_warning_sent, TrueClass +    before_save :update_effective_service_level    validates :login, :password_salt, :password_verifier, @@ -72,6 +74,14 @@ class User < CouchRest::Model::Base      Ticket.for_user(self).limit(count).all #defaults to having most recent updated first    end +  def messages(unseen = true) +    #TODO for now this only shows unseen messages. Will we ever want seen ones? Is it necessary to store? + +    # we don't want to emit all the userids associated with a message, so only emit id and text. +    Message.by_user_ids_to_show.key(self.id).map { |message| [message.id, message.text] } + +  end +    # DEPRECATED    #    # Please set the key on the identity directly @@ -110,6 +120,32 @@ class User < CouchRest::Model::Base      ServiceLevel.new({id: code})    end + +  def self.send_one_month_warnings + +    # To determine warnings to send, need to get all users where one_month_warning_sent is not set, and where it was created greater than or equal to 1 month ago. +    # TODO: might want to further limit to enabled accounts, and, based on provider's service level configuration, for particular service levels. +    users_to_warn = User.by_created_at_and_one_month_warning_not_sent.endkey(Time.now-1.month) + +    users_to_warn.each do |user| +      # instead of loop could use something like: +      # message.user_ids_to_show = users_to_warn.map(&:id) +      # but would still need to loop through users to store one_month_warning_sent + +      if !@message +        # create a message for today's date +        # only want to create once, and only if it will be used. +        @message = Message.new(:text => I18n.t(:payment_one_month_warning, :date_in_one_month => (Time.now+1.month).strftime("%Y-%d-%m"))) +      end + +      @message.user_ids_to_show << user.id +      user.one_month_warning_sent = true +      user.save +    end +    @message.save if @message + +  end +    protected    ## diff --git a/users/config/locales/en.yml b/users/config/locales/en.yml index e597164..ed6653a 100644 --- a/users/config/locales/en.yml +++ b/users/config/locales/en.yml @@ -37,6 +37,7 @@ en:    enable_description: "This will restore the account to full functionality"    deactivate_account: "Deactivate the account %{username}"    deactivate_description: "This will temporarily deactivate some account functionality." #todo detail exact functionality. can receive email but not send or renew client certificate? +  payment_one_month_warning: "We hope you have been enjoying this service this past month. Please sign up to pay within the next month, by %{date_in_one_month}. Directions for payment are available at INSERT_URL"    bye: "Goodbye!"    bye_message: "So long and thanks for all the fish." diff --git a/users/config/routes.rb b/users/config/routes.rb index 736b283..2819fa9 100644 --- a/users/config/routes.rb +++ b/users/config/routes.rb @@ -6,6 +6,7 @@ Rails.application.routes.draw do      resources :sessions, :only => [:new, :create, :update]      delete "logout" => "sessions#destroy", :as => "logout"      resources :users, :only => [:create, :update, :destroy, :index] +    resources :messages, :only => [:index, :update]    end    scope "(:locale)", :locale => MATCH_LOCALE do diff --git a/users/lib/tasks/leap_web_users_tasks.rake b/users/lib/tasks/leap_web_users_tasks.rake index 3d0649c..62bcbe9 100644 --- a/users/lib/tasks/leap_web_users_tasks.rake +++ b/users/lib/tasks/leap_web_users_tasks.rake @@ -2,3 +2,9 @@  # task :leap_web_users do  #   # Task goes here  # end + +# recommended that for our setup, we should have this triggered from a cron job in puppet rather than using whenever gem +desc "Send one month warning messages" +task :leap_web_users do +  User.send_one_month_warnings +end diff --git a/users/test/functional/v1/messages_controller_test.rb b/users/test/functional/v1/messages_controller_test.rb new file mode 100644 index 0000000..24a5b1f --- /dev/null +++ b/users/test/functional/v1/messages_controller_test.rb @@ -0,0 +1,57 @@ +require 'test_helper' + +class V1::MessagesControllerTest < ActionController::TestCase + +  setup do +    @user = FactoryGirl.build(:user) +    @user.save +    @message = Message.new(:text => 'a test message') +    @message.user_ids_to_show << @user.id +    @message.save +  end + +  teardown do +    @message.destroy +    @user.destroy +  end + +  test "get messages for user" do +    login @user +    get :index +    assert response.body.include? @message.text +    assert response.body.include? @message.id +  end + +  test "mark message read for user" do +    login @user +    assert @message.user_ids_to_show.include?(@user.id) +    assert !@message.user_ids_have_shown.include?(@user.id) +    put :update, :id => @message.id +    @message.reload +    assert !@message.user_ids_to_show.include?(@user.id) +    assert @message.user_ids_have_shown.include?(@user.id) +    assert_json_response true +  end + +  test "do not get seen messages" do +    login @user +    put :update, :id => @message.id +    @message.reload +    get :index +    assert !(response.body.include? @message.text) +    assert !(response.body.include? @message.id) +  end + + +  test "mark read responds even with bad inputs" do +    login @user +    put :update, :id => 'more nonsense' +    assert_json_response false + end + +  test "fails if not authenticated" do +    get :index, :format => :json +    assert_access_denied +  end + +end | 
