From 636692f9921bd695d726695d2d46c91f5a6e56f3 Mon Sep 17 00:00:00 2001 From: Azul Date: Fri, 11 Apr 2014 10:03:19 +0200 Subject: move engines into engines directory Also renamed help to support so it's harder to confuse it with documentation --- engines/support/Gemfile | 15 ++ engines/support/README.md | 1 + engines/support/Rakefile | 44 ++++ engines/support/app/assets/javascripts/tickets.js | 4 + .../support/app/controllers/tickets_controller.rb | 153 ++++++++++++ .../app/designs/ticket/by_includes_post_by.js | 13 + .../ticket/by_includes_post_by_and_created_at.js | 12 + ..._includes_post_by_and_is_open_and_created_at.js | 12 + ..._includes_post_by_and_is_open_and_updated_at.js | 12 + .../ticket/by_includes_post_by_and_updated_at.js | 12 + .../app/helpers/auto_tickets_path_helper.rb | 53 ++++ engines/support/app/helpers/tickets_helper.rb | 76 ++++++ .../app/models/account_extension/tickets.rb | 13 + engines/support/app/models/ticket.rb | 105 ++++++++ engines/support/app/models/ticket_comment.rb | 43 ++++ engines/support/app/models/ticket_selection.rb | 71 ++++++ .../support/app/views/tickets/_comment.html.haml | 20 ++ .../support/app/views/tickets/_edit_form.html.haml | 48 ++++ .../app/views/tickets/_new_comment_form.html.haml | 13 + engines/support/app/views/tickets/_tabs.html.haml | 23 ++ .../support/app/views/tickets/_ticket.html.haml | 6 + engines/support/app/views/tickets/index.html.haml | 19 ++ engines/support/app/views/tickets/new.html.haml | 30 +++ engines/support/app/views/tickets/show.html.haml | 12 + .../config/initializers/account_lifecycle.rb | 3 + engines/support/config/locales/en.yml | 22 ++ engines/support/config/routes.rb | 8 + engines/support/leap_web_help.gemspec | 18 ++ engines/support/lib/leap_web_help.rb | 4 + engines/support/lib/leap_web_help/engine.rb | 4 + engines/support/lib/tasks/leap_web_help_tasks.rake | 4 + engines/support/script/rails | 8 + engines/support/test/factories.rb | 18 ++ .../test/functional/tickets_controller_test.rb | 273 +++++++++++++++++++++ .../support/test/integration/navigation_test.rb | 9 + engines/support/test/leap_web_help_test.rb | 7 + engines/support/test/test_helper.rb | 15 ++ .../support/test/unit/account_extension_test.rb | 12 + engines/support/test/unit/ticket_comment_test.rb | 59 +++++ engines/support/test/unit/ticket_test.rb | 88 +++++++ 40 files changed, 1362 insertions(+) create mode 100644 engines/support/Gemfile create mode 100644 engines/support/README.md create mode 100644 engines/support/Rakefile create mode 100644 engines/support/app/assets/javascripts/tickets.js create mode 100644 engines/support/app/controllers/tickets_controller.rb create mode 100644 engines/support/app/designs/ticket/by_includes_post_by.js create mode 100644 engines/support/app/designs/ticket/by_includes_post_by_and_created_at.js create mode 100644 engines/support/app/designs/ticket/by_includes_post_by_and_is_open_and_created_at.js create mode 100644 engines/support/app/designs/ticket/by_includes_post_by_and_is_open_and_updated_at.js create mode 100644 engines/support/app/designs/ticket/by_includes_post_by_and_updated_at.js create mode 100644 engines/support/app/helpers/auto_tickets_path_helper.rb create mode 100644 engines/support/app/helpers/tickets_helper.rb create mode 100644 engines/support/app/models/account_extension/tickets.rb create mode 100644 engines/support/app/models/ticket.rb create mode 100644 engines/support/app/models/ticket_comment.rb create mode 100644 engines/support/app/models/ticket_selection.rb create mode 100644 engines/support/app/views/tickets/_comment.html.haml create mode 100644 engines/support/app/views/tickets/_edit_form.html.haml create mode 100644 engines/support/app/views/tickets/_new_comment_form.html.haml create mode 100644 engines/support/app/views/tickets/_tabs.html.haml create mode 100644 engines/support/app/views/tickets/_ticket.html.haml create mode 100644 engines/support/app/views/tickets/index.html.haml create mode 100644 engines/support/app/views/tickets/new.html.haml create mode 100644 engines/support/app/views/tickets/show.html.haml create mode 100644 engines/support/config/initializers/account_lifecycle.rb create mode 100644 engines/support/config/locales/en.yml create mode 100644 engines/support/config/routes.rb create mode 100644 engines/support/leap_web_help.gemspec create mode 100644 engines/support/lib/leap_web_help.rb create mode 100644 engines/support/lib/leap_web_help/engine.rb create mode 100644 engines/support/lib/tasks/leap_web_help_tasks.rake create mode 100755 engines/support/script/rails create mode 100644 engines/support/test/factories.rb create mode 100644 engines/support/test/functional/tickets_controller_test.rb create mode 100644 engines/support/test/integration/navigation_test.rb create mode 100644 engines/support/test/leap_web_help_test.rb create mode 100644 engines/support/test/test_helper.rb create mode 100644 engines/support/test/unit/account_extension_test.rb create mode 100644 engines/support/test/unit/ticket_comment_test.rb create mode 100644 engines/support/test/unit/ticket_test.rb (limited to 'engines/support') diff --git a/engines/support/Gemfile b/engines/support/Gemfile new file mode 100644 index 0000000..ad7d29b --- /dev/null +++ b/engines/support/Gemfile @@ -0,0 +1,15 @@ +source "https://rubygems.org" + +eval(File.read(File.dirname(__FILE__) + '/../common_dependencies.rb')) +eval(File.read(File.dirname(__FILE__) + '/..//ui_dependencies.rb')) + +# We require leap_web_core from here so we can use the path option. +gem "leap_web_core", :path => '../core' + +# Declare your gem's dependencies in leap_web_users.gemspec. +# Bundler will treat runtime dependencies like base dependencies, and +# development dependencies will be added by default to the :development group. +gemspec + +# To use debugger +# gem 'ruby-debug' diff --git a/engines/support/README.md b/engines/support/README.md new file mode 100644 index 0000000..c9573e6 --- /dev/null +++ b/engines/support/README.md @@ -0,0 +1 @@ +Implements a simple, clean, and easy to use help ticketing system. \ No newline at end of file diff --git a/engines/support/Rakefile b/engines/support/Rakefile new file mode 100644 index 0000000..0e73163 --- /dev/null +++ b/engines/support/Rakefile @@ -0,0 +1,44 @@ +#!/usr/bin/env rake + +require 'rake/packagetask' +require 'rubygems/package_task' + +begin + require 'bundler/setup' +rescue LoadError + puts 'You must `gem install bundler` and `bundle install` to run rake tasks' +end +begin + require 'rdoc/task' +rescue LoadError + require 'rdoc/rdoc' + require 'rake/rdoctask' + RDoc::Task = Rake::RDocTask +end + +RDoc::Task.new(:rdoc) do |rdoc| + rdoc.rdoc_dir = 'rdoc' + rdoc.title = 'LeapWebHelp' + rdoc.options << '--line-numbers' + rdoc.rdoc_files.include('README.rdoc') + rdoc.rdoc_files.include('lib/**/*.rb') +end + +spec = eval(File.read('leap_web_help.gemspec')) +Gem::PackageTask.new(spec) do |p| + p.gem_spec = spec +end + +Bundler::GemHelper.install_tasks + +require 'rake/testtask' + +Rake::TestTask.new(:test) do |t| + t.libs << 'lib' + t.libs << 'test' + t.pattern = 'test/**/*_test.rb' + t.verbose = false +end + + +task :default => :test diff --git a/engines/support/app/assets/javascripts/tickets.js b/engines/support/app/assets/javascripts/tickets.js new file mode 100644 index 0000000..18537aa --- /dev/null +++ b/engines/support/app/assets/javascripts/tickets.js @@ -0,0 +1,4 @@ +//$(document).ready(function () { +// $.fn.editable.defaults.mode = 'inline'; +// $('#subject').editable(); +//}); \ No newline at end of file diff --git a/engines/support/app/controllers/tickets_controller.rb b/engines/support/app/controllers/tickets_controller.rb new file mode 100644 index 0000000..d65ee43 --- /dev/null +++ b/engines/support/app/controllers/tickets_controller.rb @@ -0,0 +1,153 @@ +class TicketsController < ApplicationController + include AutoTicketsPathHelper + + respond_to :html, :json + #has_scope :open, :type => boolean + + before_filter :require_login, :only => [:index] + before_filter :fetch_ticket, :only => [:show, :update, :destroy] # don't now have an edit method + before_filter :fetch_user + before_filter :set_title + + def new + @ticket = Ticket.new + @ticket.comments.build + end + + def create + @ticket = Ticket.new(params[:ticket]) + + @ticket.comments.last.posted_by = (logged_in? ? current_user.id : nil) #protecting posted_by isn't working, so this should protect it. + @ticket.comments.last.private = false unless admin? + @ticket.created_by = current_user.id if logged_in? + @ticket.email = current_user.email_address if logged_in? and current_user.email_address + + if @ticket.save + flash[:notice] = t(:thing_was_successfully_created, :thing => t(:ticket)) + end + + # cannot set this until ticket has been saved, as @ticket.id will not be set + if !logged_in? and flash[:notice] + flash[:notice] += " " + t(:access_ticket_text, :full_url => ticket_url(@ticket.id)) + end + respond_with(@ticket, :location => auto_ticket_path(@ticket)) + end + + def show + @comment = TicketComment.new + if !@ticket + redirect_to auto_tickets_path, :alert => t(:no_such_thing, :thing => t(:ticket)) + return + end + end + + def update + if params[:commit] == 'close' + @ticket.is_open = false + @ticket.save + redirect_to_tickets + elsif params[:commit] == 'open' + @ticket.is_open = true + @ticket.save + redirect_to auto_ticket_path(@ticket) + else + @ticket.attributes = cleanup_ticket_params(params[:ticket]) + + if params[:commit] == 'reply_and_close' + @ticket.close + end + + if @ticket.comments_changed? + @ticket.comments.last.posted_by = (current_user ? current_user.id : nil) + @ticket.comments.last.private = false unless admin? + end + + if @ticket.changed? and @ticket.save + flash[:notice] = t(:changes_saved) + redirect_to_tickets + else + flash[:error] = @ticket.errors.full_messages.join(". ") if @ticket.changed? + redirect_to auto_ticket_path(@ticket) + end + end + end + + def index + @all_tickets = Ticket.search(search_options(params)) + @tickets = @all_tickets.page(params[:page]).per(APP_CONFIG[:pagination_size]) + end + + def destroy + # should we allow non-admins to delete their own tickets? i don't think necessary. + @ticket.destroy if admin? + redirect_to auto_tickets_path + end + + protected + + def set_title + @title = t(:tickets) + end + + private + + # + # redirects to ticket index, if appropriate. + # otherwise, just redirects to @ticket + # + def redirect_to_tickets + if logged_in? + if params[:commit] == t(:reply_and_close) + redirect_to auto_tickets_path + else + redirect_to auto_ticket_path(@ticket) + end + else + # if we are not logged in, there is no index to view + redirect_to auto_ticket_path(@ticket) + end + end + + # + # unset comments hash if no new comment was typed + # + def cleanup_ticket_params(ticket) + if ticket && ticket[:comments_attributes] + if ticket[:comments_attributes].values.first[:body].blank? + ticket[:comments_attributes] = nil + end + end + return ticket + end + + def ticket_access? + @ticket and (admin? or !@ticket.created_by or (current_user and current_user.id == @ticket.created_by)) + end + + def fetch_ticket + @ticket = Ticket.find(params[:id]) + if !@ticket and admin? + redirect_to auto_tickets_path, :alert => t(:no_such_thing, :thing => 'ticket') + return + end + access_denied unless ticket_access? + end + + def fetch_user + if params[:user_id] + @user = User.find(params[:user_id]) + end + end + + # + # clean up params for ticket search + # + def search_options(params) + params.merge( + :admin_status => params[:user_id] ? 'mine' : 'all', + :user_id => @user ? @user.id : current_user.id, + :is_admin => admin? + ) + end + +end diff --git a/engines/support/app/designs/ticket/by_includes_post_by.js b/engines/support/app/designs/ticket/by_includes_post_by.js new file mode 100644 index 0000000..2eeac89 --- /dev/null +++ b/engines/support/app/designs/ticket/by_includes_post_by.js @@ -0,0 +1,13 @@ +// TODO: This view is only used in tests--should we keep it? +function(doc) { + var arr = {} + if (doc['type'] == 'Ticket' && doc.comments) { + doc.comments.forEach(function(comment){ + if (comment.posted_by && !arr[comment.posted_by]) { + //don't add duplicates + arr[comment.posted_by] = true; + emit(comment.posted_by, 1); + } + }); + } +} diff --git a/engines/support/app/designs/ticket/by_includes_post_by_and_created_at.js b/engines/support/app/designs/ticket/by_includes_post_by_and_created_at.js new file mode 100644 index 0000000..72169b0 --- /dev/null +++ b/engines/support/app/designs/ticket/by_includes_post_by_and_created_at.js @@ -0,0 +1,12 @@ +function(doc) { + var arr = {} + if (doc['type'] == 'Ticket' && doc.comments) { + doc.comments.forEach(function(comment){ + if (comment.posted_by && !arr[comment.posted_by]) { + //don't add duplicates + arr[comment.posted_by] = true; + emit([comment.posted_by, doc.created_at], 1); + } + }); + } +} diff --git a/engines/support/app/designs/ticket/by_includes_post_by_and_is_open_and_created_at.js b/engines/support/app/designs/ticket/by_includes_post_by_and_is_open_and_created_at.js new file mode 100644 index 0000000..33dfe0b --- /dev/null +++ b/engines/support/app/designs/ticket/by_includes_post_by_and_is_open_and_created_at.js @@ -0,0 +1,12 @@ +function(doc) { + var arr = {} + if (doc['type'] == 'Ticket' && doc.comments) { + doc.comments.forEach(function(comment){ + if (comment.posted_by && !arr[comment.posted_by]) { + //don't add duplicates + arr[comment.posted_by] = true; + emit([comment.posted_by, doc.is_open, doc.created_at], 1); + } + }); + } +} diff --git a/engines/support/app/designs/ticket/by_includes_post_by_and_is_open_and_updated_at.js b/engines/support/app/designs/ticket/by_includes_post_by_and_is_open_and_updated_at.js new file mode 100644 index 0000000..3bd2a74 --- /dev/null +++ b/engines/support/app/designs/ticket/by_includes_post_by_and_is_open_and_updated_at.js @@ -0,0 +1,12 @@ +function(doc) { + var arr = {} + if (doc['type'] == 'Ticket' && doc.comments) { + doc.comments.forEach(function(comment){ + if (comment.posted_by && !arr[comment.posted_by]) { + //don't add duplicates + arr[comment.posted_by] = true; + emit([comment.posted_by, doc.is_open, doc.updated_at], 1); + } + }); + } +} diff --git a/engines/support/app/designs/ticket/by_includes_post_by_and_updated_at.js b/engines/support/app/designs/ticket/by_includes_post_by_and_updated_at.js new file mode 100644 index 0000000..2b4304f --- /dev/null +++ b/engines/support/app/designs/ticket/by_includes_post_by_and_updated_at.js @@ -0,0 +1,12 @@ +function(doc) { + var arr = {} + if (doc['type'] == 'Ticket' && doc.comments) { + doc.comments.forEach(function(comment){ + if (comment.posted_by && !arr[comment.posted_by]) { + //don't add duplicates + arr[comment.posted_by] = true; + emit([comment.posted_by, doc.updated_at], 1); + } + }); + } +} diff --git a/engines/support/app/helpers/auto_tickets_path_helper.rb b/engines/support/app/helpers/auto_tickets_path_helper.rb new file mode 100644 index 0000000..93f3cb9 --- /dev/null +++ b/engines/support/app/helpers/auto_tickets_path_helper.rb @@ -0,0 +1,53 @@ +# +# These "auto" forms of the normal ticket path route helpers allow us to do two things automatically: +# +# (1) include the user in the path if appropriate. +# (2) retain the sort params, if appropriate. +# +# Tickets views with a user_id are limited to that user. For admins, they don't need a user_id for any ticket action. +# +# This is available both to the views and the tickets_controller. +# +module AutoTicketsPathHelper + + protected + + def auto_tickets_path(options={}) + return unless options.class == Hash + options = ticket_view_options.merge options + if @user + user_tickets_path(@user, options) + else + tickets_path(options) + end + end + + def auto_ticket_path(ticket, options={}) + options = ticket_view_options.merge options + if @user + user_ticket_path(@user, ticket, options) + else + ticket_path(ticket, options) + end + end + + def auto_new_ticket_path(options={}) + return unless options.class == Hash + options = ticket_view_options.merge options + if @user + new_user_ticket_path(@user, options) + else + new_ticket_path(options) + end + end + + private + + def ticket_view_options + hsh = {} + hsh[:open_status] = params[:open_status] if params[:open_status] && !params[:open_status].empty? + hsh[:sort_order] = params[:sort_order] if params[:sort_order] && !params[:sort_order].empty? + hsh + end + +end \ No newline at end of file diff --git a/engines/support/app/helpers/tickets_helper.rb b/engines/support/app/helpers/tickets_helper.rb new file mode 100644 index 0000000..7af50d6 --- /dev/null +++ b/engines/support/app/helpers/tickets_helper.rb @@ -0,0 +1,76 @@ +module TicketsHelper + # + # FORM HELPERS + # + + # + # hidden fields that should be added to ever ticket form. + # these are use for proper redirection after successful actions. + # + def hidden_ticket_fields + haml_concat hidden_field_tag('open_status', params[:open_status]) + haml_concat hidden_field_tag('sort_order', params[:sort_order]) + haml_concat hidden_field_tag('user_id', params[:user_id]) + "" + end + + # + # PARAM HELPERS + # + + def search_status + if action?(:index) + params[:open_status] || 'open' + else + nil + end + end + + def search_order + params[:sort_order] || 'updated_at_desc' + end + + # + # LINK HELPERS + # + + def link_to_status(new_status) + if new_status == "open" + label = t(:open_tickets) + elsif new_status == "closed" + label = t(:closed_tickets) + elsif new_status == "all" + label = t(:all_tickets) + end + link_to label, auto_tickets_path(:open_status => new_status, :sort_order => search_order) + end + + def link_to_order(order_field) + if search_order.start_with?(order_field) + # link for currently-filtered field. Link to other direction of this field. + if search_order.end_with? 'asc' + direction = 'desc' + icon_direction = 'up' + else + direction = 'asc' + icon_direction = 'down' + end + arrow = content_tag(:i, '', class: 'icon-arrow-'+ icon_direction) + else + # for not-currently-filtered field, don't display an arrow, and link to descending direction + arrow = '' + direction = 'desc' + end + + if order_field == 'updated' + label = t(:updated) + elsif order_field == 'created' + label = t(:created) + end + + link_to auto_tickets_path(:sort_order => order_field + '_at_' + direction, :open_status => search_status) do + arrow + label + end + end + +end diff --git a/engines/support/app/models/account_extension/tickets.rb b/engines/support/app/models/account_extension/tickets.rb new file mode 100644 index 0000000..f898b56 --- /dev/null +++ b/engines/support/app/models/account_extension/tickets.rb @@ -0,0 +1,13 @@ +module AccountExtension::Tickets + extend ActiveSupport::Concern + + def destroy_with_tickets + Ticket.destroy_all_from(self.user) + destroy_without_tickets + end + + included do + alias_method_chain :destroy, :tickets + end + +end diff --git a/engines/support/app/models/ticket.rb b/engines/support/app/models/ticket.rb new file mode 100644 index 0000000..cd22758 --- /dev/null +++ b/engines/support/app/models/ticket.rb @@ -0,0 +1,105 @@ +# +# TODO: thought i should reverse keys for descending, but that didn't work. +# look into whether that should be tweaked, and whether it works okay with +# pagination (seems to now...) +# +# TODO: better validation of email +# +# TODO: don't hardcode strings 'unknown user' and 'unauthenticated user' +# +class Ticket < CouchRest::Model::Base + use_database "tickets" + + property :created_by, String, :protected => true # nil for anonymous tickets, should never be changed + property :regarding_user, String # may be nil or valid username + property :subject, String + property :email, String + property :is_open, TrueClass, :default => true + property :comments, [TicketComment] + + timestamps! + + before_validation :set_email, :set_regarding_user, :on => :create + + design do + view :by_updated_at + view :by_created_at + view :by_created_by + + view :by_is_open_and_created_at + view :by_is_open_and_updated_at + + own_path = Pathname.new(File.dirname(__FILE__)) + load_views(own_path.join('..', 'designs', 'ticket')) + end + + validates :subject, :presence => true + validates :email, :allow_blank => true, :format => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/ + + def self.search(options = {}) + @selection = TicketSelection.new(options) + @selection.tickets + end + + def self.destroy_all_from(user) + self.by_created_by.key(user.id).each do |ticket| + ticket.destroy + end + end + + def is_creator_validated? + !!created_by + end + + def set_email + self.email = nil if self.email == "" + end + + def set_regarding_user + self.regarding_user = nil if self.regarding_user == "" + end + + def close + self.is_open = false + end + + def reopen + self.is_open = true + end + + def commenters + commenters = [] + self.comments.each do |comment| + if comment.posted_by + if user = User.find(comment.posted_by) + commenters << user.login if user and !commenters.include?(user.login) + else + commenters << 'unknown user' if !commenters.include?('unknown user') + end + else + commenters << 'unauthenticated user' if !commenters.include?('unauthenticated user') + end + end + commenters.join(', ') + end + + # + # update comments. User should be set by controller. + # + def comments_attributes=(attributes) + if attributes + comment = TicketComment.new(attributes.values.first) + comment.posted_at = Time.now + comments << comment + end + end + + def created_by_user + User.find(self.created_by) + end + + def regarding_user_actual_user + User.find_by_login(self.regarding_user) + end + +end diff --git a/engines/support/app/models/ticket_comment.rb b/engines/support/app/models/ticket_comment.rb new file mode 100644 index 0000000..bed5237 --- /dev/null +++ b/engines/support/app/models/ticket_comment.rb @@ -0,0 +1,43 @@ +class TicketComment + include CouchRest::Model::Embeddable + + #belongs_to :ticket #is this best way to do it? will want to access all of a tickets comments, so maybe this isn't the way? + property :posted_by, String#, :protected => true #Integer#this should be current_user if that is set, meaning the user is logged in #cannot have it be protected and set via comments_attributes=. also, if it is protected and we set in the tickets_controller, it gets unset. TODO---is this okay to have it not protected and manually check it? We do not users to be able to set this. + # if the current user is not set, then we could just say the comment comes from an 'unauthenticated user', which would be somebody with the secret URL + property :posted_at, Time#, :protected => true + #property :posted_verified, TrueClass, :protected => true #should be true if current_user is set when the comment is created + property :body, String + property :private, TrueClass # private comments are only viewable by admins #this is checked when set, to make sure it was set by an admin + + # ? timestamps! + validates :body, :presence => true + #before_validation :set_time#, :set_posted_by + + #design do + # view :by_posted_at + # view :by_body + #end + + def is_comment_validated? + !!posted_by + end + + def posted_by_user + User.find(posted_by) if posted_by + end + +=begin + #TODO. + #this is resetting all comments associated with the ticket: + def set_time + self.posted_at = Time.now + end +=end + +=begin + def set_posted_by + self.posted_by = User.current if User.current + end +=end + +end diff --git a/engines/support/app/models/ticket_selection.rb b/engines/support/app/models/ticket_selection.rb new file mode 100644 index 0000000..74d5b78 --- /dev/null +++ b/engines/support/app/models/ticket_selection.rb @@ -0,0 +1,71 @@ +class TicketSelection + + # + # supported options: + # + # user_id: id of the user (uuid string) + # open_status: open | closed | all + # sort_order: updated_at_desc | updated_at_asc | created_at_desc | created_at_asc + # admin_status: mine | all + # is_admin: true | false + # + def initialize(options = {}) + @user_id = options[:user_id].gsub /[^a-z0-9]/, '' + @open_status = allow options[:open_status], 'open', 'closed', 'all' + @sort_order = allow options[:sort_order], 'updated_at_desc', 'updated_at_asc', 'created_at_desc', 'created_at_asc' + @admin_status = allow options[:admin_status], 'mine', 'all' + @is_admin = allow options[:is_admin], false, true + end + + def tickets + Ticket.send(finder_method).startkey(startkey).endkey(endkey).send(order) + end + + protected + + def allow(source, *allowed) + if allowed.include?(source) + source + else + allowed.first + end + end + + def finder_method + method = 'by_' + method += 'includes_post_by_and_' if only_mine? + method += 'is_open_and_' if @open_status != 'all' + method += @sort_order.sub(/_(de|a)sc$/, '') + end + + def startkey + startkeys = [] + startkeys << @user_id if only_mine? + startkeys << (@open_status == 'open') if @open_status != 'all' + startkeys << 0 + startkeys = startkeys.join if startkeys.length == 1 # want string not array if just one thing in array + startkeys + end + + def endkey + endtime = Time.now + 2.days # TODO. this obviously isn't ideal + if self.startkey.is_a?(Array) + endkeys = self.startkey + endkeys.pop + endkeys << endtime + else + endtime + end + end + + def order + # we have defined the ascending method to return the view itself: + (@sort_order.end_with? 'desc') ? 'descending' : 'ascending' + end + + + def only_mine? + !@is_admin || @admin_status == 'mine' + end + +end diff --git a/engines/support/app/views/tickets/_comment.html.haml b/engines/support/app/views/tickets/_comment.html.haml new file mode 100644 index 0000000..778ca13 --- /dev/null +++ b/engines/support/app/views/tickets/_comment.html.haml @@ -0,0 +1,20 @@ +- if admin? or !comment.private # only show comment if user is admin or comment is not private + %tr + %td.user + %div + %strong + - if comment.posted_by_user + = comment.posted_by_user.login + - else + = t(:anonymous) + %div= comment.posted_at.to_s(:short) + - if comment.posted_by_user && comment.posted_by_user.is_admin? + %div + %span.label.label-inverse + = t(:admin) + - if comment.private + %div + %span.label.label-important + = t(:private) + %td.comment + = simple_format(comment.body) \ No newline at end of file diff --git a/engines/support/app/views/tickets/_edit_form.html.haml b/engines/support/app/views/tickets/_edit_form.html.haml new file mode 100644 index 0000000..714f8ff --- /dev/null +++ b/engines/support/app/views/tickets/_edit_form.html.haml @@ -0,0 +1,48 @@ +:ruby + # created by user link + if @ticket.created_by_user + created_by = link_to @ticket.created_by_user.login, @ticket.created_by_user + else + created_by = t(:anonymous) + end + + # regarding user link + if admin? + if @ticket.regarding_user_actual_user + regarding_user_link = link_to @ticket.regarding_user_actual_user.login, @ticket.regarding_user_actual_user + else + regarding_user_link = "(#{t(:unknown)})" + end + else + regarding_user_link = '' + end + += form_for @ticket do |f| + = hidden_ticket_fields + %p.first + - if @ticket.is_open? + %span.label.label-info= t(:open) + - else + %span.label.label-success= t(:closed) + %span.label.label-clear= t(:created_by_on, :user => created_by, :time => @ticket.created_at.to_s(:short)).html_safe + %div= t(:subject) + = f.text_field :subject, :class => 'large full-width' + .row-fluid + .span4 + %div= t(:status) + = f.select :is_open, [[t(:open), "true"], [t(:closed), "false"]] + .span4 + %div= t(:email) + = f.text_field :email + .span4 + %div + = t(:regarding_account) + = regarding_user_link + = f.text_field :regarding_user + = f.button t(:save), :name => 'commit', :class => 'btn', :type => 'submit', :value => 'save' + - if @ticket.is_open? + = f.button t(:close), :name => 'commit', :class => 'btn', :type => 'submit', :value => 'close' + - else + = f.button t(:open), :name => 'commit', :class => 'btn', :type => 'submit', :value => 'open' + - if admin? + = link_to t(:destroy), auto_ticket_path(@ticket), :confirm => t(:are_you_sure), :method => :delete, :class => 'btn' diff --git a/engines/support/app/views/tickets/_new_comment_form.html.haml b/engines/support/app/views/tickets/_new_comment_form.html.haml new file mode 100644 index 0000000..8418e01 --- /dev/null +++ b/engines/support/app/views/tickets/_new_comment_form.html.haml @@ -0,0 +1,13 @@ +-# +-# for posting a new comment to an existing ticket. +-# += simple_form_for @ticket, :html => {:class => 'slim'} do |f| + = hidden_ticket_fields + = f.simple_fields_for :comments, @comment, :wrapper => :none, :html => {:class => 'slim'} do |c| + = c.input :body, :label => false, :as => :text, :input_html => {:class => "full-width", :rows=> 5} + - if admin? + = c.input :private, :as => :boolean, :label => false, :inline_label => true + = f.button :button, t(:post_reply), :name => 'commit', :class => 'btn-primary', :type => 'submit', :value => 'post_reply' + - if logged_in? && @ticket.is_open + = f.button :button, t(:reply_and_close), :name => 'commit', :class => 'btn', :type => 'submit', :value => 'reply_and_close' + = link_to t(:cancel), auto_tickets_path, :class => :btn diff --git a/engines/support/app/views/tickets/_tabs.html.haml b/engines/support/app/views/tickets/_tabs.html.haml new file mode 100644 index 0000000..b7b5d3a --- /dev/null +++ b/engines/support/app/views/tickets/_tabs.html.haml @@ -0,0 +1,23 @@ +-# +-# SORT ORDER TABS +-# +- unless action?(:new) + %ul.nav.nav-pills.pull-right.slim + %li{:class=> ("active" if search_order.start_with? 'created_at')} + = link_to_order('created') + %li{:class=> ("active" if search_order.start_with? 'updated_at')} + = link_to_order('updated') + +-# +-# STATUS FILTER TABS +-# +%ul.nav.nav-tabs + - if logged_in? + %li{:class => ("active" if search_status == 'open')} + = link_to_status 'open' + %li{:class => ("active" if search_status == 'closed')} + = link_to_status 'closed' + %li{:class => ("active" if search_status == 'all')} + = link_to_status 'all' + %li{:class => ("active" if action?(:new))} + = link_to icon(:plus, :black) + t(:new_ticket), auto_new_ticket_path diff --git a/engines/support/app/views/tickets/_ticket.html.haml b/engines/support/app/views/tickets/_ticket.html.haml new file mode 100644 index 0000000..5bc33c8 --- /dev/null +++ b/engines/support/app/views/tickets/_ticket.html.haml @@ -0,0 +1,6 @@ +- url = auto_ticket_path(ticket) +%tr + %td= link_to ticket.subject, url + %td= link_to ticket.created_at.to_s(:short), url + %td= link_to ticket.updated_at.to_s(:short), url + %td= ticket.commenters diff --git a/engines/support/app/views/tickets/index.html.haml b/engines/support/app/views/tickets/index.html.haml new file mode 100644 index 0000000..c02a326 --- /dev/null +++ b/engines/support/app/views/tickets/index.html.haml @@ -0,0 +1,19 @@ +- @show_navigation = !params[:user_id].nil? + += render 'tickets/tabs' + +%table.table.table-striped.table-bordered + %thead + %tr + %th= t(:subject) + %th= t(:created) + %th= t(:updated) + %th= t(:voices) + %tbody + - if @tickets.any? + = render @tickets.all + - else + %tr + %td{:colspan=>4}= t(:none) + += paginate @tickets diff --git a/engines/support/app/views/tickets/new.html.haml b/engines/support/app/views/tickets/new.html.haml new file mode 100644 index 0000000..8f217a5 --- /dev/null +++ b/engines/support/app/views/tickets/new.html.haml @@ -0,0 +1,30 @@ +- @show_navigation = !params[:user_id].nil? + += render 'tickets/tabs' + +- if admin? && @user + - email = @user.email_address + - regarding = @user.login +- elsif logged_in? + - email = current_user.email_address + - regarding = current_user.login + += simple_form_for @ticket, :validate => true, :html => {:class => 'form-horizontal'} do |f| + = hidden_ticket_fields + = f.input :subject + - if logged_in? + = f.input :email, input_html: {value: email} + = f.input :regarding_user, input_html: {value: regarding} + - else + = f.input :email + = f.input :regarding_user + = f.simple_fields_for :comments, @comment do |c| + = c.input :body, :label => t(:description), :as => :text, :input_html => {:class => "full-width", :rows=> 5} + - if admin? + = c.input :private, :as => :boolean, :label => false, :inline_label => true + .form-actions + = f.button :submit, :class => 'btn-primary', :value => t(:create_thing, :thing => t(:ticket)) + - if logged_in? + = link_to t(:cancel), auto_tickets_path, :class => :btn + - else + = link_to t(:cancel), home_path, :class => 'btn' \ No newline at end of file diff --git a/engines/support/app/views/tickets/show.html.haml b/engines/support/app/views/tickets/show.html.haml new file mode 100644 index 0000000..bfdb773 --- /dev/null +++ b/engines/support/app/views/tickets/show.html.haml @@ -0,0 +1,12 @@ +- @show_navigation = !params[:user_id].nil? + +.ticket + = render 'tickets/edit_form' + %table.table.table-striped.table-bordered + %tbody + = render :partial => 'tickets/comment', :collection => @ticket.comments + %tr + %td.user + = logged_in? ? current_user.login : t(:anonymous) + %td.comment + = render 'tickets/new_comment_form' \ No newline at end of file diff --git a/engines/support/config/initializers/account_lifecycle.rb b/engines/support/config/initializers/account_lifecycle.rb new file mode 100644 index 0000000..d9f04c1 --- /dev/null +++ b/engines/support/config/initializers/account_lifecycle.rb @@ -0,0 +1,3 @@ +ActiveSupport.on_load(:account) do + include AccountExtension::Tickets +end diff --git a/engines/support/config/locales/en.yml b/engines/support/config/locales/en.yml new file mode 100644 index 0000000..342adea --- /dev/null +++ b/engines/support/config/locales/en.yml @@ -0,0 +1,22 @@ +en: + access_ticket_text: > + You can later access this ticket at the URL %{full_url}. You might want to bookmark this page to find it again. + Anybody with this URL will be able to access this ticket, so if you are on a shared computer you might want to + remove it from the browser history. + support_tickets: "Support Tickets" + all_tickets: "All Tickets" + my_tickets: "My Tickets" + open_tickets: "Open Tickets" + closed_tickets: "Closed Tickets" + new_ticket: "New Ticket" + tickets: "Tickets" + subject: "Subject" + destroy: "Destroy" + open: "Open" + closed: "Closed" + close: "Close" + post_reply: "Post Reply" + reply_and_close: "Reply and Close" + description: "Description" + ticket: "Ticket" + regarding_account: "Regarding Account" \ No newline at end of file diff --git a/engines/support/config/routes.rb b/engines/support/config/routes.rb new file mode 100644 index 0000000..23e0c11 --- /dev/null +++ b/engines/support/config/routes.rb @@ -0,0 +1,8 @@ +Rails.application.routes.draw do + scope "(:locale)", :locale => MATCH_LOCALE do + resources :tickets, :except => :edit + resources :users do + resources :tickets, :except => :edit + end + end +end diff --git a/engines/support/leap_web_help.gemspec b/engines/support/leap_web_help.gemspec new file mode 100644 index 0000000..41959d6 --- /dev/null +++ b/engines/support/leap_web_help.gemspec @@ -0,0 +1,18 @@ +$:.push File.expand_path("../../lib", __FILE__) + +require File.expand_path('../../../lib/leap_web/version.rb', __FILE__) + +# Describe your gem and declare its dependencies: +Gem::Specification.new do |s| + s.name = "leap_web_help" + s.version = LeapWeb::VERSION + s.authors = ["Jessib"] + s.email = ["jessib@leap.se"] + s.homepage = "http://www.leap.se" + s.summary = "Help Desk for LeapWeb" + s.description = "Managing Tickets for a Leap provider" + + s.files = Dir["{app,config,db,lib}/**/*"] + ["Rakefile", "README.md"] + s.test_files = Dir["test/**/*"] + +end diff --git a/engines/support/lib/leap_web_help.rb b/engines/support/lib/leap_web_help.rb new file mode 100644 index 0000000..f5b04aa --- /dev/null +++ b/engines/support/lib/leap_web_help.rb @@ -0,0 +1,4 @@ +require "leap_web_help/engine" + +module LeapWebHelp +end diff --git a/engines/support/lib/leap_web_help/engine.rb b/engines/support/lib/leap_web_help/engine.rb new file mode 100644 index 0000000..dfa763f --- /dev/null +++ b/engines/support/lib/leap_web_help/engine.rb @@ -0,0 +1,4 @@ +module LeapWebHelp + class Engine < ::Rails::Engine + end +end diff --git a/engines/support/lib/tasks/leap_web_help_tasks.rake b/engines/support/lib/tasks/leap_web_help_tasks.rake new file mode 100644 index 0000000..1f38982 --- /dev/null +++ b/engines/support/lib/tasks/leap_web_help_tasks.rake @@ -0,0 +1,4 @@ +# desc "Explaining what the task does" +# task :leap_web_help do +# # Task goes here +# end diff --git a/engines/support/script/rails b/engines/support/script/rails new file mode 100755 index 0000000..5676ab9 --- /dev/null +++ b/engines/support/script/rails @@ -0,0 +1,8 @@ +#!/usr/bin/env ruby +# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. + +ENGINE_ROOT = File.expand_path('../..', __FILE__) +ENGINE_PATH = File.expand_path('../../lib/leap_web_help/engine', __FILE__) + +require 'rails/all' +require 'rails/engine/commands' diff --git a/engines/support/test/factories.rb b/engines/support/test/factories.rb new file mode 100644 index 0000000..be04f15 --- /dev/null +++ b/engines/support/test/factories.rb @@ -0,0 +1,18 @@ +FactoryGirl.define do + + factory :ticket do + subject { Faker::Lorem.sentence } + email { Faker::Internet.email } + + factory :ticket_with_comment do + comments_attributes do + { "0" => { "body" => Faker::Lorem.sentences.join(" ") } } + end + end + + factory :ticket_with_creator do + created_by { FactoryGirl.create(:user).id } + end + end + +end diff --git a/engines/support/test/functional/tickets_controller_test.rb b/engines/support/test/functional/tickets_controller_test.rb new file mode 100644 index 0000000..416fb73 --- /dev/null +++ b/engines/support/test/functional/tickets_controller_test.rb @@ -0,0 +1,273 @@ +require 'test_helper' + +class TicketsControllerTest < ActionController::TestCase + + teardown do + # destroy all tickets that were created during the test + Ticket.all.each{|t| t.destroy} + end + + test "should get index if logged in" do + login + get :index + assert_response :success + assert_not_nil assigns(:tickets) + end + + test "no index if not logged in" do + get :index + assert_response :redirect + assert_nil assigns(:tickets) + end + + test "should get new" do + get :new + assert_equal Ticket, assigns(:ticket).class + assert_response :success + end + + test "unauthenticated tickets are visible" do + ticket = find_record :ticket, :created_by => nil + get :show, :id => ticket.id + assert_response :success + end + + test "user tickets are not visible without login" do + user = find_record :user + ticket = find_record :ticket, :created_by => user.id + get :show, :id => ticket.id + assert_response :redirect + assert_redirected_to login_url + end + + test "user tickets are visible to creator" do + user = find_record :user + ticket = find_record :ticket, :created_by => user.id + login user + get :show, :id => ticket.id + assert_response :success + end + + test "other users tickets are not visible" do + other_user = find_record :user + ticket = find_record :ticket, :created_by => other_user.id + login + get :show, :id => ticket.id + assert_response :redirect + assert_redirected_to home_url + end + + test "should create unauthenticated ticket" do + params = {:subject => "unauth ticket test subject", :comments_attributes => {"0" => {"body" =>"body of test ticket"}}} + + assert_difference('Ticket.count') do + post :create, :ticket => params + end + + assert_response :redirect + assert_nil assigns(:ticket).created_by + + assert_equal 1, assigns(:ticket).comments.count + assert_nil assigns(:ticket).comments.first.posted_by + + end + + test "should create authenticated ticket" do + + params = {:subject => "auth ticket test subject", :comments_attributes => {"0" => {"body" =>"body of test ticket"}}} + + login + + assert_difference('Ticket.count') do + post :create, :ticket => params + end + + assert_response :redirect + + assert_not_nil assigns(:ticket).created_by + assert_equal assigns(:ticket).created_by, @current_user.id + assert_equal assigns(:ticket).email, @current_user.email_address + + assert_equal 1, assigns(:ticket).comments.count + assert_not_nil assigns(:ticket).comments.first.posted_by + assert_equal assigns(:ticket).comments.first.posted_by, @current_user.id + end + + test "add comment to unauthenticated ticket" do + ticket = FactoryGirl.create :ticket, :created_by => nil + + assert_difference('Ticket.find(ticket.id).comments.count') do + put :update, :id => ticket.id, + :ticket => {:comments_attributes => {"0" => {"body" =>"NEWER comment"}} } + end + + assert_equal ticket, assigns(:ticket) # still same ticket, with different comments + assert_not_equal ticket.comments, assigns(:ticket).comments # ticket == assigns(:ticket), but they have different comments (which we want) + + end + + + test "add comment to own authenticated ticket" do + + login + ticket = FactoryGirl.create :ticket, :created_by => @current_user.id + + #they should be able to comment if it is their ticket: + assert_difference('Ticket.find(ticket.id).comments.count') do + put :update, :id => ticket.id, + :ticket => {:comments_attributes => {"0" => {"body" =>"NEWER comment"}} } + end + assert_not_equal ticket.comments, assigns(:ticket).comments + assert_not_nil assigns(:ticket).comments.last.posted_by + assert_equal assigns(:ticket).comments.last.posted_by, @current_user.id + + end + + + test "cannot comment if it is not your ticket" do + + other_user = find_record :user + login :is_admin? => false, :email => nil + ticket = FactoryGirl.create :ticket, :created_by => other_user.id + # they should *not* be able to comment if it is not their ticket + put :update, :id => ticket.id, :ticket => {:comments_attributes => {"0" => {"body" =>"not allowed comment"}} } + assert_response :redirect + assert_access_denied + + assert_equal ticket.comments.map(&:body), assigns(:ticket).comments.map(&:body) + + end + + + test "admin add comment to authenticated ticket" do + + other_user = find_record :user + login :is_admin? => true + + ticket = FactoryGirl.create :ticket, :created_by => other_user.id + + #admin should be able to comment: + assert_difference('Ticket.find(ticket.id).comments.count') do + put :update, :id => ticket.id, + :ticket => {:comments_attributes => {"0" => {"body" =>"NEWER comment"}} } + end + assert_not_equal ticket.comments, assigns(:ticket).comments + assert_not_nil assigns(:ticket).comments.last.posted_by + assert_equal assigns(:ticket).comments.last.posted_by, @current_user.id + end + + test "tickets by admin" do + other_user = find_record :user + ticket = FactoryGirl.create :ticket, :created_by => other_user.id + + login :is_admin? => true + + get :index, {:admin_status => "all", :open_status => "open"} + assert assigns(:all_tickets).count > 0 + + # if we close one ticket, the admin should have 1 less open ticket + assert_difference('assigns[:all_tickets].count', -1) do + assigns(:tickets).first.close + assigns(:tickets).first.save + get :index, {:admin_status => "all", :open_status => "open"} + end + end + + + test "admin_status mine vs all" do + testticket = FactoryGirl.create :ticket + user = find_record :user + login :is_admin? => true, :email => nil + + get :index, {:open_status => "open"} + assert assigns(:all_tickets).include?(testticket) + get :index, {:user_id => user.id, :open_status => "open"} + assert !assigns(:all_tickets).include?(testticket) + end + + test "commenting on a ticket adds to tickets that are mine" do + testticket = FactoryGirl.create :ticket + user = find_record :admin_user + login user + get :index, {:user_id => user.id, :open_status => "open"} + assert_difference('assigns[:all_tickets].count') do + put :update, :id => testticket.id, :ticket => {:comments_attributes => {"0" => {"body" =>"NEWER comment"}}} + get :index, {:user_id => user.id, :open_status => "open"} + end + + assert assigns(:all_tickets).include?(assigns(:ticket)) + assert_not_nil assigns(:ticket).comments.last.posted_by + assert_equal assigns(:ticket).comments.last.posted_by, @current_user.id + end + + test "admin ticket ordering" do + tickets = FactoryGirl.create_list :ticket, 2 + + login :is_admin? => true, :email => nil + get :index, {:admin_status => "all", :open_status => "open", :sort_order => 'created_at_desc'} + + # this will consider all tickets, not just those on first page + first_tick = assigns(:all_tickets).all.first + last_tick = assigns(:all_tickets).all.last + assert first_tick.created_at > last_tick.created_at + + # and now reverse order: + get :index, {:admin_status => "all", :open_status => "open", :sort_order => 'created_at_asc'} + + assert_equal first_tick, assigns(:all_tickets).last + assert_equal last_tick, assigns(:all_tickets).first + + assert_not_equal first_tick, assigns(:all_tickets).first + assert_not_equal last_tick, assigns(:all_tickets).last + + end + + test "tickets for regular user" do + login + ticket = FactoryGirl.create :ticket + other_ticket = FactoryGirl.create :ticket + + put :update, :id => ticket.id, + :ticket => {:comments_attributes => {"0" => {"body" =>"NEWER comment"}} } + assert_not_nil assigns(:ticket).comments.last.posted_by + assert_equal assigns(:ticket).comments.last.posted_by, @current_user.id + + get :index, {:open_status => "open"} + assert assigns(:all_tickets).count > 0 + assert assigns(:all_tickets).include?(ticket) + assert !assigns(:all_tickets).include?(other_ticket) + + # user should have one more ticket if a new tick gets a comment by this user + assert_difference('assigns[:all_tickets].count') do + put :update, :id => other_ticket.id, :ticket => {:comments_attributes => {"0" => {"body" =>"NEWER comment"}}} + get :index, {:open_status => "open"} + end + assert assigns(:all_tickets).include?(other_ticket) + + # if we close one ticket, the user should have 1 less open ticket + assert_difference('assigns[:all_tickets].count', -1) do + other_ticket.reload + other_ticket.close + other_ticket.save + get :index, {:open_status => "open"} + end + + number_open_tickets = assigns(:all_tickets).count + + # look at closed tickets: + get :index, {:open_status => "closed"} + assert !assigns(:all_tickets).include?(ticket) + assert assigns(:all_tickets).include?(other_ticket) + number_closed_tickets = assigns(:all_tickets).count + + # all tickets should equal closed + open + get :index, {:open_status => "all"} + assert assigns(:all_tickets).include?(ticket) + assert assigns(:all_tickets).include?(other_ticket) + assert_equal assigns(:all_tickets).count, number_closed_tickets + number_open_tickets + + + end + +end + diff --git a/engines/support/test/integration/navigation_test.rb b/engines/support/test/integration/navigation_test.rb new file mode 100644 index 0000000..eec8c0e --- /dev/null +++ b/engines/support/test/integration/navigation_test.rb @@ -0,0 +1,9 @@ +require 'test_helper' + +class NavigationTest < ActionDispatch::IntegrationTest + + # test "the truth" do + # assert true + # end +end + diff --git a/engines/support/test/leap_web_help_test.rb b/engines/support/test/leap_web_help_test.rb new file mode 100644 index 0000000..d74c087 --- /dev/null +++ b/engines/support/test/leap_web_help_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class LeapWebHelpTest < ActiveSupport::TestCase + test "truth" do + assert_kind_of Module, LeapWebHelp + end +end diff --git a/engines/support/test/test_helper.rb b/engines/support/test/test_helper.rb new file mode 100644 index 0000000..fff9173 --- /dev/null +++ b/engines/support/test/test_helper.rb @@ -0,0 +1,15 @@ +# Configure Rails Environment +ENV["RAILS_ENV"] = "test" + +require File.expand_path('../../../../test/dummy/config/environment', __FILE__) +require "rails/test_help" + +Rails.backtrace_cleaner.remove_silencers! + +# Load support files +Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f } + +# Load fixtures from the engine +if ActiveSupport::TestCase.method_defined?(:fixture_path=) + ActiveSupport::TestCase.fixture_path = File.expand_path("../fixtures", __FILE__) +end diff --git a/engines/support/test/unit/account_extension_test.rb b/engines/support/test/unit/account_extension_test.rb new file mode 100644 index 0000000..aba162c --- /dev/null +++ b/engines/support/test/unit/account_extension_test.rb @@ -0,0 +1,12 @@ +require 'test_helper' + +class AccountExtensionTest < ActiveSupport::TestCase + + test "destroying an account triggers ticket destruction" do + t = FactoryGirl.create :ticket_with_creator + u = t.created_by_user + Account.new(u).destroy + assert_equal nil, Ticket.find(t.id) + end + +end diff --git a/engines/support/test/unit/ticket_comment_test.rb b/engines/support/test/unit/ticket_comment_test.rb new file mode 100644 index 0000000..fe8cc95 --- /dev/null +++ b/engines/support/test/unit/ticket_comment_test.rb @@ -0,0 +1,59 @@ +require 'test_helper' + +class TicketCommentTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end + +=begin + setup do + @sample_ticket = Ticket.create :title => 'test ticket' + @sample_ticket.save + end +=end + + test "create" do + + comment2 = TicketComment.new :body => "help my email is broken!" + assert comment2.valid? + #assert_not_nil comment2.posted_at #? + #assert_nil comment2.posted_by #if not logged in #TODO + + #comment.ticket = testticket #Ticket.find_by_title("testing") + #assert_equal testticket.title, comment.ticket.title + + #tc.ticket = Ticket.find_by_title("test title") + #tc.ticket.title + end + +=begin + test "create authenticated comment" do + User.current = 4 + comment2 = TicketComment.new :body => "help my email is broken!" + comment2.valid? #save # should not save comment + assert_not_nil comment2.posted_by + end +=end + + test "add comments" do + testticket = Ticket.create :subject => "testing" + assert_equal testticket.comments.count, 0 + comment = TicketComment.new :body => "my email broke" + #assert comment.valid? #validating or saving necessary for setting posted_at + #assert_not_nil comment.posted_at + + testticket.comments << comment + assert_equal testticket.comments.count, 1 + sleep(1) # so first comment has earlier posted_at time + comment2 = TicketComment.new :body => "my email broke" + testticket.comments << comment2 #this should validate comment2 + testticket.valid? + assert_equal testticket.comments.count, 2 + testticket.reload.destroy + # where should posted_at be set? + #assert_not_nil comment.posted_at + #assert_not_nil testticket.comments.last.posted_at + #assert testticket.comments.first.posted_at < testticket.comments.last.posted_at + end + +end diff --git a/engines/support/test/unit/ticket_test.rb b/engines/support/test/unit/ticket_test.rb new file mode 100644 index 0000000..f5e6ea7 --- /dev/null +++ b/engines/support/test/unit/ticket_test.rb @@ -0,0 +1,88 @@ +require 'test_helper' + +class TicketTest < ActiveSupport::TestCase + + test "ticket with default attribs is valid" do + t = FactoryGirl.build :ticket + assert t.valid? + end + + test "ticket without email is valid" do + t = FactoryGirl.build :ticket, email: "" + assert t.valid? + end + + test "ticket validates email format" do + t = FactoryGirl.build :ticket, email: "aswerssfd" + assert !t.valid? + end + + test "ticket open states" do + t = FactoryGirl.build :ticket + assert t.is_open + t.close + assert !t.is_open + t.reopen + assert t.is_open + end + + test "creation validated" do + @sample = Ticket.new + assert !@sample.is_creator_validated? + #p current_user + @sample.created_by = 22 #current_user + assert @sample.is_creator_validated? + end + + test "destroy all tickets from a user" do + t = FactoryGirl.create :ticket_with_creator + u = t.created_by_user + Ticket.destroy_all_from(u) + assert_equal nil, Ticket.find(t.id) + end +=begin +# TODO: do once have current_user stuff in order + test "code if & only if not creator-validated" do + User.current_test = nil + t1 = Ticket.create :subject => 'test title' + assert_not_nil t1.code + assert_nil t1.created_by + + User.current_test = 4 + t2 = Ticket.create :subject => 'test title' + assert_nil t2.code + assert_not_nil t2.created_by + end +=end + + + test "find tickets user commented on" do + + # clear old tickets just in case + # this will cause RestClient::ResourceNotFound errors if there are multiple copies of the same ticket returned + Ticket.by_includes_post_by.key('123').each {|t| t.destroy} + # TODO: the by_includes_post_by view is only used for tests. Maybe we should get rid of it and change the test to including ordering? + + + testticket = Ticket.create :subject => "test retrieving commented tickets" + comment = TicketComment.new :body => "my email broke", :posted_by => "123" + assert_equal 0, testticket.comments.count + assert_equal [], Ticket.by_includes_post_by.key('123').all + + testticket.comments << comment + testticket.save + assert_equal 1, testticket.reload.comments.count + assert_equal [testticket], Ticket.by_includes_post_by.key('123').all + + comment = TicketComment.new :body => "another comment", :posted_by => "123" + testticket.comments << comment + testticket.save + + # this will ensure that the ticket is only included once, even though the user has commented on the ticket twice: + assert_equal [testticket], Ticket.by_includes_post_by.key('123').all + + testticket.destroy + assert_equal [], Ticket.by_includes_post_by.key('123').all; + end + +end -- cgit v1.2.3 From 38558224e10f3fddba29aaa25397495a0fded263 Mon Sep 17 00:00:00 2001 From: Azul Date: Fri, 11 Apr 2014 10:06:02 +0200 Subject: minor: our engines do not have a db directory --- engines/support/leap_web_help.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines/support') diff --git a/engines/support/leap_web_help.gemspec b/engines/support/leap_web_help.gemspec index 41959d6..7b668d5 100644 --- a/engines/support/leap_web_help.gemspec +++ b/engines/support/leap_web_help.gemspec @@ -12,7 +12,7 @@ Gem::Specification.new do |s| s.summary = "Help Desk for LeapWeb" s.description = "Managing Tickets for a Leap provider" - s.files = Dir["{app,config,db,lib}/**/*"] + ["Rakefile", "README.md"] + s.files = Dir["{app,config,lib}/**/*"] + ["Rakefile", "README.md"] s.test_files = Dir["test/**/*"] end -- cgit v1.2.3 From 7a9ece43bd61246b450471ed6bb1089570321e38 Mon Sep 17 00:00:00 2001 From: Azul Date: Thu, 17 Apr 2014 19:27:47 +0200 Subject: make use of the UnauthorizedUser Null Pattern for current_user - use it to get rid of some conditionals --- .../support/app/controllers/tickets_controller.rb | 36 ++++++++++++++-------- engines/support/app/views/tickets/new.html.haml | 18 +++-------- engines/support/app/views/tickets/show.html.haml | 4 +-- 3 files changed, 30 insertions(+), 28 deletions(-) (limited to 'engines/support') diff --git a/engines/support/app/controllers/tickets_controller.rb b/engines/support/app/controllers/tickets_controller.rb index d65ee43..cf8743a 100644 --- a/engines/support/app/controllers/tickets_controller.rb +++ b/engines/support/app/controllers/tickets_controller.rb @@ -5,7 +5,8 @@ class TicketsController < ApplicationController #has_scope :open, :type => boolean before_filter :require_login, :only => [:index] - before_filter :fetch_ticket, :only => [:show, :update, :destroy] # don't now have an edit method + before_filter :fetch_ticket, :only => [:show, :update, :destroy] + before_filter :require_ticket_access, :only => [:show, :update, :destroy] before_filter :fetch_user before_filter :set_title @@ -17,11 +18,11 @@ class TicketsController < ApplicationController def create @ticket = Ticket.new(params[:ticket]) - @ticket.comments.last.posted_by = (logged_in? ? current_user.id : nil) #protecting posted_by isn't working, so this should protect it. + #protecting posted_by isn't working, so this should protect it: + @ticket.comments.last.posted_by = current_user.id @ticket.comments.last.private = false unless admin? - @ticket.created_by = current_user.id if logged_in? - @ticket.email = current_user.email_address if logged_in? and current_user.email_address - + @ticket.created_by = current_user.id + @ticket.email = current_user.email_address if current_user.email_address if @ticket.save flash[:notice] = t(:thing_was_successfully_created, :thing => t(:ticket)) end @@ -58,7 +59,7 @@ class TicketsController < ApplicationController end if @ticket.comments_changed? - @ticket.comments.last.posted_by = (current_user ? current_user.id : nil) + @ticket.comments.last.posted_by = current_user.id @ticket.comments.last.private = false unless admin? end @@ -120,19 +121,28 @@ class TicketsController < ApplicationController return ticket end - def ticket_access? - @ticket and (admin? or !@ticket.created_by or (current_user and current_user.id == @ticket.created_by)) - end - def fetch_ticket @ticket = Ticket.find(params[:id]) - if !@ticket and admin? - redirect_to auto_tickets_path, :alert => t(:no_such_thing, :thing => 'ticket') - return + if !@ticket + if admin? + redirect_to auto_tickets_path, + alert: t(:no_such_thing, thing: 'ticket') + else + access_denied + end end + end + + def require_ticket_access access_denied unless ticket_access? end + def ticket_access? + admin? or + @ticket.created_by.blank? or + current_user.id == @ticket.created_by + end + def fetch_user if params[:user_id] @user = User.find(params[:user_id]) diff --git a/engines/support/app/views/tickets/new.html.haml b/engines/support/app/views/tickets/new.html.haml index 8f217a5..e391499 100644 --- a/engines/support/app/views/tickets/new.html.haml +++ b/engines/support/app/views/tickets/new.html.haml @@ -2,22 +2,14 @@ = render 'tickets/tabs' -- if admin? && @user - - email = @user.email_address - - regarding = @user.login -- elsif logged_in? - - email = current_user.email_address - - regarding = current_user.login +- user = @user if admin? +- user ||= current_user = simple_form_for @ticket, :validate => true, :html => {:class => 'form-horizontal'} do |f| = hidden_ticket_fields = f.input :subject - - if logged_in? - = f.input :email, input_html: {value: email} - = f.input :regarding_user, input_html: {value: regarding} - - else - = f.input :email - = f.input :regarding_user + = f.input :email, input_html: {value: user.email} + = f.input :regarding_user, input_html: {value: user.login} = f.simple_fields_for :comments, @comment do |c| = c.input :body, :label => t(:description), :as => :text, :input_html => {:class => "full-width", :rows=> 5} - if admin? @@ -27,4 +19,4 @@ - if logged_in? = link_to t(:cancel), auto_tickets_path, :class => :btn - else - = link_to t(:cancel), home_path, :class => 'btn' \ No newline at end of file + = link_to t(:cancel), home_path, :class => 'btn' diff --git a/engines/support/app/views/tickets/show.html.haml b/engines/support/app/views/tickets/show.html.haml index bfdb773..edb6e6f 100644 --- a/engines/support/app/views/tickets/show.html.haml +++ b/engines/support/app/views/tickets/show.html.haml @@ -7,6 +7,6 @@ = render :partial => 'tickets/comment', :collection => @ticket.comments %tr %td.user - = logged_in? ? current_user.login : t(:anonymous) + = current_user.login || t(:anonymous) %td.comment - = render 'tickets/new_comment_form' \ No newline at end of file + = render 'tickets/new_comment_form' -- cgit v1.2.3 From 40dfa63aa6fc7aa3614f2a7952d088d8ff067f70 Mon Sep 17 00:00:00 2001 From: Azul Date: Fri, 18 Apr 2014 10:29:07 +0200 Subject: minor fix: User#email_address not User#email --- engines/support/app/views/tickets/new.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines/support') diff --git a/engines/support/app/views/tickets/new.html.haml b/engines/support/app/views/tickets/new.html.haml index e391499..8a89703 100644 --- a/engines/support/app/views/tickets/new.html.haml +++ b/engines/support/app/views/tickets/new.html.haml @@ -8,7 +8,7 @@ = simple_form_for @ticket, :validate => true, :html => {:class => 'form-horizontal'} do |f| = hidden_ticket_fields = f.input :subject - = f.input :email, input_html: {value: user.email} + = f.input :email, input_html: {value: user.email_address} = f.input :regarding_user, input_html: {value: user.login} = f.simple_fields_for :comments, @comment do |c| = c.input :body, :label => t(:description), :as => :text, :input_html => {:class => "full-width", :rows=> 5} -- cgit v1.2.3 From c275f43147e7a8ab54623bdc5b9a8124b8592330 Mon Sep 17 00:00:00 2001 From: Azul Date: Tue, 22 Apr 2014 14:39:43 +0200 Subject: return nil as auto_ticket_path for invalid tickets The auto_ticket_path is referenced from the tickets_controller like this: respond_with(@ticket, :location => auto_ticket_path(@ticket)) While this only uses the location parameter when the ticket is valid it will still attampt to calculate it if not. During the create action this will lead to crashes because the ticket_path can not be calculated for a ticket without an id. This led to https://leap.se/code/issues/5552 and probably https://leap.se/code/issues/5545. --- engines/support/app/helpers/auto_tickets_path_helper.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'engines/support') diff --git a/engines/support/app/helpers/auto_tickets_path_helper.rb b/engines/support/app/helpers/auto_tickets_path_helper.rb index 93f3cb9..5638222 100644 --- a/engines/support/app/helpers/auto_tickets_path_helper.rb +++ b/engines/support/app/helpers/auto_tickets_path_helper.rb @@ -23,6 +23,7 @@ module AutoTicketsPathHelper end def auto_ticket_path(ticket, options={}) + return unless ticket.persisted? options = ticket_view_options.merge options if @user user_ticket_path(@user, ticket, options) @@ -50,4 +51,4 @@ module AutoTicketsPathHelper hsh end -end \ No newline at end of file +end -- cgit v1.2.3 From c5c54ec2035813949a81e8b5977a8f2538897260 Mon Sep 17 00:00:00 2001 From: Azul Date: Tue, 22 Apr 2014 14:40:27 +0200 Subject: let's only add the flash notice if the ticket has been created --- engines/support/app/controllers/tickets_controller.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'engines/support') diff --git a/engines/support/app/controllers/tickets_controller.rb b/engines/support/app/controllers/tickets_controller.rb index d65ee43..4be3493 100644 --- a/engines/support/app/controllers/tickets_controller.rb +++ b/engines/support/app/controllers/tickets_controller.rb @@ -24,11 +24,11 @@ class TicketsController < ApplicationController if @ticket.save flash[:notice] = t(:thing_was_successfully_created, :thing => t(:ticket)) - end - # cannot set this until ticket has been saved, as @ticket.id will not be set - if !logged_in? and flash[:notice] - flash[:notice] += " " + t(:access_ticket_text, :full_url => ticket_url(@ticket.id)) + # cannot set this until ticket has been saved, as @ticket.id will not be set + if !logged_in? and flash[:notice] + flash[:notice] += " " + t(:access_ticket_text, :full_url => ticket_url(@ticket.id)) + end end respond_with(@ticket, :location => auto_ticket_path(@ticket)) end -- cgit v1.2.3 From 7df11eed6aa48d1f61ee7f3700295c78b62358f0 Mon Sep 17 00:00:00 2001 From: Azul Date: Tue, 22 Apr 2014 14:43:19 +0200 Subject: check user_id param for present? instead of !nil? when rendered from teh create action due to an error user_id param will sometimes be an empty string. We should still avoid rendering the navigation because the path's can not be resolved without a user_id. --- engines/support/app/views/tickets/index.html.haml | 2 +- engines/support/app/views/tickets/new.html.haml | 4 ++-- engines/support/app/views/tickets/show.html.haml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'engines/support') diff --git a/engines/support/app/views/tickets/index.html.haml b/engines/support/app/views/tickets/index.html.haml index c02a326..a4df6e3 100644 --- a/engines/support/app/views/tickets/index.html.haml +++ b/engines/support/app/views/tickets/index.html.haml @@ -1,4 +1,4 @@ -- @show_navigation = !params[:user_id].nil? +- @show_navigation = params[:user_id].present? = render 'tickets/tabs' diff --git a/engines/support/app/views/tickets/new.html.haml b/engines/support/app/views/tickets/new.html.haml index 8f217a5..ba86ac3 100644 --- a/engines/support/app/views/tickets/new.html.haml +++ b/engines/support/app/views/tickets/new.html.haml @@ -1,4 +1,4 @@ -- @show_navigation = !params[:user_id].nil? +- @show_navigation = params[:user_id].present? = render 'tickets/tabs' @@ -27,4 +27,4 @@ - if logged_in? = link_to t(:cancel), auto_tickets_path, :class => :btn - else - = link_to t(:cancel), home_path, :class => 'btn' \ No newline at end of file + = link_to t(:cancel), home_path, :class => 'btn' diff --git a/engines/support/app/views/tickets/show.html.haml b/engines/support/app/views/tickets/show.html.haml index bfdb773..bbca4bf 100644 --- a/engines/support/app/views/tickets/show.html.haml +++ b/engines/support/app/views/tickets/show.html.haml @@ -1,4 +1,4 @@ -- @show_navigation = !params[:user_id].nil? +- @show_navigation = params[:user_id].present? .ticket = render 'tickets/edit_form' @@ -9,4 +9,4 @@ %td.user = logged_in? ? current_user.login : t(:anonymous) %td.comment - = render 'tickets/new_comment_form' \ No newline at end of file + = render 'tickets/new_comment_form' -- cgit v1.2.3 From 5d6a82a67bffc0930ea480164be2aca60ea0d6a1 Mon Sep 17 00:00:00 2001 From: Azul Date: Tue, 22 Apr 2014 14:44:11 +0200 Subject: add tests for invalid ticket creation --- .../test/functional/tickets_controller_test.rb | 11 +++++++++ .../support/test/integration/create_ticket_test.rb | 28 ++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 engines/support/test/integration/create_ticket_test.rb (limited to 'engines/support') diff --git a/engines/support/test/functional/tickets_controller_test.rb b/engines/support/test/functional/tickets_controller_test.rb index 416fb73..d746b59 100644 --- a/engines/support/test/functional/tickets_controller_test.rb +++ b/engines/support/test/functional/tickets_controller_test.rb @@ -72,6 +72,17 @@ class TicketsControllerTest < ActionController::TestCase end + test "handle invalid ticket" do + params = {:subject => "unauth ticket test subject", :comments_attributes => {"0" => {"body" =>"body of test ticket"}}, :email => 'a'} + + assert_no_difference('Ticket.count') do + post :create, :ticket => params + end + + assert_template :new + assert_equal params[:subject], assigns(:ticket).subject + end + test "should create authenticated ticket" do params = {:subject => "auth ticket test subject", :comments_attributes => {"0" => {"body" =>"body of test ticket"}}} diff --git a/engines/support/test/integration/create_ticket_test.rb b/engines/support/test/integration/create_ticket_test.rb new file mode 100644 index 0000000..2583fc7 --- /dev/null +++ b/engines/support/test/integration/create_ticket_test.rb @@ -0,0 +1,28 @@ +require 'test_helper' + +class CreateTicketTest < BrowserIntegrationTest + + test "can submit ticket anonymously" do + visit '/' + click_on 'Get Help' + fill_in 'Subject', with: 'test ticket' + fill_in 'Description', with: 'description of the problem goes here' + click_on 'Create Ticket' + assert page.has_content?("Ticket was successfully created.") + assert page.has_content?("You can later access this ticket at the URL") + assert page.has_content?(current_url) + assert ticket = Ticket.last + ticket.destroy + end + + test "get help when creating ticket with invalid email" do + visit '/' + click_on 'Get Help' + fill_in 'Subject', with: 'test ticket' + fill_in 'Email', with: 'invalid data' + fill_in 'Description', with: 'description of the problem goes here' + click_on 'Create Ticket' + assert page.has_content?("is invalid") + end + +end -- cgit v1.2.3 From 689c10b618c6c469ce82a7f09e117567def577de Mon Sep 17 00:00:00 2001 From: Azul Date: Wed, 23 Apr 2014 14:58:30 +0200 Subject: simple form: add wrapped and loading... buttons #5542 the loading... text on the buttons was not capitalized before. So in order to change this in a (more or less) single place i added new button types to simple_form: button :wrapped - normal button, with loading and an optional cancel button wrapped in the classical bootstrap action div. cancel option contains the url to go to when canceling. button :loading - simple button with loading text capitalized by using i18n (simple_form.buttons.loading) Conflicts: engines/support/app/views/tickets/new.html.haml --- engines/support/app/views/tickets/_new_comment_form.html.haml | 4 ++-- engines/support/app/views/tickets/_tabs.html.haml | 4 ++-- engines/support/app/views/tickets/new.html.haml | 7 +------ 3 files changed, 5 insertions(+), 10 deletions(-) (limited to 'engines/support') diff --git a/engines/support/app/views/tickets/_new_comment_form.html.haml b/engines/support/app/views/tickets/_new_comment_form.html.haml index 8418e01..40c737f 100644 --- a/engines/support/app/views/tickets/_new_comment_form.html.haml +++ b/engines/support/app/views/tickets/_new_comment_form.html.haml @@ -7,7 +7,7 @@ = c.input :body, :label => false, :as => :text, :input_html => {:class => "full-width", :rows=> 5} - if admin? = c.input :private, :as => :boolean, :label => false, :inline_label => true - = f.button :button, t(:post_reply), :name => 'commit', :class => 'btn-primary', :type => 'submit', :value => 'post_reply' + = f.button :loading, t(:post_reply), class: 'btn-primary', value: 'post_reply' - if logged_in? && @ticket.is_open - = f.button :button, t(:reply_and_close), :name => 'commit', :class => 'btn', :type => 'submit', :value => 'reply_and_close' + = f.button :loading, t(:reply_and_close), value: 'reply_and_close' = link_to t(:cancel), auto_tickets_path, :class => :btn diff --git a/engines/support/app/views/tickets/_tabs.html.haml b/engines/support/app/views/tickets/_tabs.html.haml index b7b5d3a..445a909 100644 --- a/engines/support/app/views/tickets/_tabs.html.haml +++ b/engines/support/app/views/tickets/_tabs.html.haml @@ -1,7 +1,7 @@ -# -# SORT ORDER TABS -# -- unless action?(:new) +- unless action?(:new) or action?(:create) %ul.nav.nav-pills.pull-right.slim %li{:class=> ("active" if search_order.start_with? 'created_at')} = link_to_order('created') @@ -19,5 +19,5 @@ = link_to_status 'closed' %li{:class => ("active" if search_status == 'all')} = link_to_status 'all' - %li{:class => ("active" if action?(:new))} + %li{:class => ("active" if action?(:new) || action?(:create))} = link_to icon(:plus, :black) + t(:new_ticket), auto_new_ticket_path diff --git a/engines/support/app/views/tickets/new.html.haml b/engines/support/app/views/tickets/new.html.haml index 65ed67b..ab008d2 100644 --- a/engines/support/app/views/tickets/new.html.haml +++ b/engines/support/app/views/tickets/new.html.haml @@ -14,9 +14,4 @@ = c.input :body, :label => t(:description), :as => :text, :input_html => {:class => "full-width", :rows=> 5} - if admin? = c.input :private, :as => :boolean, :label => false, :inline_label => true - .form-actions - = f.button :submit, :class => 'btn-primary', :value => t(:create_thing, :thing => t(:ticket)) - - if logged_in? - = link_to t(:cancel), auto_tickets_path, :class => :btn - - else - = link_to t(:cancel), home_path, :class => 'btn' + = f.button :wrapped, cancel: (logged_in? ? auto_tickets_path : home_path) -- cgit v1.2.3 From 6c13d3323c180a333fd0f32d17a62adce9fcf2bb Mon Sep 17 00:00:00 2001 From: Azul Date: Wed, 23 Apr 2014 15:27:40 +0200 Subject: using simple_form for the last form that was not using it. --- engines/support/app/controllers/tickets_controller.rb | 8 ++++---- engines/support/app/views/tickets/_edit_form.html.haml | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'engines/support') diff --git a/engines/support/app/controllers/tickets_controller.rb b/engines/support/app/controllers/tickets_controller.rb index 650f628..d552209 100644 --- a/engines/support/app/controllers/tickets_controller.rb +++ b/engines/support/app/controllers/tickets_controller.rb @@ -43,18 +43,18 @@ class TicketsController < ApplicationController end def update - if params[:commit] == 'close' + if params[:button] == 'close' @ticket.is_open = false @ticket.save redirect_to_tickets - elsif params[:commit] == 'open' + elsif params[:button] == 'open' @ticket.is_open = true @ticket.save redirect_to auto_ticket_path(@ticket) else @ticket.attributes = cleanup_ticket_params(params[:ticket]) - if params[:commit] == 'reply_and_close' + if params[:button] == 'reply_and_close' @ticket.close end @@ -98,7 +98,7 @@ class TicketsController < ApplicationController # def redirect_to_tickets if logged_in? - if params[:commit] == t(:reply_and_close) + if params[:button] == t(:reply_and_close) redirect_to auto_tickets_path else redirect_to auto_ticket_path(@ticket) diff --git a/engines/support/app/views/tickets/_edit_form.html.haml b/engines/support/app/views/tickets/_edit_form.html.haml index 714f8ff..7958334 100644 --- a/engines/support/app/views/tickets/_edit_form.html.haml +++ b/engines/support/app/views/tickets/_edit_form.html.haml @@ -17,7 +17,7 @@ regarding_user_link = '' end -= form_for @ticket do |f| += simple_form_for @ticket do |f| = hidden_ticket_fields %p.first - if @ticket.is_open? @@ -39,10 +39,10 @@ = t(:regarding_account) = regarding_user_link = f.text_field :regarding_user - = f.button t(:save), :name => 'commit', :class => 'btn', :type => 'submit', :value => 'save' + = f.button :loading, t(:save), :value => 'save' - if @ticket.is_open? - = f.button t(:close), :name => 'commit', :class => 'btn', :type => 'submit', :value => 'close' + = f.button :loading, t(:close), :value => 'close' - else - = f.button t(:open), :name => 'commit', :class => 'btn', :type => 'submit', :value => 'open' + = f.button :loading, t(:open), :value => 'open' - if admin? = link_to t(:destroy), auto_ticket_path(@ticket), :confirm => t(:are_you_sure), :method => :delete, :class => 'btn' -- cgit v1.2.3 From 615261a6f0d1bae5d999e3014f18191ed1ba1008 Mon Sep 17 00:00:00 2001 From: Azul Date: Wed, 23 Apr 2014 17:14:30 +0200 Subject: move open and close buttons into status display They do not save any changes. So i think it's better to keep them separated from the Save button that does save changes. --- engines/support/app/views/tickets/_edit_form.html.haml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'engines/support') diff --git a/engines/support/app/views/tickets/_edit_form.html.haml b/engines/support/app/views/tickets/_edit_form.html.haml index 7958334..bf175fe 100644 --- a/engines/support/app/views/tickets/_edit_form.html.haml +++ b/engines/support/app/views/tickets/_edit_form.html.haml @@ -21,9 +21,13 @@ = hidden_ticket_fields %p.first - if @ticket.is_open? - %span.label.label-info= t(:open) + %span.label.label-info + %b{style: 'padding:10px'}= t(:open) + = f.button :loading, t(:close), value: 'close', class: 'btn-mini' - else - %span.label.label-success= t(:closed) + %span.label.label-success + %b{style: 'padding:10px'}= t(:closed) + = f.button :loading, t(:open), value: 'open', class: 'btn-mini' %span.label.label-clear= t(:created_by_on, :user => created_by, :time => @ticket.created_at.to_s(:short)).html_safe %div= t(:subject) = f.text_field :subject, :class => 'large full-width' @@ -40,9 +44,5 @@ = regarding_user_link = f.text_field :regarding_user = f.button :loading, t(:save), :value => 'save' - - if @ticket.is_open? - = f.button :loading, t(:close), :value => 'close' - - else - = f.button :loading, t(:open), :value => 'open' - if admin? = link_to t(:destroy), auto_ticket_path(@ticket), :confirm => t(:are_you_sure), :method => :delete, :class => 'btn' -- cgit v1.2.3 From 0261e82686ec4fcfc8b633664fadb1dd6d9c8070 Mon Sep 17 00:00:00 2001 From: Azul Date: Tue, 13 May 2014 10:52:55 +0200 Subject: keep empty email field if user removed prefill We should respect the users choice. We can still get their email from the user id if we really need to. --- .../support/app/controllers/tickets_controller.rb | 1 - .../support/test/integration/create_ticket_test.rb | 28 ++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) (limited to 'engines/support') diff --git a/engines/support/app/controllers/tickets_controller.rb b/engines/support/app/controllers/tickets_controller.rb index d552209..8ec8e4d 100644 --- a/engines/support/app/controllers/tickets_controller.rb +++ b/engines/support/app/controllers/tickets_controller.rb @@ -22,7 +22,6 @@ class TicketsController < ApplicationController @ticket.comments.last.posted_by = current_user.id @ticket.comments.last.private = false unless admin? @ticket.created_by = current_user.id - @ticket.email = current_user.email_address if current_user.email_address if @ticket.save flash[:notice] = t(:thing_was_successfully_created, :thing => t(:ticket)) diff --git a/engines/support/test/integration/create_ticket_test.rb b/engines/support/test/integration/create_ticket_test.rb index 2583fc7..59b263e 100644 --- a/engines/support/test/integration/create_ticket_test.rb +++ b/engines/support/test/integration/create_ticket_test.rb @@ -25,4 +25,32 @@ class CreateTicketTest < BrowserIntegrationTest assert page.has_content?("is invalid") end + test "prefills email when user has email service" do + login FactoryGirl.create(:premium_user) + visit '/' + click_on "Support Tickets" + click_on "New Ticket" + email = "#{@user.login}@#{APP_CONFIG[:domain]}" + assert_equal email, find_field('Email').value + end + + test "no prefill of email without email service" do + login + visit '/' + click_on "Support Tickets" + click_on "New Ticket" + assert_equal "", find_field('Email').value + end + + test "cleared email field should remain clear" do + login FactoryGirl.create(:premium_user) + visit '/' + click_on "Support Tickets" + click_on "New Ticket" + fill_in 'Subject', with: 'test ticket' + fill_in 'Email', with: '' + fill_in 'Description', with: 'description of the problem goes here' + click_on 'Create Ticket' + assert_nil Ticket.last.email + end end -- cgit v1.2.3 From 81a4a0527639fe4b560b8d98f977f6dbac67bb41 Mon Sep 17 00:00:00 2001 From: Azul Date: Tue, 13 May 2014 13:52:16 +0200 Subject: prefill ticket form from the model - fixes #5657 email and regarding user fields can be set to defaults based on created_by user. If these fields are emptied by the submitting user they will be set to whereas they are nil if they have not been initialized. In that case we will use meaningful defaults from the user who created the ticket. --- .../support/app/controllers/tickets_controller.rb | 5 ++--- engines/support/app/models/ticket.rb | 21 ++++++++++++--------- .../support/app/views/tickets/_edit_form.html.haml | 2 +- engines/support/app/views/tickets/new.html.haml | 4 ++-- .../support/test/integration/create_ticket_test.rb | 12 ++++++++++-- 5 files changed, 27 insertions(+), 17 deletions(-) (limited to 'engines/support') diff --git a/engines/support/app/controllers/tickets_controller.rb b/engines/support/app/controllers/tickets_controller.rb index 8ec8e4d..99357ab 100644 --- a/engines/support/app/controllers/tickets_controller.rb +++ b/engines/support/app/controllers/tickets_controller.rb @@ -12,6 +12,7 @@ class TicketsController < ApplicationController def new @ticket = Ticket.new + @ticket.created_by = current_user.id @ticket.comments.build end @@ -24,9 +25,7 @@ class TicketsController < ApplicationController @ticket.created_by = current_user.id if @ticket.save flash[:notice] = t(:thing_was_successfully_created, :thing => t(:ticket)) - - # cannot set this until ticket has been saved, as @ticket.id will not be set - if !logged_in? and flash[:notice] + if !logged_in? flash[:notice] += " " + t(:access_ticket_text, :full_url => ticket_url(@ticket.id)) end end diff --git a/engines/support/app/models/ticket.rb b/engines/support/app/models/ticket.rb index cd22758..d5a0b5d 100644 --- a/engines/support/app/models/ticket.rb +++ b/engines/support/app/models/ticket.rb @@ -19,8 +19,6 @@ class Ticket < CouchRest::Model::Base timestamps! - before_validation :set_email, :set_regarding_user, :on => :create - design do view :by_updated_at view :by_created_at @@ -34,7 +32,12 @@ class Ticket < CouchRest::Model::Base end validates :subject, :presence => true - validates :email, :allow_blank => true, :format => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/ + + # email can have three states: + # * nil - prefilled with created_by's email + # * "" - cleared + # * valid email address + validates :email, :allow_blank => true, :format => /\A(([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,}))?\Z/ def self.search(options = {}) @selection = TicketSelection.new(options) @@ -48,15 +51,15 @@ class Ticket < CouchRest::Model::Base end def is_creator_validated? - !!created_by + created_by_user.is_a? User end - def set_email - self.email = nil if self.email == "" + def email + read_attribute(:email) || created_by_user.email end - def set_regarding_user - self.regarding_user = nil if self.regarding_user == "" + def regarding_user + read_attribute(:regarding_user) || created_by_user.login end def close @@ -95,7 +98,7 @@ class Ticket < CouchRest::Model::Base end def created_by_user - User.find(self.created_by) + User.find(self.created_by) || AnonymousUser.new end def regarding_user_actual_user diff --git a/engines/support/app/views/tickets/_edit_form.html.haml b/engines/support/app/views/tickets/_edit_form.html.haml index bf175fe..fb279fb 100644 --- a/engines/support/app/views/tickets/_edit_form.html.haml +++ b/engines/support/app/views/tickets/_edit_form.html.haml @@ -1,6 +1,6 @@ :ruby # created by user link - if @ticket.created_by_user + if @ticket.is_creator_validated? created_by = link_to @ticket.created_by_user.login, @ticket.created_by_user else created_by = t(:anonymous) diff --git a/engines/support/app/views/tickets/new.html.haml b/engines/support/app/views/tickets/new.html.haml index ab008d2..3de5fe9 100644 --- a/engines/support/app/views/tickets/new.html.haml +++ b/engines/support/app/views/tickets/new.html.haml @@ -8,8 +8,8 @@ = simple_form_for @ticket, :validate => true, :html => {:class => 'form-horizontal'} do |f| = hidden_ticket_fields = f.input :subject - = f.input :email, input_html: {value: user.email_address} - = f.input :regarding_user, input_html: {value: user.login} + = f.input :email + = f.input :regarding_user = f.simple_fields_for :comments, @comment do |c| = c.input :body, :label => t(:description), :as => :text, :input_html => {:class => "full-width", :rows=> 5} - if admin? diff --git a/engines/support/test/integration/create_ticket_test.rb b/engines/support/test/integration/create_ticket_test.rb index 59b263e..0f8453c 100644 --- a/engines/support/test/integration/create_ticket_test.rb +++ b/engines/support/test/integration/create_ticket_test.rb @@ -20,18 +20,22 @@ class CreateTicketTest < BrowserIntegrationTest click_on 'Get Help' fill_in 'Subject', with: 'test ticket' fill_in 'Email', with: 'invalid data' + fill_in 'Regarding user', with: 'some user' fill_in 'Description', with: 'description of the problem goes here' click_on 'Create Ticket' assert page.has_content?("is invalid") + assert_equal 'invalid data', find_field('Email').value + assert_equal 'some user', find_field('Regarding user').value end - test "prefills email when user has email service" do + test "prefills fields" do login FactoryGirl.create(:premium_user) visit '/' click_on "Support Tickets" click_on "New Ticket" email = "#{@user.login}@#{APP_CONFIG[:domain]}" assert_equal email, find_field('Email').value + assert_equal @user.login, find_field('Regarding user').value end test "no prefill of email without email service" do @@ -40,6 +44,7 @@ class CreateTicketTest < BrowserIntegrationTest click_on "Support Tickets" click_on "New Ticket" assert_equal "", find_field('Email').value + assert_equal @user.login, find_field('Regarding user').value end test "cleared email field should remain clear" do @@ -51,6 +56,9 @@ class CreateTicketTest < BrowserIntegrationTest fill_in 'Email', with: '' fill_in 'Description', with: 'description of the problem goes here' click_on 'Create Ticket' - assert_nil Ticket.last.email + ticket = Ticket.last + assert_equal "", ticket.email + ticket.destroy end + end -- cgit v1.2.3 From 41055098941481611d4b9fa80c769092ed9bd79d Mon Sep 17 00:00:00 2001 From: Azul Date: Tue, 13 May 2014 17:10:33 +0200 Subject: open/close toggle and fields in different forms - fixes #5659 --- engines/support/app/views/tickets/_edit_form.html.haml | 2 ++ 1 file changed, 2 insertions(+) (limited to 'engines/support') diff --git a/engines/support/app/views/tickets/_edit_form.html.haml b/engines/support/app/views/tickets/_edit_form.html.haml index bf175fe..3675822 100644 --- a/engines/support/app/views/tickets/_edit_form.html.haml +++ b/engines/support/app/views/tickets/_edit_form.html.haml @@ -29,6 +29,8 @@ %b{style: 'padding:10px'}= t(:closed) = f.button :loading, t(:open), value: 'open', class: 'btn-mini' %span.label.label-clear= t(:created_by_on, :user => created_by, :time => @ticket.created_at.to_s(:short)).html_safe += simple_form_for @ticket do |f| + = hidden_ticket_fields %div= t(:subject) = f.text_field :subject, :class => 'large full-width' .row-fluid -- cgit v1.2.3 From 3278e474a32ef4926b1dab0d97ca4df1c59aa2a0 Mon Sep 17 00:00:00 2001 From: Azul Date: Tue, 13 May 2014 17:21:08 +0200 Subject: adjust tests to new config and method implementation Ticket.is_creator_vlidated? now actually fetches the user from the db and returns false if it does not exist. --- engines/support/app/models/ticket.rb | 6 +++++- engines/support/test/functional/tickets_controller_test.rb | 4 ++-- engines/support/test/unit/ticket_test.rb | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) (limited to 'engines/support') diff --git a/engines/support/app/models/ticket.rb b/engines/support/app/models/ticket.rb index d5a0b5d..bf5df53 100644 --- a/engines/support/app/models/ticket.rb +++ b/engines/support/app/models/ticket.rb @@ -98,7 +98,11 @@ class Ticket < CouchRest::Model::Base end def created_by_user - User.find(self.created_by) || AnonymousUser.new + if self.created_by + User.find(self.created_by) || AnonymousUser.new + else + AnonymousUser.new + end end def regarding_user_actual_user diff --git a/engines/support/test/functional/tickets_controller_test.rb b/engines/support/test/functional/tickets_controller_test.rb index d746b59..fc4a6f8 100644 --- a/engines/support/test/functional/tickets_controller_test.rb +++ b/engines/support/test/functional/tickets_controller_test.rb @@ -85,7 +85,7 @@ class TicketsControllerTest < ActionController::TestCase test "should create authenticated ticket" do - params = {:subject => "auth ticket test subject", :comments_attributes => {"0" => {"body" =>"body of test ticket"}}} + params = {:subject => "auth ticket test subject",:email => "", :comments_attributes => {"0" => {"body" =>"body of test ticket"}}} login @@ -97,7 +97,7 @@ class TicketsControllerTest < ActionController::TestCase assert_not_nil assigns(:ticket).created_by assert_equal assigns(:ticket).created_by, @current_user.id - assert_equal assigns(:ticket).email, @current_user.email_address + assert_equal "", assigns(:ticket).email assert_equal 1, assigns(:ticket).comments.count assert_not_nil assigns(:ticket).comments.first.posted_by diff --git a/engines/support/test/unit/ticket_test.rb b/engines/support/test/unit/ticket_test.rb index f5e6ea7..678d8dc 100644 --- a/engines/support/test/unit/ticket_test.rb +++ b/engines/support/test/unit/ticket_test.rb @@ -27,10 +27,10 @@ class TicketTest < ActiveSupport::TestCase end test "creation validated" do + user = FactoryGirl.create :user @sample = Ticket.new assert !@sample.is_creator_validated? - #p current_user - @sample.created_by = 22 #current_user + @sample.created_by = user.id assert @sample.is_creator_validated? end -- cgit v1.2.3