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
|