kitestrings 1.0.2 → 1.0.3
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +10 -0
- data/kitestrings.gemspec +0 -2
- data/lib/generators/kitestrings/install_generator.rb +26 -6
- data/lib/generators/kitestrings/message_templates/default.text.erb +7 -0
- data/lib/generators/kitestrings/message_templates/index.html.haml +26 -0
- data/lib/generators/kitestrings/{templates → message_templates}/message.rb.erb +19 -2
- data/lib/generators/kitestrings/message_templates/message_mailer.rb +19 -0
- data/lib/generators/kitestrings/message_templates/message_migration.rb +20 -0
- data/lib/generators/kitestrings/message_templates/message_spec.rb +73 -0
- data/lib/generators/kitestrings/message_templates/messages.rb +11 -0
- data/lib/generators/kitestrings/message_templates/messages_controller.rb +41 -0
- data/lib/generators/kitestrings/message_templates/messages_controller_spec.rb +86 -0
- data/lib/generators/kitestrings/message_templates/show.html.haml +32 -0
- data/lib/generators/kitestrings/messages_generator.rb +64 -1
- data/lib/generators/templates/{deploy.rb → config/deploy.rb} +19 -16
- data/lib/generators/templates/config/deploy/integ.rb +3 -0
- data/lib/generators/templates/config/deploy/production.rb +12 -0
- data/lib/generators/templates/config/deploy/uat.rb +3 -0
- data/lib/generators/templates/config/environments/integ.rb +21 -0
- data/lib/generators/templates/config/environments/uat.rb +21 -0
- data/lib/generators/templates/views/public/403.html +30 -0
- data/lib/kitestrings/menu.rb +10 -0
- data/lib/kitestrings/menu/admin_controller.rb +21 -0
- data/lib/kitestrings/menu/controller.rb +24 -0
- data/lib/kitestrings/menu/item.rb +94 -0
- data/lib/kitestrings/menu/item_collection.rb +29 -0
- data/lib/kitestrings/menu/model.rb +29 -0
- data/lib/kitestrings/menu/view_helper.rb +68 -0
- data/lib/kitestrings/version.rb +1 -1
- data/spec/lib/generators/kitestrings/install_generator_spec.rb +17 -13
- data/spec/lib/generators/kitestrings/messages_generator_spec.rb +31 -3
- data/spec/lib/kitestrings/menu/model_spec.rb +33 -0
- data/spec/support/active_record.rb +0 -1
- data/spec/support/generator_support.rb +15 -0
- metadata +30 -35
- data/lib/generators/templates/deploy/integ.rb +0 -21
- data/lib/generators/templates/deploy/production.rb +0 -26
- data/lib/generators/templates/deploy/uat.rb +0 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e359fb5855cd726d02dd9c2a51508e1d0a3bb848
|
4
|
+
data.tar.gz: 2cf04623592f47430d13f1da9c0bf81f3f78c122
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b02af42e038270039c4ce945729900c9c232086708c53988221bc26f3380367c44501b3c5c4b22641df175a2fe8406f631216fc4654d7b2fd6c7602c8c5a8d5
|
7
|
+
data.tar.gz: fa7776a4bc5cab3baf5b54cd82f0959b3b3215b70ffad2cbe96a9308f059c03eeee76f21396d0922a2e0ff39e5d3c971f21ecb54d741a2cb772ae7c56e0ca568
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
# Version history:
|
2
2
|
|
3
|
+
## Next
|
4
|
+
|
5
|
+
* Added Kitestrings::Menu classes/modules to assist with rendering menus in web pages.
|
6
|
+
* Added generator: kitestrings:messages to add a scaffold model and controller.
|
7
|
+
|
8
|
+
## 1.0.3
|
9
|
+
|
10
|
+
* Added an Access Denied page to be shown when a CanCan::AccessDenied error occurs (except in develop/test)
|
11
|
+
* Added UAT and INTEG environments and deploy files to install generator.
|
12
|
+
|
3
13
|
## 1.0.2
|
4
14
|
|
5
15
|
* Added FormObject#update to behave like persisted active record model objects.
|
data/kitestrings.gemspec
CHANGED
@@ -19,12 +19,10 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
21
|
spec.add_runtime_dependency "rails", ">= 3.2"
|
22
|
-
spec.add_runtime_dependency "activemodel", ">= 3.2"
|
23
22
|
|
24
23
|
spec.add_development_dependency "bundler", "~> 1.6"
|
25
24
|
spec.add_development_dependency "rake"
|
26
25
|
spec.add_development_dependency "rspec", "~> 2.14"
|
27
26
|
spec.add_development_dependency "generator_spec"
|
28
27
|
spec.add_development_dependency "sqlite3"
|
29
|
-
spec.add_development_dependency "activerecord", ">= 3.2"
|
30
28
|
end
|
@@ -8,12 +8,10 @@ module Kitestrings
|
|
8
8
|
|
9
9
|
desc "Copies 2rk relevant templates to the relevant directory"
|
10
10
|
|
11
|
-
def
|
12
|
-
copy_file "deploy.rb", "config/deploy.rb"
|
13
|
-
|
14
|
-
|
15
|
-
def copy_deploy_files
|
16
|
-
directory "deploy", "config/deploy"
|
11
|
+
def copy_config_files
|
12
|
+
copy_file "config/deploy.rb", "config/deploy.rb"
|
13
|
+
directory "config/deploy", "config/deploy"
|
14
|
+
directory "config/environments", "config/environments"
|
17
15
|
end
|
18
16
|
|
19
17
|
def copy_haml_files
|
@@ -35,6 +33,28 @@ module Kitestrings
|
|
35
33
|
def copy_app_view_files
|
36
34
|
copy_file "views/application/_navigation.html.haml", "app/views/application/_navigation.html.haml"
|
37
35
|
copy_file "views/layouts/application.html.haml", "app/views/layouts/application.html.haml"
|
36
|
+
copy_file "views/public/403.html", "app/views/public/403.html"
|
37
|
+
end
|
38
|
+
|
39
|
+
def setup_application_controller
|
40
|
+
inject_into_file "app/controllers/application_controller.rb", :after => /protect_from_forgery.*$/ do
|
41
|
+
<<-EOF
|
42
|
+
|
43
|
+
|
44
|
+
unless Rails.application.config.consider_all_requests_local
|
45
|
+
rescue_from CanCan::AccessDenied do |exception|
|
46
|
+
# Notify errbit if you would like to:
|
47
|
+
# Airbrake.notify(exception)
|
48
|
+
render 'public/403', status: 403, layout: 'none'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
EOF
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def setup_directories
|
56
|
+
empty_directory("lib/capistrano")
|
57
|
+
create_file("lib/capistrano/.keep")
|
38
58
|
end
|
39
59
|
end
|
40
60
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
.page-header
|
2
|
+
%h1 Listing messages
|
3
|
+
|
4
|
+
.row
|
5
|
+
.col-md-12
|
6
|
+
%table.table.table-striped
|
7
|
+
%tr
|
8
|
+
%th.subject= sortable_title :subject
|
9
|
+
%th= sortable_title :sent_at
|
10
|
+
%th= sortable_title :user_name
|
11
|
+
%th Link
|
12
|
+
%th= sortable_title :clicked_at
|
13
|
+
%th= sortable_title :id
|
14
|
+
|
15
|
+
- @messages.each do |message|
|
16
|
+
%tr
|
17
|
+
%td.subject= message.user && link_to(message.subject || "(none)", user_message_path(message.user_id, message))
|
18
|
+
%td= l message.created_at
|
19
|
+
%td= message.user && link_to_if(can?(:show, message.user), message.user.try(:full_name), user_path(message.user.id))
|
20
|
+
%td= link_to message.link, message_path(message)
|
21
|
+
%td= message.clicked_at ? l(message.clicked_at) : nil
|
22
|
+
%td= message.id
|
23
|
+
%br
|
24
|
+
|
25
|
+
%p.pagination
|
26
|
+
= paginate @messages
|
@@ -9,7 +9,7 @@ class Message < ActiveRecord::Base
|
|
9
9
|
<% end %>
|
10
10
|
serialize :options
|
11
11
|
|
12
|
-
include Rails.application.
|
12
|
+
include Rails.application.routes.url_helpers
|
13
13
|
|
14
14
|
after_create :send_email
|
15
15
|
|
@@ -41,7 +41,7 @@ class Message < ActiveRecord::Base
|
|
41
41
|
|
42
42
|
# prepare a mail object ready for delivery by email or display on the screen
|
43
43
|
def mail
|
44
|
-
@mail ||= MessageMailer.prepare_message(self
|
44
|
+
@mail ||= MessageMailer.prepare_message(self)
|
45
45
|
end
|
46
46
|
|
47
47
|
# The "view" link. This is the link to the messages controller that marks the message
|
@@ -53,4 +53,21 @@ class Message < ActiveRecord::Base
|
|
53
53
|
def name
|
54
54
|
"Message ID: #{id}"
|
55
55
|
end
|
56
|
+
|
57
|
+
def add_attachments(mailer)
|
58
|
+
# This is called by the mailer to add any attachments. For example:
|
59
|
+
# if context.is_a? CalendarEvent
|
60
|
+
# mailer.attachments.inline["calendar.ics"] = context.to_ical
|
61
|
+
# end
|
62
|
+
end
|
63
|
+
|
64
|
+
# return the mail body as a string, skipping any attachment parts that may be in the message
|
65
|
+
def mail_body
|
66
|
+
if mail.multipart?
|
67
|
+
part = mail.parts.select { |p| p.text? && !p.attachment? }.first
|
68
|
+
part.body.to_s
|
69
|
+
else
|
70
|
+
mail.body.to_s
|
71
|
+
end
|
72
|
+
end
|
56
73
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class MessageMailer < ActionMailer::Base
|
2
|
+
#TODO set default from address
|
3
|
+
default from: "noreply@example.com"
|
4
|
+
|
5
|
+
attr :subject
|
6
|
+
|
7
|
+
def prepare_message(message)
|
8
|
+
@message = message
|
9
|
+
@user = message.user
|
10
|
+
|
11
|
+
# ask the message model if we need any attachments added
|
12
|
+
message.add_attachments(self)
|
13
|
+
|
14
|
+
m = mail(to: message.user.email, subject: message.subject, template_name: message.template || :default)
|
15
|
+
# allow template to override subject in the view by doing: <% @message.subject = "new subject" %>
|
16
|
+
m.subject = message.subject
|
17
|
+
m
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class CreateMessages < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :messages do |t|
|
4
|
+
t.references :user
|
5
|
+
t.string :template
|
6
|
+
t.string :context_type
|
7
|
+
t.integer :context_id
|
8
|
+
t.string :link
|
9
|
+
t.string :subject
|
10
|
+
t.datetime :clicked_at
|
11
|
+
t.datetime :sent_at
|
12
|
+
t.text :options
|
13
|
+
|
14
|
+
t.timestamps
|
15
|
+
end
|
16
|
+
|
17
|
+
add_index :messages, :user_id
|
18
|
+
add_index :messages, [:context_type, :context_id]
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Message do
|
4
|
+
|
5
|
+
let(:freeze_1) { Time.zone.now.change(:usec => 0) }
|
6
|
+
|
7
|
+
common_lets
|
8
|
+
|
9
|
+
context "relationships" do
|
10
|
+
it { should belong_to(:user) }
|
11
|
+
it { should belong_to(:context) }
|
12
|
+
end
|
13
|
+
|
14
|
+
context "validations" do
|
15
|
+
# validate the common_lets generated message instance:
|
16
|
+
it { expect(message).to be_valid }
|
17
|
+
it { should validate_presence_of(:user) }
|
18
|
+
end
|
19
|
+
|
20
|
+
describe 'latest' do
|
21
|
+
before do
|
22
|
+
Timecop.freeze(Time.local(1990)) do
|
23
|
+
message_other
|
24
|
+
message
|
25
|
+
end
|
26
|
+
end
|
27
|
+
it { expect(Message.latest).to match_array([message_other, message]) }
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#mail" do
|
31
|
+
# Example test for mail content:
|
32
|
+
# let(:message) { Message.new(template: "report_untag", context: relation, options: {foo: "bar"}, user: user_owner) }
|
33
|
+
# context "rendering email" do
|
34
|
+
# subject { message.mail }
|
35
|
+
# it { expect(subject.subject).to eq("Tag Removed Notification") }
|
36
|
+
# it { expect(subject.body).to include("The following tag has just been removed") }
|
37
|
+
# end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "#view_link" do
|
41
|
+
subject { message }
|
42
|
+
it "production" do
|
43
|
+
Rails.application.routes.stub(:default_url_options => {:host => 'example.com'})
|
44
|
+
Rails.env.stub(:production? => true)
|
45
|
+
expect(subject.view_link).to eq("http://example.com/messages/#{message.id}")
|
46
|
+
end
|
47
|
+
it "development" do
|
48
|
+
expect(subject.view_link).to eq("http://localhost/messages/#{message.id}")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
context '#send_email' do
|
54
|
+
context 'build only' do
|
55
|
+
before do
|
56
|
+
message.update_column(:sent_at, nil)
|
57
|
+
ActionMailer::Base.deliveries.clear
|
58
|
+
message.mail
|
59
|
+
end
|
60
|
+
it { expect(message.sent_at).to be_nil }
|
61
|
+
it { ActionMailer::Base.deliveries.should be_empty }
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'build and send' do
|
65
|
+
before do
|
66
|
+
Timecop.freeze(freeze_1) { message.send_email }
|
67
|
+
end
|
68
|
+
|
69
|
+
it { ActionMailer::Base.deliveries.last.to.should == [user.email] }
|
70
|
+
it { message.sent_at.should == freeze_1 }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class MessagesController < ApplicationController
|
2
|
+
|
3
|
+
include PageAndSortHelper
|
4
|
+
include PageAndSortHelper::Controller
|
5
|
+
helper PageAndSortHelper
|
6
|
+
|
7
|
+
before_filter do
|
8
|
+
authenticate_user!
|
9
|
+
load_and_authorize_if_present :user do
|
10
|
+
load_and_authorize :message
|
11
|
+
end
|
12
|
+
load_and_authorize :message
|
13
|
+
end
|
14
|
+
|
15
|
+
def index
|
16
|
+
@messages =
|
17
|
+
case
|
18
|
+
when @user
|
19
|
+
@user.messages
|
20
|
+
when can?(:index_all, Message)
|
21
|
+
Message
|
22
|
+
else
|
23
|
+
current_user.messages
|
24
|
+
end
|
25
|
+
|
26
|
+
@messages = page_and_sort(@messages, default_sort: :created_at, default_direction: :desc)
|
27
|
+
end
|
28
|
+
|
29
|
+
# this one controller action has two totally different functions:
|
30
|
+
#
|
31
|
+
# 1. /users/1/messages/3 => show the message content
|
32
|
+
# 2. /messages/3 => mark the message clicked at time and redirect to the link in the message.
|
33
|
+
def show
|
34
|
+
if @user
|
35
|
+
# show
|
36
|
+
else
|
37
|
+
@message.update_column(:clicked_at, Time.now) if current_user == @message.user
|
38
|
+
redirect_to @message.link
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe MessagesController do
|
4
|
+
render_views
|
5
|
+
common_lets
|
6
|
+
|
7
|
+
before :all do
|
8
|
+
Fracture.define_selector :new_message_link
|
9
|
+
Fracture.define_selector :cancel_new_message_link
|
10
|
+
Fracture.define_selector :edit_message_link
|
11
|
+
Fracture.define_selector :cancel_edit_message_link
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'not logged in' do
|
15
|
+
{index: :get, show: :get}.each do |v, m|
|
16
|
+
it "#{m} #{v} should logout" do
|
17
|
+
self.send(m, v, id: message)
|
18
|
+
should redirect_to new_user_session_path
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "signed in" do
|
24
|
+
before do
|
25
|
+
sign_in user
|
26
|
+
controller.should_receive(:authenticate_user!).and_call_original
|
27
|
+
end
|
28
|
+
|
29
|
+
context "GET index" do
|
30
|
+
context "not nested" do
|
31
|
+
before do
|
32
|
+
controller.should_receive(:authorize!).with(:index, Message)
|
33
|
+
message; message_other
|
34
|
+
get :index
|
35
|
+
end
|
36
|
+
it { should assign_to(:messages).with_items([message]) }
|
37
|
+
it { should render_template :index }
|
38
|
+
it { should have_only_fractures }
|
39
|
+
end
|
40
|
+
|
41
|
+
context "under user" do
|
42
|
+
before do
|
43
|
+
controller.should_receive(:authorize!).with(:show, user)
|
44
|
+
controller.should_receive(:authorize!).with(:index, user => Message)
|
45
|
+
controller.should_receive(:authorize!).with(:index, Message)
|
46
|
+
message; message_other
|
47
|
+
get :index, :user_id => user.id
|
48
|
+
end
|
49
|
+
it { should assign_to(:messages).with_items([message]) }
|
50
|
+
it { should render_template :index }
|
51
|
+
it { should have_only_fractures }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context "GET show" do
|
56
|
+
context "not nested" do # this is the redirect action. This link appears in the email.
|
57
|
+
before do
|
58
|
+
message.update_column :link, "/some/location"
|
59
|
+
Timecop.freeze(freeze_1) do
|
60
|
+
get :show, id: message
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
it { should assign_to(:message).with(message) }
|
65
|
+
it { should assign_to("message.clicked_at").with(freeze_1) }
|
66
|
+
it { should_not render_template :show }
|
67
|
+
it { should redirect_to("/some/location") }
|
68
|
+
end
|
69
|
+
|
70
|
+
# context 'not as the owner of the message' do
|
71
|
+
# it { expects_access_denied { get :show, id: message_other } }
|
72
|
+
# end
|
73
|
+
|
74
|
+
context "under user" do
|
75
|
+
before do
|
76
|
+
controller.should_receive(:authorize!).with(:show, user)
|
77
|
+
controller.should_receive(:authorize!).with(:show, message)
|
78
|
+
get :show, user_id: user, id: message
|
79
|
+
end
|
80
|
+
it { should assign_to(:message).with(message) }
|
81
|
+
it { should render_template :show }
|
82
|
+
it { should have_only_fractures }
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
%h1 Message
|
2
|
+
|
3
|
+
.row.form-horizontal
|
4
|
+
.col-md-1
|
5
|
+
%label.control-label Subject
|
6
|
+
.col-md-9
|
7
|
+
%p.form-text
|
8
|
+
%b= @message.subject
|
9
|
+
.row
|
10
|
+
.col-md-1
|
11
|
+
%label.control-label Date Sent
|
12
|
+
.col-md-9
|
13
|
+
%p.form-text
|
14
|
+
= @message.sent_at ? l(@message.sent_at) : "(not sent)"
|
15
|
+
.row
|
16
|
+
.col-md-1
|
17
|
+
%label.control-label Body
|
18
|
+
.col-md-9
|
19
|
+
%p
|
20
|
+
= simple_format(@message.mail_body)
|
21
|
+
-# or add the `gem "rails_autolink"` to Gemfile to detect links in the message body:
|
22
|
+
-#= simple_format(auto_link(@message.mail_body))
|
23
|
+
|
24
|
+
-#- if @message.mail.attachments.any?
|
25
|
+
-# .row
|
26
|
+
-# .col-md-1
|
27
|
+
-# %label.control-label Attachments
|
28
|
+
-# .col-md-9
|
29
|
+
-# %ul
|
30
|
+
-# - @message.mail.attachments.each_with_index do |attachment, index|
|
31
|
+
-# %li
|
32
|
+
-# = link_to(attachment.filename, company_user_message_attachment_path(@company, @user, @message, index+1))
|