watchtower 0.0.1

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.
Files changed (50) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +3 -0
  3. data/Rakefile +40 -0
  4. data/app/assets/javascripts/watchtower/application.js +15 -0
  5. data/app/assets/javascripts/watchtower/contacts.js +11 -0
  6. data/app/assets/javascripts/watchtower/jquery.jqmodal.js +69 -0
  7. data/app/assets/stylesheets/watchtower/application.css +13 -0
  8. data/app/assets/stylesheets/watchtower/bootstrap.css +610 -0
  9. data/app/assets/stylesheets/watchtower/contacts.css +156 -0
  10. data/app/controllers/watchtower/application_controller.rb +4 -0
  11. data/app/controllers/watchtower/contacts_controller.rb +101 -0
  12. data/app/controllers/watchtower/notes_controller.rb +15 -0
  13. data/app/controllers/watchtower/tags_controller.rb +11 -0
  14. data/app/helpers/watchtower/application_helper.rb +4 -0
  15. data/app/helpers/watchtower/contacts_helper.rb +4 -0
  16. data/app/models/watchtower/address.rb +17 -0
  17. data/app/models/watchtower/contact.rb +54 -0
  18. data/app/models/watchtower/custom_data.rb +4 -0
  19. data/app/models/watchtower/data.rb +15 -0
  20. data/app/models/watchtower/email.rb +4 -0
  21. data/app/models/watchtower/note.rb +13 -0
  22. data/app/models/watchtower/phone.rb +4 -0
  23. data/app/models/watchtower/tag.rb +14 -0
  24. data/app/models/watchtower/tagging.rb +9 -0
  25. data/app/views/layouts/watchtower/application.html.erb +27 -0
  26. data/app/views/watchtower/addresses/_address.html.erb +2 -0
  27. data/app/views/watchtower/contacts/_contact.html.erb +9 -0
  28. data/app/views/watchtower/contacts/_form.html.erb +33 -0
  29. data/app/views/watchtower/contacts/edit.html.erb +6 -0
  30. data/app/views/watchtower/contacts/index.html.erb +23 -0
  31. data/app/views/watchtower/contacts/new.html.erb +5 -0
  32. data/app/views/watchtower/contacts/show.html.erb +77 -0
  33. data/app/views/watchtower/emails/_email.html.erb +1 -0
  34. data/app/views/watchtower/notes/_note.html.erb +1 -0
  35. data/app/views/watchtower/phones/_phone.html.erb +1 -0
  36. data/app/views/watchtower/tags/_tag.html.erb +4 -0
  37. data/app/views/watchtower/tags/index.html.erb +12 -0
  38. data/app/views/watchtower/tags/show.html.erb +23 -0
  39. data/config/routes.rb +10 -0
  40. data/db/migrate/20120616233432_create_watchtower_contacts.rb +12 -0
  41. data/db/migrate/20120616235440_create_watchtower_data.rb +13 -0
  42. data/db/migrate/20120617010925_create_watchtower_addresses.rb +18 -0
  43. data/db/migrate/20120617055914_create_watchtower_notes.rb +13 -0
  44. data/db/migrate/20120617073423_create_watchtower_taggings.rb +12 -0
  45. data/db/migrate/20120617073438_create_watchtower_tags.rb +9 -0
  46. data/lib/tasks/watchtower_tasks.rake +4 -0
  47. data/lib/watchtower.rb +4 -0
  48. data/lib/watchtower/engine.rb +11 -0
  49. data/lib/watchtower/version.rb +3 -0
  50. metadata +164 -0
@@ -0,0 +1,156 @@
1
+ /*
2
+ Place all the styles related to the matching controller here.
3
+ They will automatically be included in application.css.
4
+ */
5
+
6
+ body {
7
+ margin: 15px;
8
+ margin-top: 55px;
9
+ line-height: 24px !important;
10
+ margin-left: 35px;
11
+ }
12
+
13
+ ul.tags {
14
+ list-style: none;
15
+ margin-left: 0px;
16
+ }
17
+ ul.tags li {
18
+ display: inline-block;
19
+ }
20
+
21
+ dl {
22
+ margin-top: 0px;
23
+ clear: both;
24
+ }
25
+
26
+ dt {
27
+ font-weight: normal;
28
+ color: #888;
29
+ clear: both;
30
+ display: inline-block;
31
+ width: 50px;
32
+ }
33
+
34
+ dd {
35
+ display: inline;
36
+ clear: right;
37
+ }
38
+
39
+ textarea {
40
+ height: 100px;
41
+ width: 600px;
42
+ }
43
+
44
+ .navbar-inner {
45
+ height: 36px;
46
+ background: #f0f0f0;
47
+ padding-left: 20px;
48
+ }
49
+
50
+ .navbar a {
51
+ color: #333 !important;
52
+ text-shadow: none;
53
+ }
54
+ .navbar .brand {
55
+ margin-left: 15px;
56
+ }
57
+
58
+ .navbar li.active a {
59
+ height: 20px;
60
+ color: #f5f5f5 !important;
61
+ }
62
+
63
+ h1, h3 {
64
+ margin-top: 20px;
65
+ margin-bottom: 8px;
66
+ }
67
+ h1 {
68
+ font-size: 25px;
69
+ }
70
+
71
+ h3 {
72
+ font-weight: 200;
73
+ clear: left;
74
+ }
75
+
76
+ table {
77
+ width: 100%;
78
+ }
79
+
80
+ .field {
81
+ margin-bottom: 10px
82
+ }
83
+
84
+ .field input {
85
+ margin-left: 15px;
86
+ }
87
+
88
+ .notes {
89
+ list-style: none;
90
+ margin: 0;
91
+ margin-left: 15px;
92
+ }
93
+
94
+ .note {
95
+ background: #f5f5f5;
96
+ margin-top: 10px;
97
+ margin-bottom: 10px;
98
+ padding: 15px;
99
+ }
100
+
101
+
102
+
103
+ .dialog {
104
+ width: 100px;
105
+ margin: auto;
106
+ display: none;
107
+
108
+ position: fixed;
109
+ top: 20%;
110
+ left: 50%;
111
+
112
+ margin-left: -300px;
113
+ width: 500px;
114
+
115
+ background-color: #fff;
116
+ -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
117
+ -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
118
+ box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
119
+ -webkit-background-clip: padding-box;
120
+ -moz-background-clip: padding-box;
121
+ background-clip: padding-box;
122
+ color: #333;
123
+ border: 1px solid #555;
124
+ border: 1px solid rgba(0, 0, 0, 0.3);
125
+ }
126
+ .dialog h2 {
127
+ margin: 23px;
128
+ margin-top: 14px;
129
+ font-size: 20px;
130
+ font-weight: 400;
131
+ }
132
+ .dialog p { margin: 8px;}
133
+ .dialog p.dlg_content {
134
+ min-height: 25px;
135
+ font-size: 15px;
136
+ padding-left: 15px;
137
+ }
138
+ .dialog p.actions {
139
+ margin: 0;
140
+ display: block;
141
+ float: right;
142
+ height: 30px;
143
+ text-align: right;
144
+ padding: 14px 15px 15px;
145
+ }
146
+ /* a { display: inline-block; }
147
+ a.submit {
148
+ @include button;
149
+ text-decoration: none;
150
+ }*/
151
+ /* }
152
+ }*/
153
+
154
+
155
+ .jqmOverlay { background-color: #fff; }
156
+
@@ -0,0 +1,4 @@
1
+ module Watchtower
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,101 @@
1
+ require_dependency "watchtower/application_controller"
2
+
3
+ module Watchtower
4
+ class ContactsController < ApplicationController
5
+ # GET /contacts
6
+ # GET /contacts.json
7
+ def index
8
+ @contacts = Contact.all
9
+
10
+ respond_to do |format|
11
+ format.html # index.html.erb
12
+ format.json { render json: @contacts }
13
+ end
14
+ end
15
+
16
+ # GET /contacts/1
17
+ # GET /contacts/1.json
18
+ def show
19
+ @contact = Contact.find(params[:id])
20
+
21
+ respond_to do |format|
22
+ format.html # show.html.erb
23
+ format.json { render json: @contact }
24
+ end
25
+ end
26
+
27
+ # GET /contacts/new
28
+ # GET /contacts/new.json
29
+ def new
30
+ @contact = Contact.new
31
+
32
+ respond_to do |format|
33
+ format.html # new.html.erb
34
+ format.json { render json: @contact }
35
+ end
36
+ end
37
+
38
+ # GET /contacts/1/edit
39
+ def edit
40
+ @contact = Contact.find(params[:id])
41
+ end
42
+
43
+ # POST /contacts
44
+ # POST /contacts.json
45
+ def create
46
+ @contact = Contact.new(params[:contact])
47
+
48
+ respond_to do |format|
49
+ if @contact.save
50
+ format.html { redirect_to @contact, notice: 'Contact was successfully created.' }
51
+ format.json { render json: @contact, status: :created, location: @contact }
52
+ else
53
+ format.html { render action: "new" }
54
+ format.json { render json: @contact.errors, status: :unprocessable_entity }
55
+ end
56
+ end
57
+ end
58
+
59
+ # PUT /contacts/1
60
+ # PUT /contacts/1.json
61
+ def update
62
+ @contact = Contact.find(params[:id])
63
+
64
+ respond_to do |format|
65
+ if @contact.update_attributes(params[:contact])
66
+ format.html { redirect_to @contact, notice: 'Contact was successfully updated.' }
67
+ format.json { head :no_content }
68
+ else
69
+ format.html { render action: "edit" }
70
+ format.json { render json: @contact.errors, status: :unprocessable_entity }
71
+ end
72
+ end
73
+ end
74
+
75
+ # DELETE /contacts/1
76
+ # DELETE /contacts/1.json
77
+ def destroy
78
+ @contact = Contact.find(params[:id])
79
+ @contact.destroy
80
+
81
+ respond_to do |format|
82
+ format.html { redirect_to contacts_url }
83
+ format.json { head :no_content }
84
+ end
85
+ end
86
+
87
+ def tag
88
+ @contact = Contact.find(params[:id])
89
+
90
+ respond_to do |format|
91
+ if @contact.tag_with(params[:tag_name]).valid?
92
+ format.html { redirect_to @contact, notice: 'Contact was successfully tagged.' }
93
+ format.json { head :no_content }
94
+ else
95
+ format.html { render action: "show" }
96
+ format.json { render json: @contact.errors, status: :unprocessable_entity }
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,15 @@
1
+ require_dependency "watchtower/application_controller"
2
+
3
+ module Watchtower
4
+ class NotesController < ApplicationController
5
+ def create
6
+ @contact = Contact.find(params[:contact_id])
7
+ @note = @contact.notes.build(params[:note])
8
+ if @note.save
9
+ redirect_to @contact, notice: "Note added."
10
+ else
11
+ redirect_to @contact, notice: "Note could not be added."
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ module Watchtower
2
+ class TagsController < ApplicationController
3
+ def index
4
+ @tags = Tag.all
5
+ end
6
+
7
+ def show
8
+ @tag = Tag.find(params[:id])
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,4 @@
1
+ module Watchtower
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Watchtower
2
+ module ContactsHelper
3
+ end
4
+ end
@@ -0,0 +1,17 @@
1
+ module Watchtower
2
+ class Address < ActiveRecord::Base
3
+ attr_accessible :address_1, :address_2, :address_3, :city, :country, :kind, :name, :postcode, :state
4
+
5
+ def kind
6
+ self[:kind] || "primary"
7
+ end
8
+
9
+ def full_address
10
+ [:address_1, :address_2, :address_3, :city, :state, :country].compact.join("\n")
11
+ end
12
+
13
+ def to_s
14
+ name
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,54 @@
1
+ module Watchtower
2
+ class Contact < ActiveRecord::Base
3
+ attr_accessible :first_name, :gender, :last_name, :middle_name, :primary_phone, :primary_email
4
+
5
+ module DataExtension
6
+ def add(string, opts={})
7
+ create(content: string, primary: opts[:primary])
8
+ end
9
+ end
10
+
11
+ has_many :emails, :class_name => "Watchtower::Email", :extend => DataExtension
12
+ has_many :phones, :class_name => "Watchtower::Phone", :extend => DataExtension
13
+ has_many :custom_data, :class_name => "Watchtower::CustomData", :extend => DataExtension
14
+
15
+ has_many :addresses, :class_name => "Watchtower::Address"
16
+
17
+ has_many :notes, :class_name => "Watchtower::Note"
18
+ has_many :users, :through => :notes
19
+
20
+ has_many :taggings, :class_name => "Watchtower::Tagging"
21
+ has_many :tags, :through => :taggings
22
+
23
+ def tag_names
24
+ tags.map(&:to_s)
25
+ end
26
+
27
+ # FIXME: metaprogramming bad
28
+ %w(email address phone).each do |type|
29
+ define_method "primary_#{type}" do
30
+ self.send(type.pluralize).where(primary: true).first || self.send(type.pluralize).first
31
+ end
32
+
33
+ define_method "primary_#{type}=" do |addr|
34
+ self.send(type.pluralize).build(content: addr, primary: true)
35
+ end
36
+ end
37
+
38
+ def full_name
39
+ [first_name, middle_name, last_name].compact.join(' ')
40
+ end
41
+
42
+ def name
43
+ full_name
44
+ end
45
+
46
+ def to_s
47
+ full_name
48
+ end
49
+
50
+ def tag_with(tag_name)
51
+ taggings.create(tag: Tag.find_or_create_by_name(tag_name.try(:downcase)))
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,4 @@
1
+ module Watchtower
2
+ class CustomData < Watchtower::Data
3
+ end
4
+ end
@@ -0,0 +1,15 @@
1
+ module Watchtower
2
+ class Data < ActiveRecord::Base
3
+ attr_accessible :content, :name, :primary
4
+
5
+ belongs_to :contact, :class_name => "Watchtower::Contact"
6
+
7
+ def name
8
+ self[:name] || "other"
9
+ end
10
+
11
+ def to_s
12
+ content
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,4 @@
1
+ module Watchtower
2
+ class Email < Watchtower::Data
3
+ end
4
+ end
@@ -0,0 +1,13 @@
1
+ module Watchtower
2
+ class Note < ActiveRecord::Base
3
+ belongs_to :user, :class_name => Watchtower.user_class
4
+ belongs_to :contact
5
+ attr_accessible :content
6
+
7
+ validates :content, :presence => true
8
+
9
+ def to_s
10
+ content
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,4 @@
1
+ module Watchtower
2
+ class Phone < Watchtower::Data
3
+ end
4
+ end
@@ -0,0 +1,14 @@
1
+ module Watchtower
2
+ class Tag < ActiveRecord::Base
3
+ attr_accessible :name
4
+
5
+ has_many :taggings, :class_name => "Watchtower::Tagging"
6
+ has_many :contacts, :through => :taggings
7
+
8
+ validates :name, :presence => true
9
+
10
+ def to_s
11
+ name
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,9 @@
1
+ module Watchtower
2
+ class Tagging < ActiveRecord::Base
3
+ belongs_to :contact
4
+ belongs_to :tag
5
+ attr_accessible :tag
6
+
7
+ validates :contact_id, :uniqueness => { :scope => :tag_id }
8
+ end
9
+ end