summaryrefslogtreecommitdiff
path: root/engines/support/app/models/ticket.rb
blob: b1bdf8de70b58a06aac93a68996d7e0f4fd3665a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#
# 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: don't hardcode strings 'unknown user' and 'unauthenticated user'
#
# TODO: this should use associations instead of non-standard created_by.
#
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!

  unique_id :generate_code

  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

  # email can be nil, "", or valid address.
  # validation provided by 'valid_email' gem.
  validates :email, :allow_blank => true,
    :email => true,
    :mx_with_fallback => true

  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
  rescue RestClient::ResourceNotFound
    # silently ignore if design docs are not yet created
  end

  def is_creator_validated?
    created_by_user.is_a? User
  end

  def email
    read_attribute(:email) || created_by_user.email
  end

  def regarding_user
    read_attribute(:regarding_user) || created_by_user.login
  end

  def close
    self.is_open = false
  end

  def reopen
    self.is_open = true
  end

  def commenters(locale = I18n.locale)
    commenters = []
    unknown = false
    anonymous = false
    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)
        elsif !unknown
          unknown = true
          commenters << I18n.t(:unknown, :locale => locale)
        end
      elsif !anonymous
        anonymous = true
        commenters << I18n.t(:anonymous, :locale => locale)
      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
    if self.created_by
      User.find(self.created_by) || AnonymousUser.new
    else
      AnonymousUser.new
    end
  end

  def regarding_user_actual_user
    User.find_by_login(self.regarding_user)
  end

  # Generate a unique code for identifying this ticket.
  # This will become the ID of the document. It is also used for
  # tracking email replies. The code must be URL friendly.
  def generate_code
    while code = SecureRandom.urlsafe_base64.downcase.gsub(/[li1o0_-]/,'')[0..7]
      if code.length == 8 && self.class.find(code).nil?
        return code
      end
    end
  end

end