Skip to content

Commit

Permalink
Merge pull request #1495 from scott/dev/2.7/prepare-2.7.0
Browse files Browse the repository at this point in the history
Dev/2.7/prepare 2.7.0
  • Loading branch information
scott authored Nov 4, 2019
2 parents 197a2a6 + 47acfa6 commit e82fe97
Show file tree
Hide file tree
Showing 34 changed files with 159 additions and 29 deletions.
44 changes: 44 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,47 @@
## VERSION 2.7.0

The 2.7 release of Helpy is here, with several great new features to help you b etter provide great customer support.

New Features:

- New nested categories feature lets you create sub categories with a drag and drop UI to group and administer them.
- New API setting for default reply type
- Site URL is now validated
- New Anti-spam setting to filter any ticket from matching email addresses to spam
- Address a ticket is sent to is now captured

Bug Fixes:

- Webhooks preference did not always save
- Customers list view does not always load

See UPDATING.md for details on how to update.

## VERSION 2.6.0

This release fixes several edge case bugs and adds a couple new API features and an all new Ukrainian language translation. Specifically:

- New Ukrainian locale #1378 @Serg2294

Bug Fixes:

- Translated versions are now properly included in the search index #1375
- The CC address is now persisted if you change the assignment of a ticket while editing the reply #1387
- Agents can now create an unassigned ticket #1317
- A rare bug that docs unclickable on mobile has been resolved #1371

API:

- A new endpoint has been added to get specifics of the currently logged in user #1242 @trevormerritt
- Categories can now be filtered by visibility (public/private/internal) #1269
- Forum topics now respect a limit param #1357 @elguitar
- The User entity is now included with topics and posts #1318

Misc:

- Can now specify a theme environment var when running test suite #1253 @azul


## VERSION 2.5.0

This release adds important new functionality for managing incoming spam email tickets (particularly from parse webhook services such as Sendgrid or Mandrill).
Expand Down
4 changes: 3 additions & 1 deletion app/controllers/admin/dashboard_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ def index
redirect_to admin_topics_path
elsif current_user.is_editor? && knowledgebase?
redirect_to admin_categories_path
elsif (current_user.is_admin? || current_user.is_agent?)
redirect_to admin_users_path
else
redirect_to root_url
redirect_to admin_blank_dashboard_path
end
end

Expand Down
4 changes: 2 additions & 2 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ def url_options

def after_sign_in_path_for(_resource)
# If the user is an agent, redirect to admin panel
redirect_url = current_user.is_agent? ? admin_root_url : root_url
oauth_url = current_user.is_agent? ? admin_root_url : request.env['omniauth.origin']
redirect_url = current_user.is_editor? ? admin_root_url : root_url
oauth_url = current_user.is_editor? ? admin_root_url : request.env['omniauth.origin']
oauth_url || redirect_url
end

Expand Down
2 changes: 2 additions & 0 deletions app/controllers/home_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ class HomeController < ApplicationController
respond_to :html

def index
redirect_to new_user_session_path if !tickets? && !knowledgebase?

@topics = Topic.by_popularity.ispublic.front
@rss = Topic.chronologic.active
@articles = Doc.all_public_popular.with_translations(I18n.locale).includes(:tags)
Expand Down
2 changes: 1 addition & 1 deletion app/helpers/admin/topics_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def ticket_status_label

def new_ticket_button
content_tag :span, class: 'hidden-xs pull-right' do
link_to t(:open_new_discussion, default: 'Open Discussion'), new_admin_topic_path, remote: true, class: 'btn btn-primary'
link_to t(:open_new_discussion, default: 'Open Discussion'), new_admin_topic_path, remote: true, class: 'btn btn-primary' if tickets?
end
end

Expand Down
2 changes: 1 addition & 1 deletion app/helpers/admin/users_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ def user_header

def new_user_ticket_button
content_tag :span, class: "hidden-xs pull-right" do
link_to t(:open_new_discussion, default: 'Open Discussion'), new_admin_topic_path(user_id: @user.id), remote: true, class: 'btn btn-primary'
link_to t(:open_new_discussion, default: 'Open Discussion'), new_admin_topic_path(user_id: @user.id), remote: true, class: 'btn btn-primary' if tickets?
end
end

Expand Down
1 change: 1 addition & 0 deletions app/models/entity/post.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ class Post < Base
expose :cc, documentation: { type: "String", desc: "Comma separated list of emails to CC" }
expose :bcc, documentation: { type: "String", desc: "Comma separated list of emails to BCC" }
expose :raw_email, documentation: { desc: "The original full raw email body" }
expose :email_to_address, documentation: { desc: "The address a ticket was sent to" }
end
end
8 changes: 8 additions & 0 deletions app/models/topic.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ class Topic < ActiveRecord::Base
# may want to get rid of this filter:
# before_save :check_for_private
before_create :add_locale
before_create :reject_blacklisted_email_addresses

before_save :cache_user_name
acts_as_taggable_on :tags, :teams
Expand Down Expand Up @@ -277,6 +278,13 @@ def posts_in_last_minute

private

# Send any tickets created by a blacklisted email to spam
def reject_blacklisted_email_addresses
if AppSettings['email.email_blacklist'].split(",").any? { |s| self.user.email.downcase.include?(s.downcase) }
self.current_status = "spam"
end
end

def cache_user_name
return if self.user.nil?
if self.user.name.present?
Expand Down
1 change: 0 additions & 1 deletion app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ class User < ActiveRecord::Base
validates :name, presence: true
validates :email, presence: true


include Gravtastic
mount_uploader :profile_image, ProfileImageUploader

Expand Down
Empty file.
5 changes: 3 additions & 2 deletions app/views/admin/settings/email.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@
</div>
</div>
<div class="settings-section spam-protection" data-hook="spam_protection">
<%= f.text_field 'email.spam_assassin_reject', label: 'Reject incoming email SpamAssassin threshold', value: AppSettings['email.spam_assassin_reject'] %>
<%= f.text_field 'email.spam_assassin_filter', label: 'Filter to Spam incoming email SA threshold ', value: AppSettings['email.spam_assassin_filter'] %>
<%= f.text_field 'email.spam_assassin_reject', label: t('spam_assassin_reject'), value: AppSettings['email.spam_assassin_reject'] %>
<%= f.text_field 'email.spam_assassin_filter', label: t('spam_assassin_filter'), value: AppSettings['email.spam_assassin_filter'] %>
<%= f.text_area 'email.email_blacklist', label: t('email_blacklist'), value: AppSettings['email.email_blacklist'] %>
</div>
<div class="submit-section">
<%= f.submit "Save Settings", class: 'btn btn-warning' %>
Expand Down
2 changes: 1 addition & 1 deletion app/views/admin/topics/_ticket_nav_dropdown.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
<% end %>
</li>
<li class="mailbox tiny-header">
<%= link_to t(:open_new_discussion, default: "Create New Ticket"), new_admin_topic_path, remote: true, class: 'btn btn-default' %>
<%= link_to t(:open_new_discussion, default: "Create New Ticket"), new_admin_topic_path, remote: true, class: 'btn btn-default' if tickets? %>
</li>
</ul>
</div>
2 changes: 1 addition & 1 deletion app/views/admin/topics/_tickets.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
data: { confirm: t(:empty_trash_warning, default: "Are you sure you want to empty the trash? This will permanently delete all tickets in the trash.") },
class: 'btn btn-default', remote: true if params[:status] == 'trash' && current_user.is_admin? %>
<%= link_to t(:open_new_discussion, default: "Open Discussion"), new_admin_topic_path,
remote: true, class: 'btn btn-primary' %>
remote: true, class: 'btn btn-primary' if tickets? %>
</div>
<% end %>
<% if @topics.present? %>
Expand Down
2 changes: 1 addition & 1 deletion app/views/admin/topics/_topic_options.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<% if @topic.user.present? %>
<li class="dropdown-header"><%= @topic.user.name %></li>
<li><%= link_to t(:tickets, default: 'Tickets'), remote: true %></li>
<li><%= link_to t(:open_new_discussion, default: 'Open Discussion'), new_admin_topic_path(user_id: @topic.user.id), remote: true, class: '' %></li>
<li><%= link_to t(:open_new_discussion, default: 'Open Discussion'), new_admin_topic_path(user_id: @topic.user.id), remote: true, class: '' if tickets? %></li>
<li><%= link_to t(:edit_user, default: 'Edit User'), edit_admin_user_path(@topic.user), remote: false if @topic.user.can_be_edited? current_user %></li>
<% end %>
</ul>
Expand Down
2 changes: 1 addition & 1 deletion app/views/admin/users/_tickets.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
</div>
<div class="pull-right nav-new-button" style="margin-top:18px;">
<%= link_to t(:open_new_discussion, default: "Open Discussion"), new_admin_topic_path(user_id: @user.id),
remote: true, class: 'btn btn-primary' %>
remote: true, class: 'btn btn-primary' if tickets? %>
</div>

</div>
Expand Down
2 changes: 1 addition & 1 deletion app/views/admin/users/_user.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<div class="btn-group">
<span id="row-<%= user.id %>" data-toggle="dropdown" aria-expanded="false" class='btn dropdown-toggle fas fa-ellipsis-v'></span>
<ul class="dropdown-menu dropdown-menu-right" role="menu">
<li><%= link_to t(:open_new_discussion, default: 'Open Discussion'), new_admin_topic_path(user_id: user.id), remote: true, class: '' %></li>
<li><%= link_to t(:open_new_discussion, default: 'Open Discussion'), new_admin_topic_path(user_id: user.id), remote: true, class: '' if tickets? %></li>
<li><%= link_to t(:discussions, default: 'Discussions'), admin_user_path(user), remote: true %></li>
<li><%= link_to t(:edit_user, default: 'Edit User'), edit_admin_user_path(user, mode: 'edit'), remote: false if user.can_be_edited? current_user%></li>
</ul>
Expand Down
2 changes: 1 addition & 1 deletion app/views/admin/users/_user_context_menu.html.erb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<span class="btn-group left-col-dropdown" style="margin-top:18px;">
<%= link_to content_tag(:small, '', class: 'fas fa-ellipsis-v ticket-ellipsis btn'), '#', class: 'dropdown-toggle', data: { toggle: 'dropdown' }%>
<ul class="dropdown-menu dropdown-menu-right" role="menu">
<li><%= link_to t(:open_new_discussion, default: 'Open Discussion'), new_admin_topic_path(user_id: user.id), remote: true, class: '' %></li>
<li><%= link_to t(:open_new_discussion, default: 'Open Discussion'), new_admin_topic_path(user_id: user.id), remote: true, class: '' if tickets? %></li>
<li><%= link_to t(:edit_user, default: 'Edit User'), edit_admin_user_path(user), remote: false if user.can_be_edited? current_user %></li>
<li><%= link_to t(:scrub_user, default: 'Anonymize User'), admin_scrub_user_path(user), remote: true,
method: :post,
Expand Down
2 changes: 1 addition & 1 deletion app/views/admin/users/_user_info.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<span class="btn-group left-col-dropdown">
<%= link_to content_tag(:small, '', class: 'fas fa-ellipsis-v ticket-ellipsis btn'), '#', class: 'dropdown-toggle', data: { toggle: 'dropdown' }%>
<ul class="dropdown-menu dropdown-menu-right" role="menu">
<li><%= link_to t(:open_new_discussion, default: 'Open Discussion'), new_admin_topic_path(user_id: @user.id), remote: true, class: '' %></li>
<li><%= link_to t(:open_new_discussion, default: 'Open Discussion'), new_admin_topic_path(user_id: @user.id), remote: true, class: '' if tickets? %></li>
<li><%= link_to t(:edit_user, default: 'Edit User'), edit_admin_user_path(@user), remote: false %></li>
<li><%= link_to t(:scrub_user, default: 'Anonymize User'), admin_scrub_user_path(@user), remote: true,
method: :post,
Expand Down
4 changes: 2 additions & 2 deletions app/views/layouts/_admin_header.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ a.navbar-brand {
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right pull-right hidden-xs" data-hook='admin-nav-right'>
<%= content_tag(:li, '' , class: "visible-lg visible-md visible-sm hidden-xs click-loader new-discussion #{new_active_class}") do %>
<%= navbar_expanding_link(new_admin_topic_path, "fas fa-plus", t(:new_ticket, default: "New Ticket"), "", (params[:controller] == 'admin/topics')) %>
<%= navbar_expanding_link(new_admin_topic_path, "fas fa-plus", t(:new_ticket, default: "New Ticket"), "", (params[:controller] == 'admin/topics')) if tickets? %>
<% end if current_user.is_agent? %>
<%= help_menu %>
<%= admin_avatar_menu %>
Expand All @@ -90,7 +90,7 @@ a.navbar-brand {
<%= helpcenter_menu_or_item %>
<%= content_tag(:li, link_to(t(:content, default: "Content"), admin_categories_path), class:'kblink') if knowledgebase? && current_user.role == 'editor' %>
<%#= content_tag(:li, link_to(t(:app_store, default: "App Store"), "http://helpy.io/store/"), class: "hidden-sm hidden-xs") if current_user.is_agent? %>
<%= content_tag(:li, link_to(t(:open_new_discussion, default: "New Ticket"), new_admin_topic_path), class: 'visible-xs hidden-lg hidden-md hidden-sm') if current_user.is_agent? %>
<%= content_tag(:li, link_to(t(:open_new_discussion, default: "New Ticket"), new_admin_topic_path), class: 'visible-xs hidden-lg hidden-md hidden-sm') if current_user.is_agent? && tickets? %>
<%= content_tag(:li, link_to(t(:settings, default: "Settings"), admin_settings_path), class: 'visible-xs hidden-lg hidden-md hidden-sm') if current_user.is_admin? %>
<%= content_tag(:li, link_to(t(:get_help, default: "Get Help"), "http://support.helpy.io/"), class: 'visible-xs hidden-lg hidden-md hidden-sm', target: 'blank') %>
</ul>
Expand Down
2 changes: 1 addition & 1 deletion config/environment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
Rails.application.initialize!

# Get the current tag version
VERSION = '2.6.0'
VERSION = '2.7.0'
REVISION = `git log --pretty=format:'%h' -n 1`
APP_VERSION = "#{VERSION}:#{REVISION}"
1 change: 1 addition & 0 deletions config/initializers/default_settings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
AppSettings.defaults["email.mail_domain"]= Settings.mail_domain
AppSettings.defaults["email.spam_assassin_reject"]= 4
AppSettings.defaults["email.spam_assassin_filter"]= 2
AppSettings.defaults["email.email_blacklist"] = ""

# notifications

Expand Down
3 changes: 3 additions & 0 deletions config/locales/de.yml
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,9 @@ de:
# mail_smtp: SMTP Server
# mail_port: SMTP Port
# mail_domain: SMTP Domain
# spam_assassin_reject: SpamAssassin Threshold for rejecting incoming email tickets
# spam_assassin_filter: SpamAssassin Threshold for marking incoming tickets spam
# email_blacklist: Automatically mark tickets from these addresses as spam (separate multiple with commas)

# API Key Managmeent
api_keys: "API Keys"
Expand Down
3 changes: 3 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,9 @@ en:
mail_smtp: SMTP Server
mail_port: SMTP Port
mail_domain: SMTP Domain
spam_assassin_reject: SpamAssassin Threshold for rejecting incoming email tickets
spam_assassin_filter: SpamAssassin Threshold for marking incoming tickets spam
email_blacklist: Automatically mark tickets from these addresses as spam (separate multiple with commas)

# API Key Managmeent
api_keys: "API Keys"
Expand Down
5 changes: 4 additions & 1 deletion config/locales/es.yml
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,10 @@ es:
# mail_smtp: SMTP Server
# mail_port: SMTP Port
# mail_domain: SMTP Domain

# spam_assassin_reject: SpamAssassin Threshold for rejecting incoming email tickets
# spam_assassin_filter: SpamAssassin Threshold for marking incoming tickets spam
# email_blacklist: Automatically mark tickets from these addresses as spam (separate multiple with commas)

# API Key Managmeent
# api_keys: "API Keys"
# key_name: "Key Name"
Expand Down
3 changes: 3 additions & 0 deletions config/locales/fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,9 @@ fr:
mail_smtp: "Serveur SMTP"
mail_port: "Port SMTP"
mail_domain: "Nom de domaine SMTP"
# spam_assassin_reject: SpamAssassin Threshold for rejecting incoming email tickets
# spam_assassin_filter: SpamAssassin Threshold for marking incoming tickets spam
# email_blacklist: Automatically mark tickets from these addresses as spam (separate multiple with commas)

# API Key Managmeent
api_keys: "Clés API"
Expand Down
3 changes: 3 additions & 0 deletions config/locales/pt_BR.yml
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,9 @@ pt-br:
mail_smtp: "Servidor SMTP"
mail_port: "Porta SMTP"
mail_domain: "Domínio SMTP"
# spam_assassin_reject: SpamAssassin Threshold for rejecting incoming email tickets
# spam_assassin_filter: SpamAssassin Threshold for marking incoming tickets spam
# email_blacklist: Automatically mark tickets from these addresses as spam (separate multiple with commas)

# API Keys
api_keys: "Chaves da API"
Expand Down
2 changes: 2 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@
get '/reports/groups' => 'reports#groups', as: :group_reports
get '/reports' => 'reports#index', as: :reports

get '/dashboard/blank' => 'dashboard#blank', as: :blank_dashboard

root to: 'dashboard#index'
end

Expand Down
5 changes: 5 additions & 0 deletions db/migrate/20191005134018_add_email_sent_to_posts.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddEmailSentToPosts < ActiveRecord::Migration
def change
add_column :posts, :email_to_address, :string, default: ''
end
end
13 changes: 7 additions & 6 deletions db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 20190716202013) do
ActiveRecord::Schema.define(version: 20191005134018) do

# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
Expand Down Expand Up @@ -188,14 +188,15 @@
t.integer "user_id"
t.text "body"
t.string "kind"
t.boolean "active", default: true
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "points", default: 0
t.string "attachments", default: [], array: true
t.boolean "active", default: true
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "points", default: 0
t.string "attachments", default: [], array: true
t.string "cc"
t.string "bcc"
t.text "raw_email"
t.string "email_to_address", default: ""
end

create_table "searches", force: :cascade do |t|
Expand Down
9 changes: 6 additions & 3 deletions lib/email_processor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ def self.create_new_ticket_from_email(email, email_address, email_name, subject,
raw_email: raw,
user_id: @user.id,
kind: "first",
cc: cc
cc: cc,
email_to_address: to
)
# Push array of attachments and send to Cloudinary
EmailProcessor.handle_attachments(email, post)
Expand Down Expand Up @@ -167,7 +168,8 @@ def self.create_forwarded_message_from_email(email, subject, raw, message, token
raw_email: raw,
user_id: @user.id,
kind: 'first',
cc: cc
cc: cc,
email_to_address: to
)

# Push array of attachments and send to Cloudinary
Expand Down Expand Up @@ -204,7 +206,8 @@ def self.create_reply_from_email(email, email_address, email_name, subject, raw,
raw_email: raw,
user_id: @user.id,
kind: "reply",
cc: cc
cc: cc,
email_to_address: to
)

# Push array of attachments and send to Cloudinary
Expand Down
8 changes: 8 additions & 0 deletions test/factories/factories.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@
spam_report { '' }
end

factory :blacklist_email, class: OpenStruct do
to { [{ full: '[email protected]', email: '[email protected]', token: 'to_user', host: 'email.com', name: nil }] }
from { ({ token: 'blacklist', host: 'email.com', email: '[email protected]', full: 'blacklist <[email protected]>', name: 'blacklist User' }) }
subject { 'spam email subject' }
header {}
body { 'Spam' }
end

factory :spam_from_unknown, class: OpenStruct do
to { [{ full: '[email protected]', email: '[email protected]', token: 'to_user', host: 'email.com', name: nil }] }
from { ({ token: 'spam_user', host: 'email.com', email: '[email protected]', full: 'spammer <[email protected]>', name: 'Spam User' }) }
Expand Down
2 changes: 1 addition & 1 deletion test/integration/sign_in_flow_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def sign_out

test "an editor should be able to sign in and be shown the categories page" do
sign_in("[email protected]")
assert_equal '/en', current_path
assert_equal '/admin/categories', current_path
sign_out
end

Expand Down
Loading

0 comments on commit e82fe97

Please sign in to comment.