insight_rails 0.1.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 (48) hide show
  1. data/README.md +43 -0
  2. data/Rakefile +15 -0
  3. data/VERSION +1 -0
  4. data/app/controllers/help/categories_controller.rb +11 -0
  5. data/app/controllers/help/comments_controller.rb +22 -0
  6. data/app/controllers/help/issues_controller.rb +53 -0
  7. data/app/controllers/help/sessions_controller.rb +40 -0
  8. data/app/controllers/help_controller.rb +10 -0
  9. data/app/controllers/insight_controller.rb +32 -0
  10. data/app/controllers/knowledge/article_categories_controller.rb +13 -0
  11. data/app/controllers/knowledge/articles_controller.rb +11 -0
  12. data/app/helpers/help/issues_helper.rb +15 -0
  13. data/app/models/article.rb +11 -0
  14. data/app/models/article_category.rb +11 -0
  15. data/app/models/category.rb +11 -0
  16. data/app/models/category_issue.rb +10 -0
  17. data/app/models/comment.rb +26 -0
  18. data/app/models/insight_user.rb +19 -0
  19. data/app/models/issue.rb +30 -0
  20. data/app/models/lead.rb +15 -0
  21. data/app/views/help/categories/index.html.erb +29 -0
  22. data/app/views/help/comments/_form.html.erb +25 -0
  23. data/app/views/help/index.html.erb +0 -0
  24. data/app/views/help/issues/_form.html.erb +43 -0
  25. data/app/views/help/issues/index.html.erb +42 -0
  26. data/app/views/help/issues/new.html.erb +3 -0
  27. data/app/views/help/issues/show.html.erb +39 -0
  28. data/app/views/help/sessions/new.html.erb +20 -0
  29. data/app/views/knowledge/article_categories/index.html.erb +16 -0
  30. data/app/views/knowledge/articles/show.html.erb +3 -0
  31. data/app/views/layouts/_insight_footer.html.erb +25 -0
  32. data/app/views/layouts/insight_layout.html.erb +56 -0
  33. data/config/routes.rb +42 -0
  34. data/generators/insight/insight_generator.rb +26 -0
  35. data/generators/insight/lib/insert_commands.rb +33 -0
  36. data/generators/insight/templates/README +0 -0
  37. data/generators/insight/templates/insight.rake +26 -0
  38. data/generators/insight/templates/insight.rb +7 -0
  39. data/generators/insight/templates/insight.sass +284 -0
  40. data/generators/insight/templates/migrations/link_users_to_crm_contacts.rb +13 -0
  41. data/lib/insight/configuration.rb +28 -0
  42. data/lib/insight/crm/callbacks/account.rb +39 -0
  43. data/lib/insight/crm/callbacks/user.rb +53 -0
  44. data/lib/insight/crm/models/account.rb +17 -0
  45. data/lib/insight/crm/models/contact.rb +17 -0
  46. data/lib/insight/multi_pass_attributes.rb +32 -0
  47. data/lib/insight.rb +3 -0
  48. metadata +140 -0
data/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # Insight
2
+
3
+ Rails engine to access support requests and knowledge base articles stored in FatFree CRM.
4
+
5
+ ## Installation
6
+
7
+ Add insight to your applications dependencies.
8
+
9
+ For Rails 2
10
+
11
+ gem.config "insight_rails", :lib => "insight"
12
+
13
+ For those using bundler
14
+
15
+ gem "insight_rails", :require => "insight"
16
+
17
+ Make sure your development database exists and run the generator:
18
+
19
+ script/generate insight
20
+
21
+ Firstly, run the migration to add the crm_id field to your users table.
22
+
23
+ Then update the insight initializer with details of your api_key, fatfree's url and your recaptcha keys.
24
+
25
+ ## Usage
26
+
27
+ You will now have a knowledge base of articles from your fat free installation available at:
28
+
29
+ /knowledge
30
+
31
+ You will also have a support page available at:
32
+
33
+ /help
34
+
35
+ Discussions can be viewed at:
36
+
37
+ /help/browse
38
+
39
+ This will pull through the issue_categories you setup in Fat Free.
40
+
41
+ ## Copyright
42
+
43
+ Copyright (c) 2010 Kieran Johnson. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ require 'jeweler'
2
+
3
+ Jeweler::Tasks.new do |gem|
4
+ gem.name = "insight_rails"
5
+ gem.summary = "Customer Support and Knowledge Base"
6
+ gem.description = "Customer Support and Knowledge Base"
7
+ gem.email = "support@invisiblelines.com"
8
+ gem.homepage = "http://github.com/kieranj/insight"
9
+ gem.authors = ["Kieran Johnson"]
10
+ gem.files = FileList["[A-Z]*", "{app,config,generators,lib,rails}/**/*"]
11
+ gem.add_dependency "recaptcha"
12
+ gem.add_dependency "gravtastic"
13
+ end
14
+
15
+ Jeweler::GemcutterTasks.new
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.1
@@ -0,0 +1,11 @@
1
+ class Help::CategoriesController < InsightController
2
+
3
+ skip_before_filter :login_required
4
+
5
+ layout Insight.configuration.layout
6
+
7
+ def index
8
+ @categories = Category.find(:all)
9
+ end
10
+
11
+ end
@@ -0,0 +1,22 @@
1
+ class Help::CommentsController < InsightController
2
+
3
+ skip_before_filter :login_required
4
+
5
+ def create
6
+ @comment = Comment.new(params[:comment].merge(defaults))
7
+ if verify_recaptcha(:model => @comment, :private_key => Insight.configuration.recaptcha_private_key) && @comment.save
8
+ redirect_to(help_issue_path(@comment.issue.to_param))
9
+ else
10
+ redirect_to(help_issue_path(@comment.issue.to_param))
11
+ end
12
+ end
13
+
14
+ protected
15
+
16
+ def defaults
17
+ {
18
+ :issue_id => params[:issue_id]
19
+ }
20
+ end
21
+
22
+ end
@@ -0,0 +1,53 @@
1
+ class Help::IssuesController < InsightController
2
+
3
+ layout Insight.configuration.layout
4
+
5
+ skip_before_filter :login_required
6
+
7
+ def my
8
+ @issues = Issue.get(:my, :crm_id => current_user.crm_id)
9
+ render :action => "index"
10
+ end
11
+
12
+ def index
13
+ if params[:category_id]
14
+ @category = Category.find(params[:category_id])
15
+ @issues = @category.issues
16
+ else
17
+ @issues = Issue.find(:all)
18
+ end
19
+ end
20
+
21
+ def show
22
+ @issue = Issue.find(params[:id])
23
+ end
24
+
25
+ def new
26
+ @issue = Issue.new
27
+ end
28
+
29
+ def create
30
+ @issue = Issue.new(params[:issue])
31
+ @issue.contact_id = current_user.crm_id if logged_in? && !current_user.crm_id.nil?
32
+
33
+ if verify_recaptcha(:model => @issue, :private_key => Insight.configuration.recaptcha_private_key) && @issue.save
34
+ redirect_to(help_issue_path(@issue))
35
+ else
36
+ render :action => "new"
37
+ end
38
+ end
39
+
40
+ def edit
41
+ @issue = Issue.find(params[:id])
42
+ end
43
+
44
+ def update
45
+ @issue = Issue.find(params[:id])
46
+ if verify_recaptcha(:model => @issue, :private_key => Insight.configuration.recaptcha_private_key) && @issue.update_attributes(params[:issue].merge(:contact_id => current_user.crm_id))
47
+ redirect_to(help_issues_path)
48
+ else
49
+ render :action => "edit"
50
+ end
51
+ end
52
+
53
+ end
@@ -0,0 +1,40 @@
1
+ class Help::SessionsController < ApplicationController
2
+
3
+ layout Insight.configuration.layout
4
+
5
+ skip_before_filter :login_required
6
+
7
+ before_filter :check_existing_login, :only => [ :new ]
8
+
9
+ # def new
10
+ # end
11
+ #
12
+ # def create
13
+ # json = { :username => params[:username], :password => params[:password] }.to_json
14
+ # auth_details = MultiPass.encode64(json)
15
+ #
16
+ # session = InsightSession.new(:auth => auth_details)
17
+ # if session.save
18
+ # self.current_user = session.multipass
19
+ # else
20
+ # render :action => "new"
21
+ # end
22
+ # end
23
+
24
+ def destroy
25
+ session[:multipass] = nil
26
+ redirect_to("/help")
27
+ end
28
+
29
+ protected
30
+
31
+ def check_existing_login
32
+ if logged_in?
33
+ session[:multipass] = current_user.multipass
34
+ redirect_to("/help")
35
+ else
36
+ redirect_to(login_path(:to => "/help"))
37
+ end
38
+ end
39
+
40
+ end
@@ -0,0 +1,10 @@
1
+ class HelpController < InsightController
2
+
3
+ skip_before_filter :login_required
4
+
5
+ layout Insight.configuration.layout
6
+
7
+ def index
8
+ end
9
+
10
+ end
@@ -0,0 +1,32 @@
1
+ class InsightController < ApplicationController
2
+
3
+ before_filter :login_required
4
+
5
+ def current_user
6
+ @insight_user ||= login_from_multipass
7
+ end
8
+
9
+ def current_user=(multipass)
10
+ session[:multipass] = multipass
11
+ @insight_user = login_from_multipass
12
+ end
13
+
14
+ def authorized?
15
+ logged_in?
16
+ end
17
+
18
+ def logged_in?
19
+ !!current_user
20
+ end
21
+
22
+ protected
23
+
24
+ def login_required
25
+ authorized?
26
+ end
27
+
28
+ def login_from_multipass
29
+ session[:multipass].nil? ? nil : InsightUser.new(session[:multipass])
30
+ end
31
+
32
+ end
@@ -0,0 +1,13 @@
1
+ class Knowledge::ArticleCategoriesController < ApplicationController
2
+
3
+ skip_before_filter :login_required
4
+
5
+ layout Insight.configuration.layout
6
+
7
+ def index
8
+ @categories = ArticleCategory.find(:all)
9
+ @latest_articles = Article.get(:latest)
10
+ @latest_issues = Issue.get(:latest)
11
+ end
12
+
13
+ end
@@ -0,0 +1,11 @@
1
+ class Knowledge::ArticlesController < ApplicationController
2
+
3
+ skip_before_filter :login_required
4
+
5
+ layout Insight.configuration.layout
6
+
7
+ def show
8
+ @article = Article.find(params[:id])
9
+ end
10
+
11
+ end
@@ -0,0 +1,15 @@
1
+ module Help::IssuesHelper
2
+
3
+ def posted_on_long(date)
4
+ date.strftime("%B #{date.day.ordinalize} %Y") + " at " + date.strftime("%H:%M%p").downcase
5
+ end
6
+
7
+ def posted_on_short(date)
8
+ date.strftime("%B #{date.day.ordinalize}, %Y %H:%M") + date.strftime("%p").downcase
9
+ end
10
+
11
+ def comment_by(comment)
12
+ "staff" if comment.commenter_type == "User"
13
+ end
14
+
15
+ end
@@ -0,0 +1,11 @@
1
+ class Article < ActiveResource::Base
2
+
3
+ headers["X-ApiKey"] = Insight.configuration.api_key
4
+
5
+ self.site = Insight.configuration.fat_free_url
6
+
7
+ def to_param
8
+ slug
9
+ end
10
+
11
+ end
@@ -0,0 +1,11 @@
1
+ class ArticleCategory < ActiveResource::Base
2
+
3
+ headers["X-ApiKey"] = Insight.configuration.api_key
4
+
5
+ self.site = Insight.configuration.fat_free_url
6
+
7
+ def to_param
8
+ slug
9
+ end
10
+
11
+ end
@@ -0,0 +1,11 @@
1
+ class Category < ActiveResource::Base
2
+
3
+ headers["X-ApiKey"] = Insight.configuration.api_key
4
+
5
+ self.site = Insight.configuration.fat_free_url
6
+
7
+ def to_param
8
+ slug
9
+ end
10
+
11
+ end
@@ -0,0 +1,10 @@
1
+ class CategoryIssue < ActiveResource::Base
2
+
3
+ self.site = Insight.configuration.fat_free_url + "/categories/:category_id"
4
+ self.element_name = "issue"
5
+
6
+ def to_param
7
+ slug
8
+ end
9
+
10
+ end
@@ -0,0 +1,26 @@
1
+ class Comment < ActiveResource::Base
2
+
3
+ headers["X-ApiKey"] = Insight.configuration.api_key
4
+
5
+ self.site = Insight.configuration.fat_free_url + "/issues/:issue_id"
6
+
7
+ include Gravtastic
8
+ gravtastic :user_email
9
+
10
+ def user_name
11
+ if commenter_id
12
+ commenter.username
13
+ else
14
+ super
15
+ end
16
+ end
17
+
18
+ def user_email
19
+ if commenter_id
20
+ commenter.email
21
+ else
22
+ super
23
+ end
24
+ end
25
+
26
+ end
@@ -0,0 +1,19 @@
1
+ class InsightUser
2
+
3
+ def initialize(multipass)
4
+ @multipass_attributes = self.class.multipass.decode(multipass)
5
+ end
6
+
7
+ def method_missing(method, *args, &block)
8
+ if @multipass_attributes.keys.include?(method)
9
+ @multipass_attributes[method]
10
+ else
11
+ super
12
+ end
13
+ end
14
+
15
+ def self.multipass
16
+ @multipass ||= MultiPass.new('fatfree', 'abc')
17
+ end
18
+
19
+ end
@@ -0,0 +1,30 @@
1
+ class Issue < ActiveResource::Base
2
+
3
+ headers["X-ApiKey"] = Insight.configuration.api_key
4
+
5
+ self.site = Insight.configuration.fat_free_url
6
+
7
+ include Gravtastic
8
+ gravtastic :user_email
9
+
10
+ def to_param
11
+ "#{slug}-#{id}"
12
+ end
13
+
14
+ def user_name
15
+ if contact_id
16
+ contact.username
17
+ else
18
+ super
19
+ end
20
+ end
21
+
22
+ def user_email
23
+ if contact_id
24
+ contact.email
25
+ else
26
+ super
27
+ end
28
+ end
29
+
30
+ end
@@ -0,0 +1,15 @@
1
+ class Lead < ActiveResource::Base
2
+
3
+ headers["X-ApiKey"] = Insight.configuration.api_key
4
+
5
+ self.site = Insight.configuration.fat_free_url
6
+
7
+ attr_accessor :password, :password_confirmation
8
+
9
+ def validate
10
+ self.errors.add(:email, "Is required") if email.nil?
11
+ self.errors.add(:password, "Is required") if password.nil?
12
+ self.errors.add(:password_confirmation, "Must match password") if password != password_confirmation
13
+ end
14
+
15
+ end
@@ -0,0 +1,29 @@
1
+ <h1>Public Discussions</h1>
2
+
3
+ <h2>Welcome to the discussion area. You can browse public discussions or start your own discussion in a category of your choosing.</h2>
4
+
5
+ <table>
6
+ <thead>
7
+ <tr>
8
+ <th width="790">Category</th>
9
+ <th width="150">Latest Post</th>
10
+ </tr>
11
+ </thead>
12
+ <tbody>
13
+ <% @categories.each do |category| -%>
14
+ <tr class="<%= cycle(:odd, :even) %>">
15
+ <td>
16
+ <h2><%= link_to(category.name, help_category_issues_path(category)) %></h2>
17
+ <%= simple_format(category.description) %>
18
+ </td>
19
+ <td>
20
+ <% if !category.issues.empty? -%>
21
+ <%= link_to(category.issues.first.updated_at.strftime("%b %d, %Y %H:%M"),
22
+ help_category_issue_path(category, category.issues.first)) %>
23
+ by <%= category.issues.first.user_name %>
24
+ <% end -%>
25
+ </td>
26
+ </tr>
27
+ <% end -%>
28
+ </tbody>
29
+ </table>
@@ -0,0 +1,25 @@
1
+ <% form_tag(help_issue_comments_path(@issue), :class => "formtastic") do %>
2
+ <fieldset class="inputs">
3
+ <ol>
4
+ <% if !logged_in? -%>
5
+ <li class="string">
6
+ <%= label_tag "comment[user_name]", "Name" %>
7
+ <%= text_field_tag "comment[user_name]" %>
8
+ </li>
9
+ <li class="string">
10
+ <%= label_tag "comment[user_email]", "Email" %>
11
+ <%= text_field_tag "comment[user_email]" %>
12
+ </li>
13
+ <% end -%>
14
+ <li class="text">
15
+ <%= text_area_tag "comment[comment]" %>
16
+ </li>
17
+ </ol>
18
+ </fieldset>
19
+
20
+ <%= recaptcha_tags :public_key => Insight.configuration.recaptcha_public_key %>
21
+
22
+ <fieldset class="buttons">
23
+ <%= submit_tag("Post Comment") %>
24
+ </fieldset>
25
+ <% end %>
File without changes
@@ -0,0 +1,43 @@
1
+ <% form_tag(help_issues_path, :class => "formtastic") do %>
2
+ <fieldset class="inputs">
3
+ <ol>
4
+ <% if !logged_in? -%>
5
+ <li class="string">
6
+ <%= label_tag "issue[user_name]", "Name" %>
7
+ <%= text_field_tag "issue[user_name]" %>
8
+ </li>
9
+ <li class="string">
10
+ <%= label_tag "issue[user_email]", "Email" %>
11
+ <%= text_field_tag "issue[user_email]" %>
12
+ </li>
13
+ <% end -%>
14
+ <li class="select">
15
+ <%= label_tag "issue[category_id]", "Category" %>
16
+ <%= select_tag "issue[category_id]",
17
+ options_from_collection_for_select(Category.find(:all), :id, :name),
18
+ :prompt => "Please select" %>
19
+ </li>
20
+ <li class="string">
21
+ <%= label_tag "issue[subject]", "Subject" %>
22
+ <%= text_field_tag "issue[subject]" %>
23
+ </li>
24
+ <li class="text">
25
+ <%= text_area_tag "issue[body]" %>
26
+ </li>
27
+ <% if logged_in? -%>
28
+ <li class="boolean">
29
+ <label>
30
+ <%= check_box_tag "issue[private]" %>
31
+ Mark this issue as private. Only allow support representatives to see it.
32
+ </label>
33
+ </li>
34
+ <% end -%>
35
+ </ol>
36
+ </fieldset>
37
+
38
+ <%= recaptcha_tags :public_key => Insight.configuration.recaptcha_public_key %>
39
+
40
+ <fieldset class="buttons">
41
+ <%= submit_tag("Post Issue") %>
42
+ </fieldset>
43
+ <% end %>
@@ -0,0 +1,42 @@
1
+ <h1><%= @category.name %></h1>
2
+ <h2><%= @category.description %></h2>
3
+
4
+ <%= link_to("Create New Issue", new_help_issue_path, :class => "button") %>
5
+
6
+ <table>
7
+ <thead>
8
+ <tr>
9
+ <th width="590">Topic</th>
10
+ <th width="60">State</th>
11
+ <th width="60">Replies</th>
12
+ <th width="180">Latest Post</th>
13
+ </tr>
14
+ </thead>
15
+ <tbody>
16
+ <% @issues.each do |issue| %>
17
+ <tr class="<%= cycle(:odd, :even) %>">
18
+ <td>
19
+ <h2><%= link_to(issue.subject, help_issue_path(issue)) %></h2>
20
+ <p>Started by <%= issue.user_name %></p>
21
+ </td>
22
+ <td>
23
+ <%= issue.state %>
24
+ </td>
25
+ <td>
26
+ <%= issue.comments.count %>
27
+ </td>
28
+ <td>
29
+ <% if issue.comments.empty? %>
30
+ <%= link_to(posted_on_short(issue.created_at), help_issue_path(issue)) %>
31
+ <br />
32
+ <%= issue.user_name %>
33
+ <% else %>
34
+ <%= link_to(posted_on_short(issue.comments.last.updated_at), help_issue_path(issue)) %>
35
+ <br />
36
+ <%= issue.comments.last.user_name %>
37
+ <% end %>
38
+ </td>
39
+ </tr>
40
+ <% end %>
41
+ </tbody>
42
+ </table>
@@ -0,0 +1,3 @@
1
+ <h1>New Issue</h1>
2
+
3
+ <%= render :partial => "help/issues/form" %>
@@ -0,0 +1,39 @@
1
+ <div class="issue">
2
+ <h2><strong>Subject</strong> : <%= @issue.subject %></h2>
3
+
4
+ <div class="author">
5
+ <%= image_tag(@issue.gravatar_url(:size => 30)) %>
6
+ <p>Posted by <cite><%= @issue.user_name %></cite> on <%= posted_on_long(@issue.updated_at) %></p>
7
+ </div>
8
+
9
+ <div class="body">
10
+ <%= simple_format(@issue.body) %>
11
+ </div>
12
+
13
+ <% if !@issue.comments.empty? %>
14
+ <h3 class="comment_count"><%= @issue.comments.count %> Comments</h3>
15
+
16
+ <ol class="comments">
17
+ <% @issue.comments.each_with_index do |comment, index| %>
18
+ <li class="<%= cycle(:odd, :even) %>">
19
+ <div class="<%= comment_by(comment) %>">
20
+ <p><strong><%= index + 1 %></strong> Posted by <cite><%= comment.user_name %></cite> on <%= posted_on_long(comment.updated_at) %></p>
21
+ </div>
22
+ <div class="gravatar">
23
+ <%= image_tag(comment.gravatar_url(:size => 30)) %>
24
+ </div>
25
+ <div class="said">
26
+ <%= simple_format(comment.comment) %>
27
+ </div>
28
+ </li>
29
+ <% end %>
30
+ </ol>
31
+ <% end %>
32
+
33
+ <h3 class="reply">Reply to this discussion</h3>
34
+ <%= render :partial => "help/comments/form" %>
35
+ </div>
36
+
37
+ <div class="issue-status">
38
+ <p><strong><%= @issue.state %></strong></p>
39
+ </div>
@@ -0,0 +1,20 @@
1
+ <h1>Login</h1>
2
+
3
+ <% form_tag(help_session_path, :class => "formtastic") do %>
4
+ <fieldset class="inputs">
5
+ <ol>
6
+ <li class="string">
7
+ <%= label_tag "user[email]", "Email" %>
8
+ <%= text_field_tag "user[email]" %>
9
+ </li>
10
+ <li class="password">
11
+ <%= label_tag "user[password]", "Password" %>
12
+ <%= password_field_tag "user[password]" %>
13
+ </li>
14
+ </ol>
15
+ </fieldset>
16
+
17
+ <fieldset class="buttons">
18
+ <%= submit_tag("Login") %>
19
+ </fieldset>
20
+ <% end %>
@@ -0,0 +1,16 @@
1
+ <h1>Knowledge Base</h1>
2
+
3
+ <div class="articles">
4
+ <% @categories.each do |category| %>
5
+ <div class="category">
6
+ <h2><%= category.name %></h2>
7
+ <ul>
8
+ <% category.articles[0..5].each do |article| %>
9
+ <li>
10
+ <%= link_to(article.title, knowledge_article_path(article)) %>
11
+ </li>
12
+ <% end %>
13
+ </ul>
14
+ </div>
15
+ <% end %>
16
+ </div>
@@ -0,0 +1,3 @@
1
+ <h1><%= @article.title %></h1>
2
+
3
+ <%= simple_format(@article.body) %>