db_notes_engine2 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 (94) hide show
  1. checksums.yaml +15 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +3 -0
  4. data/Rakefile +40 -0
  5. data/app/assets/images/db_notes_engine2/glyphicons-halflings-white.png +0 -0
  6. data/app/assets/images/db_notes_engine2/glyphicons-halflings.png +0 -0
  7. data/app/assets/images/db_notes_engine2/profile_b32.png +0 -0
  8. data/app/assets/javascripts/db_notes_engine2/bootstrap.js +2276 -0
  9. data/app/assets/javascripts/model_info.js +2 -0
  10. data/app/assets/stylesheets/db_notes_engine2/bootstrap-responsive.css +1109 -0
  11. data/app/assets/stylesheets/db_notes_engine2/bootstrap.css +6158 -0
  12. data/app/assets/stylesheets/model_info.css +4 -0
  13. data/app/controllers/model_info_controller.rb +165 -0
  14. data/app/helpers/model_info_helper.rb +2 -0
  15. data/app/models/comment.rb +4 -0
  16. data/app/models/note.rb +4 -0
  17. data/app/views/model_info/DBNotes.html.erb +418 -0
  18. data/config/routes.rb +32 -0
  19. data/db/migrate/1_create_notes.rb +12 -0
  20. data/db/migrate/2_create_comments.rb +11 -0
  21. data/lib/db_notes_engine2/engine.rb +4 -0
  22. data/lib/db_notes_engine2/version.rb +3 -0
  23. data/lib/db_notes_engine2.rb +4 -0
  24. data/lib/tasks/db_notes_engine2_tasks.rake +4 -0
  25. data/test/db_notes_engine2_test.rb +7 -0
  26. data/test/dummy/README.rdoc +261 -0
  27. data/test/dummy/Rakefile +7 -0
  28. data/test/dummy/app/assets/javascripts/application.js +15 -0
  29. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  30. data/test/dummy/app/controllers/application_controller.rb +3 -0
  31. data/test/dummy/app/helpers/application_helper.rb +2 -0
  32. data/test/dummy/app/models/table1.rb +3 -0
  33. data/test/dummy/app/models/table2.rb +3 -0
  34. data/test/dummy/app/views/layouts/application.html.erb +16 -0
  35. data/test/dummy/config/application.rb +59 -0
  36. data/test/dummy/config/boot.rb +10 -0
  37. data/test/dummy/config/database.yml +25 -0
  38. data/test/dummy/config/environment.rb +5 -0
  39. data/test/dummy/config/environments/development.rb +37 -0
  40. data/test/dummy/config/environments/production.rb +67 -0
  41. data/test/dummy/config/environments/test.rb +37 -0
  42. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  43. data/test/dummy/config/initializers/inflections.rb +15 -0
  44. data/test/dummy/config/initializers/mime_types.rb +5 -0
  45. data/test/dummy/config/initializers/secret_token.rb +7 -0
  46. data/test/dummy/config/initializers/session_store.rb +8 -0
  47. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  48. data/test/dummy/config/locales/en.yml +5 -0
  49. data/test/dummy/config/routes.rb +58 -0
  50. data/test/dummy/config.ru +4 -0
  51. data/test/dummy/db/development.sqlite3 +0 -0
  52. data/test/dummy/db/migrate/20130429103747_create_table1s.rb +11 -0
  53. data/test/dummy/db/migrate/20130429103818_create_table2s.rb +11 -0
  54. data/test/dummy/db/schema.rb +49 -0
  55. data/test/dummy/log/development.log +3344 -0
  56. data/test/dummy/public/404.html +26 -0
  57. data/test/dummy/public/422.html +26 -0
  58. data/test/dummy/public/500.html +25 -0
  59. data/test/dummy/public/favicon.ico +0 -0
  60. data/test/dummy/script/rails +6 -0
  61. data/test/dummy/test/fixtures/table1s.yml +11 -0
  62. data/test/dummy/test/fixtures/table2s.yml +11 -0
  63. data/test/dummy/test/unit/table1_test.rb +7 -0
  64. data/test/dummy/test/unit/table2_test.rb +7 -0
  65. data/test/dummy/tmp/cache/assets/C3D/0B0/sprockets%2Fa90e1f5537e716291e61838559766d78 +0 -0
  66. data/test/dummy/tmp/cache/assets/C5C/C70/sprockets%2Ffe40816117579661b1169b80494dae78 +0 -0
  67. data/test/dummy/tmp/cache/assets/C85/B90/sprockets%2F3752b7a9ca8205c7152739e4b04d5498 +0 -0
  68. data/test/dummy/tmp/cache/assets/C8B/D80/sprockets%2Fe1099f086a9013779fbf0644a6d08465 +0 -0
  69. data/test/dummy/tmp/cache/assets/CC0/690/sprockets%2Fde26f6ed8a7253208ca5e93235753869 +0 -0
  70. data/test/dummy/tmp/cache/assets/CD8/370/sprockets%2F357970feca3ac29060c1e3861e2c0953 +0 -0
  71. data/test/dummy/tmp/cache/assets/CE3/100/sprockets%2F80c613eaa3543b4085b7f550878b88dc +0 -0
  72. data/test/dummy/tmp/cache/assets/D1A/5C0/sprockets%2Fa9d7786d843709f1e0eba4c803b3e926 +0 -0
  73. data/test/dummy/tmp/cache/assets/D31/5E0/sprockets%2F138072f71f7bae615ff40a740e73a1bb +0 -0
  74. data/test/dummy/tmp/cache/assets/D32/A10/sprockets%2F13fe41fee1fe35b49d145bcc06610705 +0 -0
  75. data/test/dummy/tmp/cache/assets/D37/3D0/sprockets%2Fda69cb627e8723a40554434a5e9a3baa +0 -0
  76. data/test/dummy/tmp/cache/assets/D4A/320/sprockets%2F35053de8bfc618818a5ab98e51ef6b28 +0 -0
  77. data/test/dummy/tmp/cache/assets/D4E/1B0/sprockets%2Ff7cbd26ba1d28d48de824f0e94586655 +0 -0
  78. data/test/dummy/tmp/cache/assets/D53/5C0/sprockets%2Fe4fcc71e4933b8bffc17c869316c7719 +0 -0
  79. data/test/dummy/tmp/cache/assets/D5A/EA0/sprockets%2Fd771ace226fc8215a3572e0aa35bb0d6 +0 -0
  80. data/test/dummy/tmp/cache/assets/D6E/5B0/sprockets%2Fe70a8df5eea2403f7f21a0861d7673de +0 -0
  81. data/test/dummy/tmp/cache/assets/DB5/320/sprockets%2F0d355156da9bea1ea0dacd5a4e27513b +0 -0
  82. data/test/dummy/tmp/cache/assets/DDC/400/sprockets%2Fcffd775d018f68ce5dba1ee0d951a994 +0 -0
  83. data/test/dummy/tmp/cache/assets/E04/890/sprockets%2F2f5173deea6c795b8fdde723bb4b63af +0 -0
  84. data/test/dummy/tmp/cache/assets/E05/F10/sprockets%2Ffb396321cce1c7ea39cefed54f4a962e +0 -0
  85. data/test/dummy/tmp/pids/server.pid +1 -0
  86. data/test/fixtures/comments.yml +11 -0
  87. data/test/fixtures/notes.yml +13 -0
  88. data/test/functional/model_info_controller_test.rb +9 -0
  89. data/test/integration/navigation_test.rb +10 -0
  90. data/test/test_helper.rb +15 -0
  91. data/test/unit/comment_test.rb +7 -0
  92. data/test/unit/helpers/model_info_helper_test.rb +4 -0
  93. data/test/unit/note_test.rb +7 -0
  94. metadata +232 -0
@@ -0,0 +1,4 @@
1
+ /*
2
+ Place all the styles related to the matching controller here.
3
+ They will automatically be included in application.css.
4
+ */
@@ -0,0 +1,165 @@
1
+ class ModelInfoController < ApplicationController
2
+
3
+ #before_filter :get_models_info
4
+
5
+
6
+
7
+ before_filter :user_logged_in, :only => [:add_note, :add_comment]
8
+
9
+ def get_models_info
10
+ # The below line requires "cache_classes" to be "on"
11
+ # It seems it is "on" by default in Dev , but not in Prod
12
+ # See the following SO question & answers - http://stackoverflow.com/questions/516579/is-there-a-way-to-get-a-collection-of-all-the-models-in-your-rails-app
13
+ Rails.application.eager_load!
14
+ #Dir.glob(Rails.root.join('app/models/*')).each do |x|
15
+ # require x
16
+ #end
17
+ @models = ActiveRecord::Base.descendants
18
+ return @models
19
+ end
20
+
21
+ def DBNotes
22
+ Rails.application.eager_load!
23
+ @models = get_models_info
24
+ session[:username] = nil
25
+ end
26
+
27
+ <<-DOC
28
+ def show_notes_for_table
29
+ @table_name = params[:table]
30
+ @notes = Note.where(:table_name => @table_name)
31
+
32
+ render "index"
33
+ end
34
+ DOC
35
+
36
+
37
+ ################################################################################################
38
+ # Authentication using Jira REST Api
39
+ ################################################################################################
40
+
41
+ <<-DOC
42
+ # THis function is not being used at present..
43
+ def user_exists? (username, password)
44
+ # Below is the message returned when "Not already Authenticated in Jira"
45
+ # {"errorMessages":["You are not authenticated. Authentication required to perform this operation."],"errors":{}}
46
+
47
+ # Below is the message returned when "Already Authenticated in Jira"
48
+ # {"self":"https://jira2.icentris.com/jira/rest/api/latest/user?username=jyothiprasad.ponduru","name":"jyothiprasad.ponduru","loginInfo":{"failedLoginCount":15,"loginCount":278,"lastFailedLoginTime":"2013-04-18T05:49:07.054-0600","previousLoginTime":"2013-04-18T22:19:09.290-0600"}}
49
+ #!(jira(username, password).include? "not authenticated")
50
+ !(IcentrisJira::get_user_info(username, password).include? "not authenticated")
51
+ end
52
+ DOC
53
+
54
+ # This is called in before_filter for add_note() & add_comment()
55
+ def user_logged_in
56
+ if session[:username].blank?
57
+ render :json => "not logged in".to_json
58
+ else
59
+ true
60
+ end
61
+ end
62
+
63
+ <<-DOC
64
+ require 'net/http'
65
+
66
+ def jira(username, password)
67
+ #uri = URI.parse("https://jira2.icentris.com/jira/rest/auth/1/session/")
68
+ uri = URI.parse("https://jira2.icentris.com/jira/rest/api/2/user?username=" + username)
69
+ http = Net::HTTP.new(uri.host, uri.port)
70
+ http.use_ssl = true
71
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
72
+ request = Net::HTTP::Get.new(uri.request_uri)
73
+ request.basic_auth username, password
74
+ request["Content-Type"] = "application/json"
75
+ @jira_response = http.request(request)
76
+ return @jira_response.body
77
+ end
78
+ DOC
79
+
80
+ require 'IcentrisJira'
81
+ def user_authenticate
82
+ username = params[:username]
83
+ password = params[:password]
84
+ #jira_response = jira(username, password)
85
+ #jira_response = IcentrisJira::get_user_info(username, password) # Used IcentrisJira gem (which has the same code as jira() method above)
86
+ jira_response = IcentrisJira::getJSON("https://jira2.icentris.com/jira/rest/api/2/user?username=" + username, username, password)
87
+ if jira_response.include? "username="
88
+ session[:username] = jira_response.split('"displayName":')[1].split(",")[0]
89
+ render :json => "Authentication Successful".to_json # send back user's full name if authentication is successful
90
+ else
91
+ session[:username] = nil
92
+ render :json => "Authentication Failed".to_json # send back "Authentication Failed" if authentication has failed
93
+ end
94
+ end
95
+
96
+ ################################################################################################
97
+ # Below actions are called by Ajax calls and return JSON
98
+ ################################################################################################
99
+ def show_notes_for_column
100
+ @table_name = params[:table]
101
+ @column_name = params[:column]
102
+ @notes = Note.where(:table_name => @table_name, :column_name => @column_name)
103
+
104
+ #respond_to do |format|
105
+ #format.any(:xml, :html, :json) { render :json => @notes.to_json(:include => :comments) }
106
+ #end
107
+ render :json => @notes.to_json(:include => :comments)
108
+ end
109
+
110
+ def is_user_logged_in
111
+ logged_in_status = !session[:username].blank?
112
+ render :json => logged_in_status.to_json
113
+ end
114
+
115
+
116
+ def get_author_name
117
+ render :json => session[:username].to_json
118
+ end
119
+
120
+ def add_note
121
+ table_name = params[:table_name]
122
+ column_name = params[:column_name]
123
+ author = params[:author]
124
+ note_text = params[:note_text]
125
+ @n = Note.create :table_name => table_name, :column_name => column_name, :author => author, :note_text => note_text
126
+ respond_to do |format|
127
+ format.any(:xml, :html, :json) { render :json => @n.to_json }
128
+ end
129
+ end
130
+
131
+ def add_comment
132
+ #table_name = params[:table_name]
133
+ #column_name = params[:column_name]
134
+ author = params[:author]
135
+ comment_text = params[:comment_text]
136
+ note_id = params[:note_id]
137
+ @c = Comment.create :author => author, :comment_text => comment_text, :note_id => note_id
138
+ respond_to do |format|
139
+ format.any(:xml, :html, :json) { render :json => @c.to_json}
140
+ end
141
+ end
142
+
143
+
144
+ # This will be called on page-load via Ajax
145
+ def get_table_notes_count
146
+ # write code to that outputs some json
147
+ # {"table1": 21, "table2": 2,.....}
148
+ render :json => Note.find_by_sql("select table_name, count(*) as note_count from Notes group by table_name").to_json
149
+ end
150
+
151
+
152
+ # This will be called when user clicks on a particular table-name in the Accordion control
153
+ def get_column_notes_count_within_a_table (table_name)
154
+ # write code that outputs some json
155
+ # {"col1": 10, "col2": 5, "col3": 3,......}
156
+ render :json => Note.find_by_sql("select table_name, column_name, count(*) as note_count from Notes where table_name = ? group by table_name, column_name", table_name).to_json
157
+ end
158
+
159
+
160
+ def get_column_notes_count()
161
+ render :json => Note.find_by_sql("select table_name, column_name, count(*) as note_count from Notes group by table_name, column_name").to_json
162
+ end
163
+
164
+
165
+ end
@@ -0,0 +1,2 @@
1
+ module ModelInfoHelper
2
+ end
@@ -0,0 +1,4 @@
1
+ class Comment < ActiveRecord::Base
2
+ attr_accessible :author, :comment_text, :note_id
3
+ belongs_to :note
4
+ end
@@ -0,0 +1,4 @@
1
+ class Note < ActiveRecord::Base
2
+ attr_accessible :author, :column_name, :note_text, :table_name
3
+ has_many :comments
4
+ end
@@ -0,0 +1,418 @@
1
+ <script src="/assets/db_notes_engine2/bootstrap.js" type="text/javascript"></script>
2
+ <link href="/assets/db_notes_engine2/bootstrap.css" media="all" rel="stylesheet" type="text/css">
3
+
4
+ <style type="text/css">
5
+ /* This has been added below becuase the Search icon was not showing up */
6
+ .glyph {
7
+ background-image: url(/assets/db_notes_engine2/glyphicons-halflings.png);
8
+ }
9
+ .glyphw {
10
+ background-image: url(/assets/db_notes_engine2/glyphicons-halflings-white.png);
11
+ }
12
+ </style>
13
+
14
+ <div class="row">&nbsp;</div>
15
+ <div class="container">
16
+
17
+ <div class="row">
18
+ <div class="span3">
19
+ <span class="label label-info">Informal Database Documentation - </span> <span class="label label-warning">NOTEs and COMMENTs</span> <span class="badge badge-important">to share info about the Database</span>
20
+ </div>
21
+ <div class="span6">
22
+ <small>Type <b>Table-name</b> or <b>Column name : </b></small>
23
+
24
+ <input id="search" type="text" class="input-xlarge search-query" autocomplete="off" >
25
+
26
+ <button class="btn btn-primary" onclick="search2();"><i class="icon-search glyphw"></i> Search</button>
27
+ </div>
28
+
29
+ <div class="span3 text-right">
30
+ <img width="28" height="28" alt="" src="http://l.yimg.com/dh/ap/social/profile/profile_b32.png"> <span id="user_full_name" class="text-warning"> Anonymous User </span>
31
+ </div>
32
+
33
+ </div>
34
+ <div class="row">&nbsp;</div>
35
+ <div class="row" >
36
+
37
+ <div class="span3 accordion" id="accordion1">
38
+ <% @models.each do |m| %>
39
+ <% if !['Note', 'Comment'].include? m.to_s %> <!-- Exclude "Note", "Comment" tables since they are specific to DBNotes tool-->
40
+ <div class="accordion-group">
41
+ <div class="accordion-heading">
42
+ <a class="text-info" href="#collapse<%= m%>" class="accordion-toggle" data-toggle="collapse" data-parent="accordion1">&nbsp;<%= m %>&nbsp;<span class="caret" style="vertical-align: baseline"></span><span class="badge badge-warning pull-right" style="margin-right:15px" id="<%= m %>_note_count">0</span></a>
43
+ </div>
44
+ <div id="collapse<%= m%>" class="accordion-body collapse">
45
+ <div class="accordion-inner">
46
+ <ul>
47
+ <% m.column_names.each do |c| %>
48
+ <% unless ['id', 'created_at', 'updated_at'].include? c %>
49
+ <li><a id="<%= m %>_<%= c %>_link" class="text-success" href="#" onclick="update_breadcrumbs('<%= m %>', '<%= c %>');show_notes_for('<%= m %>', '<%= c %>');add_selected_icon(this);"><%= c %></a> <span class="badge badge-info pull-right" id="<%= m %>_<%= c %>_note_count">0</span></li>
50
+ <% end %>
51
+ <% end %>
52
+ </ul>
53
+ </div>
54
+ </div>
55
+ </div>
56
+ <% end %>
57
+ <% end %>
58
+ </div>
59
+ <div class="span9" >
60
+
61
+ <div class="row" style="padding-left:5px">
62
+ <ul class="breadcrumb" style="font-weight:bold; background-color:lightgoldenrodyellow">
63
+ <li><%= link_to "HOME", '/DBNotes' %></li>
64
+ <li id="table_name"> </li>
65
+ <li id="column_name" class="active"></li>
66
+ </ul>
67
+ </div>
68
+
69
+ <div class="row" id="middle_column" style="padding-left:5px">
70
+
71
+ </div>
72
+
73
+ <div class="row" id="AddNote" class="span9">
74
+ <span class="label label-info "> Add New Note </span>
75
+ <textarea name="newnote" id="newnote" rows="10" class="span9">(HTMLEditor goes here . For now it is a textarea.)</textarea><br>
76
+ <button class="btn btn-primary" type="button" onclick="javascript:addNote();">Add Note</button>
77
+ </div>
78
+
79
+
80
+ </div>
81
+
82
+ </div>
83
+ <div class="row text-center">
84
+ <br><br> <hr><h4>Footer goes here </h4><hr>
85
+ </div>
86
+ </div>
87
+
88
+
89
+ <script type="text/javascript">
90
+
91
+ function add_selected_icon(selected_link) {
92
+ $('.icon-ok').remove(); // Remove icon from previously selected link
93
+ $(selected_link).append('<i class="icon-ok glyph"></i>'); // Add icon to currently selected link
94
+ }
95
+
96
+ function update_breadcrumbs(model_name, column_name) {
97
+ jQuery('.breadcrumb').show();
98
+ jQuery('#table_name').html('<span class="divider">></span>' + model_name);
99
+ jQuery('#column_name').html('<span class="divider">></span>' + column_name);
100
+ }
101
+
102
+ function show_notes_for(model_name, column_name) {
103
+ // 1. Place Ajax call
104
+ // 2. Callback will populate #middle_column
105
+
106
+ jQuery.getJSON("/tables/" + model_name + "/columns/" + column_name + ".json", show_notes_for_CB);
107
+
108
+
109
+ function show_notes_for_CB (response) {
110
+ if (response.length == 0) { // if no Notes are present in DB, show message and return
111
+ jQuery('#middle_column').html('<h3 class="text-center"> No NOTES present for selected Column</h3><br>');
112
+ return;
113
+ }
114
+
115
+
116
+ jQuery('#middle_column').html(''); // empty out the Div (i.e. initialize to empty)
117
+ jQuery(response).each(function(i, ele) {
118
+ var html = "&nbsp;";
119
+ html = html + '<span class="label label-inverse "> &nbsp;&nbsp;' + (i+1) + '&nbsp;&nbsp; </span>';
120
+ html = html + '<span class="label label-inverse pull-right"> ' + ele.author + ' , &nbsp;' + ele.updated_at +' </span>';
121
+ html = html + '<div class="well">';
122
+
123
+ html = html + '<p>' + ele.note_text + '</p>' ; // Use <p> element to show Note's text
124
+ //html = html + '<p class="text-right"><small> - ' + ele.author + ' , &nbsp;' + ele.updated_at + '</small></p>'; // Use <p> element to show Note's author and date
125
+
126
+ // If Note has Comments, create <p> element for each Comment, and append them
127
+ if (ele.comments.length != 0) {
128
+ jQuery(ele.comments).each( function(i, c_ele) {
129
+ html = html + '<hr>' ;
130
+ html = html + '<p style="font-size:x-small">' + c_ele.comment_text + ' &nbsp;&nbsp;- ' + c_ele.author +', &nbsp;' + c_ele.updated_at + '</p>';
131
+ });
132
+ }
133
+
134
+ html = html + '<hr><a href="#" onclick="show_AddCommentDiv('+ ele.id + ');return false;"><small>Add Comment</small></a>'; // for "Add Comment" link
135
+ html = html + '<div id="newcommentdiv' + ele.id +'" style="display:none">' ; // Add a Div that contains TextArea & Button to add a new comment
136
+ html = html + '<textarea rows="5" class="span8"></textarea>';
137
+ html = html + '<br>';
138
+ html = html + '<button onclick="addComment(' + ele.id + ')" class="btn btn-primary">Add Comment</button>&nbsp; &nbsp; ';
139
+ html = html + '<button onclick="hide_addCommentDiv(' + ele.id + ');" class="btn btn-danger">Cancel</button>' ;
140
+ html = html + '</div>' ;
141
+ html = html + '</div>';
142
+ jQuery('#middle_column').append(html);
143
+ });
144
+
145
+
146
+ UI();
147
+
148
+ }
149
+
150
+ }
151
+
152
+ function UI() {
153
+ // Give some color to Notes & Comments & "Add Comment" link
154
+ jQuery('.well').each(function(i, ele) {
155
+ if (i%2 == 0) {
156
+ $(ele).addClass("badge-important");
157
+ $(ele).css("color","whitesmoke");
158
+ $(ele).find('a:contains("Add Comment")').css("color","orange").css("font-weight", "bold");
159
+ }
160
+ else {
161
+ $(ele).addClass("badge-warning");
162
+ $(ele).find('a:contains("Add Comment")').css("color","navyblue").css("font-weight", "bold");
163
+ }
164
+ });
165
+ }
166
+
167
+
168
+ function addNote() {
169
+
170
+ var user_logged_in = get_login_status();
171
+
172
+ if (!user_logged_in) {
173
+ show_login_dialog();
174
+ return ;
175
+ }
176
+
177
+
178
+ var table_name = $('li#table_name').text().substr(1) ; // Get TableName (strip off the last character which is > )
179
+ var column_name = $('li#column_name').text().substr(1) ;
180
+ //var author = 'Sai Ponduru';
181
+ author = get_author_name();
182
+ var note_text = $('#newnote').val();
183
+ jQuery.getJSON('/add_note?table_name=' + table_name + '&column_name=' + column_name + '&author=' + author + '&note_text=' + note_text, addNote_CB);
184
+
185
+ function addNote_CB (response) {
186
+ if (response == "not logged in") {
187
+ show_login_dialog();
188
+ return ;
189
+ }
190
+
191
+ var ele = response;
192
+ //var ele = {"author":"Sai Ponduru","column_name":"note_id","created_at":"2013-04-11T04:55:40Z","id":37,"note_text":"s","table_name":"Comment","updated_at":"2013-04-11T04:55:40Z"};
193
+ $('#newnote').val('');
194
+ $('#' + ele.table_name + "_" + ele.column_name + "_link").click();
195
+ update_note_count();
196
+ }
197
+ }
198
+
199
+
200
+ function show_AddCommentDiv( note_id) {
201
+
202
+ //$(link_element).parent().append('<div id="newcomment_div><textarea id="newcomment">This is a new comment</textarea><br><button onclick="addComment(' + link_element + ',' + note_id + ')">Add Comment</button></div>');
203
+ jQuery('#newcommentdiv' + note_id).show();
204
+
205
+ }
206
+
207
+ function hide_addCommentDiv(note_id){
208
+ jQuery('#newcommentdiv' + note_id).hide();
209
+ }
210
+
211
+
212
+ function addComment( note_id) {
213
+
214
+ var user_logged_in = get_login_status();
215
+
216
+ if (!user_logged_in) {
217
+ show_login_dialog();
218
+ return ;
219
+ }
220
+
221
+ author = get_author_name();
222
+
223
+ //var author = 'Sai Ponduru';
224
+ var comment_text = $('#newcommentdiv' + note_id + '> textarea').val();
225
+ jQuery.getJSON('/add_comment?author=' + author + '&note_id=' + note_id + '&comment_text=' + comment_text, addComment_CB);
226
+
227
+ function addComment_CB (response) {
228
+ if (response == "not logged in") {
229
+ show_login_dialog();
230
+ return ;
231
+ }
232
+
233
+ // response contains json data of newly added comment - we are using data received from the server (instead of taking it from the textarea element) in order to make sure that the comment got saved on the server side ;
234
+ var ele = response;
235
+
236
+ // construct html for the new comment to be appended
237
+ var html = "";
238
+ html = html + '<p style="font-size:x-small">' + ele.comment_text + ' &nbsp;&nbsp;- ' + ele.author +', &nbsp;' + ele.updated_at + '</p>';
239
+ html = html + '<hr>' ;
240
+
241
+ // append the above constructed html
242
+ var last_comments_hr = $('#newcommentdiv' + note_id).parent().find('hr').last(); // find last comment's hr
243
+ $(html).insertAfter(last_comments_hr); // insert new comment after the last comment's hr
244
+ $('#newcommentdiv' + note_id).hide(); // hide textarea & button to add new comment
245
+ $('#newcommentdiv' + note_id + '>textarea').val(''); //clear textarea's contents
246
+
247
+ UI();
248
+ update_note_count();
249
+ }
250
+
251
+ }
252
+
253
+ function get_login_status() {
254
+ var user_logged_in = false;
255
+ //jQuery.getJSON('/is_user_logged_in', function(response){ user_logged_in = response; alert(response);});
256
+ $.ajax({
257
+ url: '/is_user_logged_in',
258
+ dataType: 'json',
259
+ async: false,
260
+ success: function(response){ user_logged_in = response; }
261
+ });
262
+ return user_logged_in;
263
+ }
264
+
265
+ function get_author_name() {
266
+ author = "Anonymous User";
267
+ //if (get_login_status()) {
268
+ //jQuery.getJSON('/get_author_name', function(response){ author = response.replace(/"/g,''); });
269
+ $.ajax({
270
+ url: '/get_author_name',
271
+ dataType: 'json',
272
+ async: false,
273
+ success: function(response){ author = response.replace(/"/g,''); }
274
+ });
275
+ //}
276
+ return author;
277
+ }
278
+
279
+
280
+
281
+ </script>
282
+
283
+ <script type="text/javascript">
284
+ if (<%= @table_name.blank? %>) {
285
+ // Click on the 1st Table's 1st column in Accordion control
286
+ $('.accordion a')[0].click();
287
+ $('.accordion-inner a')[0].click();
288
+ }
289
+ </script>
290
+
291
+ <script type="text/javascript">
292
+ var arr = [];
293
+ <% @models.each do |m| %>
294
+ <% unless ['Note', 'Comment'].include? m.to_s %>
295
+ <% m.column_names.each do |c| %>
296
+ <% unless ['id', 'created_at', 'updated_at'].include? c %>
297
+ arr.push ('<%= (m.to_s + ":" + c.to_s) %>');
298
+ <% end %>
299
+ <% end %>
300
+ <%end%>
301
+ <% end %>
302
+ $('#search').typeahead({source: arr});
303
+
304
+ function search2() {
305
+ reset_accordion();
306
+ setTimeout("",2000);
307
+
308
+ var table_name = $('#search').val().split(":")[0] ;
309
+ var column_name = $('#search').val().split(":")[1] ;
310
+
311
+ var table_name_link = $(".accordion a:contains(" + table_name + ")"); // Find the <a> tag that contains the 'table name' as its text
312
+ table_name_link.click();
313
+
314
+ // To find the column-name, below search is happening within the current Table (because the same column name could be in 2 tables)
315
+ // The <a> tag for a column-name can be found by going to the next div of tablename's link's parent-div
316
+
317
+ var column_name_link = table_name_link.parent().next().find("a:contains(" + column_name + ")");
318
+ column_name_link.click();
319
+ }
320
+ </script>
321
+
322
+
323
+ <div id="myModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
324
+ <div class="modal-header">
325
+ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
326
+ <h3 id="myModalLabel">Login using JIRA credentials</h3>
327
+ </div>
328
+ <div class="modal-body">
329
+
330
+ <label for="username"> Username: </label><input type="text" id="username" name="username"/><br>
331
+ <label for="password"> Password: </label><input type="password" id="password" name="password"/><br>
332
+ <div class="pull-left">
333
+ <button class="btn btn-primary" onclick="javascript:authenticate_with_Jira();">Login</button>
334
+ <button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
335
+ </div>
336
+ </div>
337
+
338
+ <div class="modal-footer">
339
+ <p id="login_feedback" class="text-center" style="font-size:1.4em">To add a Note / Comment, you have to login.</p>
340
+ </div>
341
+ </div>
342
+
343
+ <script type="text/javascript">
344
+
345
+ function show_login_dialog() {
346
+ $('#myModal').modal('show');
347
+ }
348
+
349
+ function authenticate_with_Jira() {
350
+
351
+ // send ajax request to ModelInfo#jira
352
+ // if unsuccessful, update #login_feedback to say - "Tried authenticating with - https://jira2.icentris.com/jira/rest/api/2/user?username=" + username ....Login unsuccessful.. "
353
+ var username = $('#username').val();
354
+ var password = $('#password').val();
355
+ $.getJSON('/user_authenticate?username=' + username + '&password=' + password, authenticate_with_Jira_CB );
356
+ $('#login_feedback').html("<p class='text-info'>Authentication in progress ...</p>");
357
+
358
+ function authenticate_with_Jira_CB(response) {
359
+
360
+ if (response.indexOf("Authentication Failed") >= 0)
361
+ $('#login_feedback').html("<p class='text-warning'>" + response + " </p><b> Please try again.</b>");
362
+ else {
363
+ $('#login_feedback').html("<p class='text-success'> Login Successful!. </p> <p class='text-warning'> Click 'Add Note/Comment' again </p>");
364
+ setTimeout("$('#username').val(''); $('#password').val(''); $('#myModal').modal('hide');", 3000);
365
+ author = get_author_name();
366
+ $('#user_full_name').html(author);
367
+ }
368
+
369
+ }
370
+
371
+ }
372
+
373
+ </script>
374
+
375
+
376
+ <script type="text/javascript">
377
+
378
+ function update_note_count() {
379
+
380
+ $.getJSON('/get_table_notes_count', function(response){
381
+ /* Example JSON response from server :
382
+ [{"note_count":2,"table_name":null},{"note_count":46,"table_name":"Comment"},{"note_count":4,"table_name":"Note"},{"note_count":21,"table_name":"Table1"},{"note_count":2,"table_name":"Table2"}]
383
+ */
384
+ $(response).each(function() {
385
+ var table_name = this.table_name;
386
+ var note_count = this.note_count;
387
+ $('#' + table_name + '_note_count').html(note_count);
388
+ });
389
+ });
390
+
391
+ //$.getJSON('/get_table_notes_count', function(response){
392
+ $.getJSON('/get_column_notes_count', function(response){
393
+ /* Example JSON response from server :
394
+ [{"column_name":null,"note_count":2,"table_name":null},{"column_name":"author","note_count":11,"table_name":"Comment"},{"column_name":"comment_text","note_count":5,"table_name":"Comment"},{"column_name":"note_id","note_count":30,"table_name":"Comment"},{"column_name":"author","note_count":2,"table_name":"Note"},{"column_name":"table_name","note_count":2,"table_name":"Note"},{"column_name":"col1","note_count":15,"table_name":"Table1"},{"column_name":"col2","note_count":2,"table_name":"Table1"},{"column_name":"col3","note_count":2,"table_name":"Table1"},{"column_name":"col4","note_count":2,"table_name":"Table1"},{"column_name":"col1","note_count":2,"table_name":"Table2"}]
395
+ */
396
+ $(response).each(function() {
397
+ var table_name = this.table_name;
398
+ var column_name = this.column_name;
399
+ var note_count = this.note_count;
400
+ $('#' + table_name + '_' + column_name + '_note_count').html(note_count);
401
+ });
402
+ });
403
+
404
+ }
405
+
406
+ update_note_count();
407
+
408
+
409
+ </script>
410
+
411
+ <script type="text/javascript">
412
+ function reset_accordion() {
413
+ // collapse all 'tables' that are expanded
414
+ $('div[class*=collapse][class*=in][class*=accordion-body]').parent().find('div.accordion-heading a').click();
415
+ }
416
+ </script>
417
+
418
+
data/config/routes.rb ADDED
@@ -0,0 +1,32 @@
1
+ Rails.application.routes.draw do
2
+ get "model_info/DBNotes"
3
+
4
+ #get "model_info/index"
5
+
6
+ get "DBNotes" => "ModelInfo#DBNotes"
7
+
8
+ match 'tables/:table/columns/:column', to: "ModelInfo#show_notes_for_column", as: "table_column"
9
+
10
+ match 'add_note', to: "ModelInfo#add_note"
11
+
12
+ match 'add_comment', to: "ModelInfo#add_comment"
13
+
14
+ match 'get_login_status', to: "ModelInfo#user_logged_in"
15
+
16
+ match 'user_authenticate', to: "ModelInfo#user_authenticate"
17
+
18
+ match 'is_user_logged_in', to: "ModelInfo#is_user_logged_in"
19
+
20
+ match 'get_author_name', to: "ModelInfo#get_author_name"
21
+
22
+ match 'get_table_notes_count', to: "ModelInfo#get_table_notes_count"
23
+
24
+ match 'get_column_notes_count', to: "ModelInfo#get_column_notes_count"
25
+
26
+ match 'get_column_notes_count_within_a_table', to: "ModelInfo#get_column_notes_count_within_a_table"
27
+
28
+ resources :notes do
29
+ resources :comments
30
+ end
31
+
32
+ end
@@ -0,0 +1,12 @@
1
+ class CreateNotes < ActiveRecord::Migration
2
+ def change
3
+ create_table :notes do |t|
4
+ t.string :author
5
+ t.string :column_name
6
+ t.text :note_text
7
+ t.string :table_name
8
+
9
+ t.timestamps
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ class CreateComments < ActiveRecord::Migration
2
+ def change
3
+ create_table :comments do |t|
4
+ t.string :author
5
+ t.text :comment_text
6
+ t.integer :note_id
7
+
8
+ t.timestamps
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,4 @@
1
+ module DbNotesEngine2
2
+ class Engine < ::Rails::Engine
3
+ end
4
+ end
@@ -0,0 +1,3 @@
1
+ module DbNotesEngine2
2
+ VERSION = "0.0.1"
3
+ end