Skip to content

Commit

Permalink
Merge branch 'custom_fields' of github.com:fatfreecrm/fat_free_crm in…
Browse files Browse the repository at this point in the history
…to custom_fields
  • Loading branch information
ndbroadbent committed Nov 16, 2011
2 parents ef28269 + 85eaec6 commit 07d11c1
Show file tree
Hide file tree
Showing 42 changed files with 1,301 additions and 66 deletions.
1 change: 0 additions & 1 deletion .gitignore
Expand Up @@ -8,7 +8,6 @@ config/*.yml
.rspec
spec/reports
coverage/*
db/schema.rb
db/*.sql*
log/*.log

Expand Down
7 changes: 4 additions & 3 deletions Gemfile
Expand Up @@ -11,13 +11,16 @@ gem "pg", ">= 0.9.0"

gem 'authlogic', '~> 3.0.3'
gem 'acts_as_commentable', '>= 3.0.1'
gem 'acts-as-taggable-on', '>= 2.0.6'
gem 'haml', '>= 3.1.1'
gem 'sass', '>= 3.1.1'
gem 'paperclip', '~> 2.3.6'
gem 'will_paginate', '>= 3.0.pre2'
gem 'acts_as_list', '~> 0.1.4'
gem 'simple_form', '~> 1.5.2'
#~ gem 'jquery-rails' TODO: Go to rails 3.1
gem 'ffaker', '>= 1.5.0' # For demo data


group :development, :test do
gem 'ruby-debug', :platform => :mri_18
Expand All @@ -28,14 +31,13 @@ group :development, :test do
gem 'test-unit', '1.2.3', :platform => :mri_19
gem "rspec-rails", '>= 2.5.0'
gem 'ffaker', '>= 1.5.0'
gem 'factory_girl', '~> 1.3.3'
gem 'factory_girl', '>= 1.3.3'
end

group :test do
gem 'factory_girl_rails', '~> 1.0.1'
end


# Gem watch list:
#---------------------------------------------------------------------
# gem 'authlogic', :git => 'git://github.com/crossroads/authlogic.git', :branch => 'rails3'
Expand All @@ -51,4 +53,3 @@ end
# is_paranoid, git://github.com/theshortcut/is_paranoid.git
# prototype_legacy_helper, git://github.com/rails/prototype_legacy_helper.git
# responds_to_parent, git://github.com/markcatley/responds_to_parent.git

5 changes: 4 additions & 1 deletion Gemfile.lock
Expand Up @@ -28,6 +28,8 @@ GEM
activemodel (= 3.0.7)
activesupport (= 3.0.7)
activesupport (3.0.7)
acts-as-taggable-on (2.1.1)
rails
acts_as_commentable (3.0.1)
acts_as_list (0.1.4)
annotate (2.4.0)
Expand Down Expand Up @@ -134,12 +136,13 @@ PLATFORMS
ruby

DEPENDENCIES
acts-as-taggable-on (>= 2.0.6)
acts_as_commentable (>= 3.0.1)
acts_as_list (~> 0.1.4)
annotate (>= 2.4.0)
authlogic (~> 3.0.3)
awesome_print (>= 0.3.1)
factory_girl (~> 1.3.3)
factory_girl (>= 1.3.3)
factory_girl_rails (~> 1.0.1)
ffaker (>= 1.5.0)
haml (>= 3.1.1)
Expand Down
3 changes: 2 additions & 1 deletion Rakefile
Expand Up @@ -15,8 +15,9 @@ namespace :spec do
tmp_env = Rails.env
Rails.env = "test"
Rake::Task["crm:copy_default_config"].invoke
puts "Running initial migrations..."
puts "Preparing test database..."
Rake::Task["db:test:prepare"].invoke
Rake::Task["db:schema:load"].invoke
Rails.env = tmp_env
end
end
Expand Down
29 changes: 2 additions & 27 deletions app/controllers/admin/fields_controller.rb
Expand Up @@ -121,12 +121,10 @@ def update
# DELETE /fields/1.xml HTML and AJAX
#----------------------------------------------------------------------------
def destroy
@custom_field = CustomField.find(params[:id])
@custom_field.destroy if @custom_field
@field = CustomField.find(params[:id])

respond_to do |format|
format.html { respond_to_destroy(:html) }
format.js { respond_to_destroy(:ajax) }
format.js # destroy.js.rjs
format.xml { head :ok }
end

Expand All @@ -137,27 +135,4 @@ def destroy
# POST /fields/auto_complete/query AJAX
#----------------------------------------------------------------------------
# Handled by before_filter :auto_complete, :only => :auto_complete

private

#----------------------------------------------------------------------------
def respond_to_destroy(method)
if method == :ajax
if called_from_index_page?
@fields = get_fields
if @fields.blank?
@fields = get_fields(:page => current_page - 1) if current_page > 1
render :action => :index and return
end
else
self.current_page = 1
end
# At this point render destroy.js.rjs
else
self.current_page = 1
flash[:notice] = "#{@custom_field.field_name} has beed deleted."
redirect_to(fields_path)
end
end
end

40 changes: 33 additions & 7 deletions app/controllers/application_controller.rb
Expand Up @@ -83,6 +83,15 @@ def timeline(asset)
(asset.comments + asset.emails).sort { |x, y| y.created_at <=> x.created_at }
end

# Controller instance method that responds to /controlled/tagged/tag request.
# It stores given tag as current query and redirect to index to display all
# records tagged with the tag.
#----------------------------------------------------------------------------
def tagged
self.send(:current_query=, "#" << params[:id]) unless params[:id].blank?
redirect_to :action => "index"
end

private
#----------------------------------------------------------------------------
def set_context
Expand Down Expand Up @@ -227,8 +236,9 @@ def respond_to_related_not_found(related, *types)
#----------------------------------------------------------------------------
def get_list_of_records(klass, options = {})
items = klass.name.tableize
self.current_page = options[:page] if options[:page]
self.current_query = options[:query] if options[:query]
self.current_page = options[:page] if options[:page]
query, tags = parse_query_and_tags(options[:query]) if options[:query]
self.current_query = query

records = {
:user => @current_user,
Expand All @@ -250,10 +260,11 @@ def get_list_of_records(klass, options = {})
filter = session[options[:filter]].to_s.split(',') if options[:filter]

scope = klass.my(records)
scope = scope.state(filter) unless filter.blank?
scope = scope.search(current_query) unless current_query.blank?
scope = scope.unscoped if wants.csv?
scope = scope.paginate(pages) if wants.html? || wants.js? || wants.xml?
scope = scope.state(filter) if filter.present?
scope = scope.search(query) if query.present?
scope = scope.tagged_with(tags, :on => :tags) if tags.present?
scope = scope.unscoped if wants.csv?
scope = scope.paginate(pages) if wants.html? || wants.js? || wants.xml?
scope
end

Expand All @@ -280,5 +291,20 @@ def current_query
@current_query = params[:query] || session["#{controller_name}_current_query".to_sym] || ""
end

# Somewhat simplistic parser that extracts query and hash-prefixed tags from
# the search string and returns them as two element array, for example:
#
# "#real Billy Bones #pirate" => [ "Billy Bones", "real, pirate" ]
#----------------------------------------------------------------------------
def parse_query_and_tags(search_string)
query, tags = [], []
search_string.scan(/[\w@\-\.#]+/).each do |token|
if token.starts_with?("#")
tags << token[1 .. -1]
else
query << token
end
end
[ query.join(" "), tags.join(", ") ]
end
end

49 changes: 49 additions & 0 deletions app/helpers/tags_helper.rb
@@ -0,0 +1,49 @@
# Fat Free CRM
# Copyright (C) 2008-2011 by Michael Dvorkin
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#------------------------------------------------------------------------------

module TagsHelper

# Generate tag links for use on asset index pages.
#----------------------------------------------------------------------------
def tags_for_index(model)
model.tag_list.inject([]) do |arr, tag|
query = controller.send(:current_query) || ""
hashtag = "##{tag}"
if query.empty?
query = hashtag
elsif !query.include?(hashtag)
query += " #{hashtag}"
end
arr << link_to_function(tag, "crm.search_tagged('#{query}', '#{model.class.to_s.tableize}')", :title => tag)
end.join(" ").html_safe
end

# Generate tag links for the asset landing page (shown on a sidebar).
#----------------------------------------------------------------------------
def tags_for_show(model)
model.tag_list.inject([]) do |arr, tag|
arr << link_to(tag, url_for(:action => "tagged", :id => tag), :title => tag)
end.join(" ").html_safe
end

# Return asset tags to be built manually if the asset failed validation.
def unsaved_param_tags(asset)
params[asset][:tag_list].split(",").map {|x|
ActsAsTaggableOn::Tag.find_by_name(x.strip)
}.compact.uniq
end
end
1 change: 1 addition & 0 deletions app/models/core/account.rb
Expand Up @@ -64,6 +64,7 @@ class Account < ActiveRecord::Base

uses_user_permissions
acts_as_commentable
acts_as_taggable_on :tags
is_paranoid
has_fields
exportable
Expand Down
1 change: 1 addition & 0 deletions app/models/core/campaign.rb
Expand Up @@ -63,6 +63,7 @@ class Campaign < ActiveRecord::Base

uses_user_permissions
acts_as_commentable
acts_as_taggable_on :tags
is_paranoid
has_fields
exportable
Expand Down
1 change: 1 addition & 0 deletions app/models/core/contact.rb
Expand Up @@ -85,6 +85,7 @@ class Contact < ActiveRecord::Base

uses_user_permissions
acts_as_commentable
acts_as_taggable_on :tags
is_paranoid
has_fields
exportable
Expand Down
1 change: 1 addition & 0 deletions app/models/core/lead.rb
Expand Up @@ -75,6 +75,7 @@ class Lead < ActiveRecord::Base

uses_user_permissions
acts_as_commentable
acts_as_taggable_on :tags
is_paranoid
has_fields
exportable
Expand Down
1 change: 1 addition & 0 deletions app/models/core/opportunity.rb
Expand Up @@ -71,6 +71,7 @@ class Opportunity < ActiveRecord::Base

uses_user_permissions
acts_as_commentable
acts_as_taggable_on :tags
is_paranoid
has_fields
exportable
Expand Down
11 changes: 11 additions & 0 deletions app/stylesheets/common.sass
Expand Up @@ -644,3 +644,14 @@ span.handle img
vertical-align: middle
margin-right: 5px

.tags, .list li dt .tags
a:link, a:visited
:background lightsteelblue
:color white
:font-weight normal
:padding 0px 6px 1px 6px
:-moz-border-radius 8px
:-webkit-border-radius 8px
a:hover
:background steelblue
:color yellow
6 changes: 5 additions & 1 deletion app/views/accounts/_account.html.haml
Expand Up @@ -21,11 +21,15 @@
= t('pluralize.contact', account.contacts.count) << " | "
= t('pluralize.opportunity', account.opportunities.count)


- unless @current_user.preference[:accounts_outline] == "brief"
%dt
= stars_for(account) + " | "
= link_to(account.website, account.website.to_url) << " | " if account.website.present?
= link_to_email(account.email) << " | " if account.email.present?
= t(:phone_small) << ": " << (account.toll_free_phone || account.phone) if account.toll_free_phone? || account.phone?

- if account.tag_list.present?
%dt
.tags= tags_for_index(account)

= hook(:account_bottom, self, :account => account)
4 changes: 4 additions & 0 deletions app/views/accounts/_sidebar_show.html.haml
Expand Up @@ -48,4 +48,8 @@
.caption #{t :background_info}
= auto_link(simple_format h(@account.background_info))

- if @account.tag_list.present?
%dt
.tags= tags_for_index(@account)

= hook(:show_account_sidebar_bottom, self, :account => @account)
3 changes: 2 additions & 1 deletion app/views/accounts/_top_section.html.haml
Expand Up @@ -25,5 +25,6 @@
.label= t(:background_info) << ':'
= f.text_area :background_info, :style =>"width:500px", :rows => 3

= hook(:account_top_section_bottom, self, :f => f)
= render :partial => "/shared/tags", :locals => {:f => f, :span => 3}

= hook(:account_top_section_bottom, self, :f => f)
4 changes: 4 additions & 0 deletions app/views/campaigns/_campaign.html.haml
Expand Up @@ -10,4 +10,8 @@
= render "campaigns/status", :campaign => campaign
- unless @current_user.preference[:campaigns_outline] == "brief"
= render "campaigns/metrics", :campaign => campaign
- if campaign.tag_list.present?
%dt
.tags= tags_for_index(campaign)

= hook(:campaign_bottom, self, :campaign => campaign)
10 changes: 7 additions & 3 deletions app/views/campaigns/_sidebar_show.html.haml
Expand Up @@ -14,19 +14,19 @@
%tt #{t :budget}:

.caption #{t :campaign_targets}

-# Target Leads.
-#---------------------------------------------------------------------------
%li
%dt= @campaign.target_leads || t(:n_a)
%tt #{t :leads}:

-# Target Conversion Ratio.
-#---------------------------------------------------------------------------
%li
%dt= number_to_percentage(@campaign.target_conversion, :precision => 1) || t(:n_a)
%tt #{t :conversion}:

-# Target Opportunities: calculated based on target number of leads and
-# expected conversion ratio.
-#---------------------------------------------------------------------------
Expand Down Expand Up @@ -82,4 +82,8 @@
.caption #{t :background_info}
= auto_link(simple_format h(@campaign.background_info))

- if @campaign.tag_list.present?
%dt
.tags= tags_for_index(@campaign)

= hook(:show_campaign_sidebar_bottom, self, :campaign => @campaign)
2 changes: 2 additions & 0 deletions app/views/campaigns/_top_section.html.haml
Expand Up @@ -25,4 +25,6 @@
.label= t(:background_info) << ':'
= f.text_area :background_info, :style =>"width:500px", :rows => 3

= render :partial => "/shared/tags", :locals => {:f => f, :span => 5}

= hook(:campaign_top_section_bottom, self, :f => f)
4 changes: 4 additions & 0 deletions app/views/contacts/_contact.html.haml
Expand Up @@ -27,4 +27,8 @@
= "#{t :phone_small}: <b>".html_safe + h(contact.phone) << "</b> | ".html_safe if contact.phone.present?
= "#{t :mobile_small}: <b>".html_safe + h(contact.mobile) << "</b> | ".html_safe if contact.mobile.present?
= t(:added_ago, time_ago_in_words(contact.created_at))
- if contact.tag_list.present?
%dt
.tags= tags_for_index(contact)

= hook(:contact_bottom, self, :contact => contact)
4 changes: 4 additions & 0 deletions app/views/contacts/_sidebar_show.html.haml
Expand Up @@ -32,4 +32,8 @@
.caption #{t :background_info}
= auto_link(simple_format h(@contact.background_info))

- if @contact.tag_list.present?
%dt
.tags= tags_for_index(@contact)

= hook(:show_contact_sidebar_bottom, self, :contact => @contact)

0 comments on commit 07d11c1

Please sign in to comment.