summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Gemfile.lock5
-rw-r--r--users/app/controllers/v1/messages_controller.rb30
-rw-r--r--users/app/designs/user/by_created_at_and_one_month_warning_not_sent.js5
-rw-r--r--users/app/models/message.rb10
-rw-r--r--users/app/models/user.rb37
-rw-r--r--users/config/locales/en.yml1
-rw-r--r--users/config/routes.rb2
-rw-r--r--users/config/schedule.rb24
-rw-r--r--users/leap_web_users.gemspec1
-rw-r--r--users/lib/leap_web_users/engine.rb1
-rw-r--r--users/test/functional/v1/messages_controller_test.rb60
11 files changed, 176 insertions, 0 deletions
diff --git a/Gemfile.lock b/Gemfile.lock
index 09d3123..b42ac86 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -42,6 +42,7 @@ PATH
leap_web_core (= 0.5.0.rc)
rails_warden
ruby-srp (~> 0.2.1)
+ whenever
GEM
remote: https://rubygems.org/
@@ -88,6 +89,7 @@ GEM
rack (>= 1.0.0)
rack-test (>= 0.5.4)
xpath (~> 2.0)
+ chronic (0.9.1)
client_side_validations (3.2.6)
client_side_validations-simple_form (2.1.0)
client_side_validations (~> 3.2.5)
@@ -255,6 +257,9 @@ GEM
warden (1.2.3)
rack (>= 1.0)
websocket-driver (0.3.1)
+ whenever (0.8.2)
+ activesupport (>= 2.3.4)
+ chronic (>= 0.6.3)
xpath (2.0.0)
nokogiri (~> 1.3)
diff --git a/users/app/controllers/v1/messages_controller.rb b/users/app/controllers/v1/messages_controller.rb
new file mode 100644
index 0000000..b58dfe9
--- /dev/null
+++ b/users/app/controllers/v1/messages_controller.rb
@@ -0,0 +1,30 @@
+module V1
+ class MessagesController < ApplicationController
+
+ before_filter :authorize_admin # not sure this is best way
+ respond_to :json
+
+ # for now, will not pass unseen, so unseen will always be true
+ def user_messages(unseen = true)
+ user = User.find(params[:user_id])
+ render json: (user ? user.messages : [] )
+ end
+
+ # routes ensure this is only for PUT
+ def mark_read
+
+ # make sure user and message exist
+ if (user = User.find(params[:user_id])) && Message.find(params[:message_id])
+
+ user.message_ids_seen << params[:message_id] if !user.message_ids_seen.include?(params[:message_id]) #TODO: is it quicker to instead call uniq! after adding?
+ user.message_ids_to_see.delete(params[:message_id])
+ user.save
+ render json: true
+ return
+ else
+ render json: false
+ end
+
+ end
+ end
+end
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..38fa71e
--- /dev/null
+++ b/users/app/models/message.rb
@@ -0,0 +1,10 @@
+class Message < CouchRest::Model::Base
+
+ use_database :messages
+
+ property :text, String
+
+ design do
+ end
+
+end
diff --git a/users/app/models/user.rb b/users/app/models/user.rb
index 720f5a9..6e445be 100644
--- a/users/app/models/user.rb
+++ b/users/app/models/user.rb
@@ -13,6 +13,10 @@ class User < CouchRest::Model::Base
property :desired_service_level_code, Integer, :accessible => true
property :effective_service_level_code, Integer, :accessible => true
+ property :message_ids_to_see, [String]
+ property :message_ids_seen, [String]
+ property :one_month_warning_sent, TrueClass
+
before_save :update_effective_service_level
validates :login, :password_salt, :password_verifier,
@@ -72,6 +76,18 @@ class User < CouchRest::Model::Base
Ticket.for_user(self).limit(count).all #defaults to having most recent updated first
end
+ def messages(unseen = true)
+
+ message_ids = unseen ? self.message_ids_to_see : self.message_ids_to_see + self.message_ids_seen # TODO check unique?
+
+ messages = []
+ message_ids.each do |message_id|
+ messages << Message.find(message_id)
+ end
+ messages
+
+ end
+
# DEPRECATED
#
# Please set the key on the identity directly
@@ -110,6 +126,27 @@ 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|
+ 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")))
+ @message.save
+ end
+
+ user.message_ids_to_see << @message.id
+ user.one_month_warning_sent = true
+ user.save
+ end
+
+ end
+
protected
##
diff --git a/users/config/locales/en.yml b/users/config/locales/en.yml
index 934fcee..0db63eb 100644
--- a/users/config/locales/en.yml
+++ b/users/config/locales/en.yml
@@ -38,6 +38,7 @@ en:
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"
#
# overview
diff --git a/users/config/routes.rb b/users/config/routes.rb
index 736b283..9a7c531 100644
--- a/users/config/routes.rb
+++ b/users/config/routes.rb
@@ -6,6 +6,8 @@ Rails.application.routes.draw do
resources :sessions, :only => [:new, :create, :update]
delete "logout" => "sessions#destroy", :as => "logout"
resources :users, :only => [:create, :update, :destroy, :index]
+ get "user_messages/:user_id" => "messages#user_messages"
+ put "mark_read/:user_id/:message_id" => "messages#mark_read"
end
scope "(:locale)", :locale => MATCH_LOCALE do
diff --git a/users/config/schedule.rb b/users/config/schedule.rb
new file mode 100644
index 0000000..4ecbe7c
--- /dev/null
+++ b/users/config/schedule.rb
@@ -0,0 +1,24 @@
+# Use this file to easily define all of your cron jobs.
+#
+# It's helpful, but not entirely necessary to understand cron before proceeding.
+# http://en.wikipedia.org/wiki/Cron
+
+# Example:
+#
+# set :output, "/path/to/my/cron_log.log"
+#
+# every 2.hours do
+# command "/usr/bin/some_great_command"
+# runner "MyModel.some_method"
+# rake "some:great:rake:task"
+# end
+#
+# every 4.days do
+# runner "AnotherModel.prune_old_records"
+# end
+
+# Learn more: http://github.com/javan/whenever
+
+every 1.day, :at => '1am' do
+ runner "User.send_one_month_warnings"
+end
diff --git a/users/leap_web_users.gemspec b/users/leap_web_users.gemspec
index 7d1f220..06965a7 100644
--- a/users/leap_web_users.gemspec
+++ b/users/leap_web_users.gemspec
@@ -19,4 +19,5 @@ Gem::Specification.new do |s|
s.add_dependency "ruby-srp", "~> 0.2.1"
s.add_dependency "rails_warden"
+ s.add_dependency "whenever"
end
diff --git a/users/lib/leap_web_users/engine.rb b/users/lib/leap_web_users/engine.rb
index f8ed71c..61131ef 100644
--- a/users/lib/leap_web_users/engine.rb
+++ b/users/lib/leap_web_users/engine.rb
@@ -8,6 +8,7 @@ require "warden/session_serializer"
require "warden/strategies/secure_remote_password"
require "webfinger"
+require "whenever"
module LeapWebUsers
class Engine < ::Rails::Engine
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..0bc09be
--- /dev/null
+++ b/users/test/functional/v1/messages_controller_test.rb
@@ -0,0 +1,60 @@
+require 'test_helper'
+
+class V1::MessagesControllerTest < ActionController::TestCase
+
+ setup do
+ @message = Message.new(:text => 'a test message')
+ @message.save
+ @user = FactoryGirl.build(:user)
+ @user.message_ids_to_see << @message.id
+ @user.save
+ login :is_admin? => true
+ end
+
+ teardown do
+ @user.destroy
+ @message.destroy
+ end
+
+ test "get messages for user" do
+ get :user_messages, :user_id => @user.id
+ assert response.body.include? @message.text
+ assert response.body.include? @message.id
+ end
+
+ test "mark message read for user" do
+ assert @user.message_ids_to_see.include?(@message.id)
+ assert !@user.message_ids_seen.include?(@message.id)
+
+ put :mark_read, :user_id => @user.id, :message_id => @message.id
+ @user.reload
+ assert !@user.message_ids_to_see.include?(@message.id)
+ assert @user.message_ids_seen.include?(@message.id)
+ assert_json_response true
+ end
+
+ test "do not get seen messages" do
+ put :mark_read, :user_id => @user.id, :message_id => @message.id
+ @user.reload
+ get :user_messages, :user_id => @user.id
+ assert !(response.body.include? @message.text)
+ assert !(response.body.include? @message.id)
+ end
+
+ test "empty messages for non-existing user" do
+ get :user_messages, :user_id => 'some random string'
+ assert_json_response []
+ end
+
+ test "mark read responds even with bad inputs" do
+ put :mark_read, :user_id => 'nonsense', :message_id => 'more nonsense'
+ assert_json_response false
+ end
+
+ test "fails if not admin" do
+ login :is_admin? => false
+ get :user_messages, :user_id => @user.id
+ assert_access_denied
+ end
+
+end