summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorazul <azul@riseup.net>2014-02-10 12:44:08 +0100
committerazul <azul@riseup.net>2014-02-10 12:44:08 +0100
commitbcdde2f6bfb4ed3a1535bd2e50ab47529a9141e2 (patch)
tree6748d5170cb2a3ed387f2bf8f26bacbbc46df7d1
parent38474e94e3bfaeb40fb87bf2a9b8b1fbe546bc05 (diff)
parent7e0573f3347dca6323eae05127849431ecbceb77 (diff)
Merge pull request #134 from jessib/feature/messages_api
Feature/messages api
-rw-r--r--users/app/controllers/v1/messages_controller.rb28
-rw-r--r--users/app/designs/message/by_user_ids_to_show.js7
-rw-r--r--users/app/designs/message/by_user_ids_to_show_and_created_at.js9
-rw-r--r--users/app/designs/user/by_created_at_and_one_month_warning_not_sent.js5
-rw-r--r--users/app/models/message.rb16
-rw-r--r--users/app/models/user.rb36
-rw-r--r--users/config/locales/en.yml1
-rw-r--r--users/config/routes.rb1
-rw-r--r--users/lib/tasks/leap_web_users_tasks.rake6
-rw-r--r--users/test/functional/v1/messages_controller_test.rb57
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