knjtasks 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +66 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +19 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/files/database_schema.rb +174 -0
- data/lib/knjtasks.rb +172 -0
- data/locales/da_DK/LC_MESSAGES/default.mo +0 -0
- data/locales/da_DK/LC_MESSAGES/default.po +1153 -0
- data/locales/da_DK/title.txt +1 -0
- data/locales/en_GB/title.txt +1 -0
- data/models/class_comment.rb +44 -0
- data/models/class_customer.rb +13 -0
- data/models/class_email_check.rb +7 -0
- data/models/class_project.rb +22 -0
- data/models/class_task.rb +163 -0
- data/models/class_task_assigned_user.rb +62 -0
- data/models/class_task_check.rb +26 -0
- data/models/class_timelog.rb +82 -0
- data/models/class_user.rb +125 -0
- data/models/class_user_project_link.rb +66 -0
- data/models/class_user_rank.rb +3 -0
- data/models/class_user_rank_link.rb +17 -0
- data/models/class_user_task_list_link.rb +17 -0
- data/pages/admin.rhtml +7 -0
- data/pages/comment_edit.rhtml +121 -0
- data/pages/comment_update_id_per_obj.rhtml +41 -0
- data/pages/customer_edit.rhtml +69 -0
- data/pages/customer_search.rhtml +80 -0
- data/pages/customer_show.rhtml +50 -0
- data/pages/frontpage.rhtml +198 -0
- data/pages/project_edit.rhtml +129 -0
- data/pages/project_search.rhtml +82 -0
- data/pages/project_show.rhtml +203 -0
- data/pages/task_check_edit.rhtml +98 -0
- data/pages/task_edit.rhtml +168 -0
- data/pages/task_search.rhtml +131 -0
- data/pages/task_show.rhtml +454 -0
- data/pages/timelog_edit.rhtml +134 -0
- data/pages/timelog_search.rhtml +318 -0
- data/pages/user_edit.rhtml +223 -0
- data/pages/user_login.rhtml +83 -0
- data/pages/user_profile.rhtml +89 -0
- data/pages/user_rank_search.rhtml +95 -0
- data/pages/user_search.rhtml +136 -0
- data/pages/user_show.rhtml +87 -0
- data/pages/workstatus.rhtml +320 -0
- data/scripts/fckeditor_validate_login.rb +23 -0
- data/spec/knjtasks_spec.rb +115 -0
- data/spec/spec_helper.rb +12 -0
- data/threads/thread_mail_task_comments.rb +114 -0
- data/www/api/task.rhtml +9 -0
- data/www/api/user.rhtml +20 -0
- data/www/clean.rhtml +14 -0
- data/www/css/default.css +186 -0
- data/www/gfx/body_bg.jpg +0 -0
- data/www/gfx/button_bg.png +0 -0
- data/www/gfx/main_box_design.png +0 -0
- data/www/gfx/main_box_left.png +0 -0
- data/www/gfx/main_box_right.png +0 -0
- data/www/gfx/main_box_top.png +0 -0
- data/www/gfx/main_box_top_left.png +0 -0
- data/www/gfx/main_box_top_right.png +0 -0
- data/www/index.rhtml +154 -0
- data/www/js/default.js +112 -0
- metadata +208 -0
@@ -0,0 +1 @@
|
|
1
|
+
Danish
|
@@ -0,0 +1 @@
|
|
1
|
+
English
|
@@ -0,0 +1,44 @@
|
|
1
|
+
class Knjtasks::Comment < Knj::Datarow
|
2
|
+
has_one [
|
3
|
+
{:class => :User, :required => true}
|
4
|
+
]
|
5
|
+
|
6
|
+
def self.list(d)
|
7
|
+
sql = "SELECT * FROM Comment WHERE 1=1"
|
8
|
+
|
9
|
+
ret = list_helper(d)
|
10
|
+
d.args.each do |key, val|
|
11
|
+
case key
|
12
|
+
when "object_lookup"
|
13
|
+
sql += " AND object_class = '#{val.table}' AND object_id = '#{d.db.esc(val.id)}'"
|
14
|
+
else
|
15
|
+
raise sprintf(_("Invalid key: %s."), key)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
sql += ret[:sql_where]
|
20
|
+
sql += ret[:sql_order]
|
21
|
+
sql += ret[:sql_limit]
|
22
|
+
|
23
|
+
return d.ob.list_bysql(:Comment, sql)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.add(d)
|
27
|
+
d.data[:user_id ] = _site.user.id if !d.data[:user_id] and _site.user
|
28
|
+
d.data[:date_saved] = Time.new if !d.data[:date_saved]
|
29
|
+
|
30
|
+
raise "No 'object_class' was given." if !d.data[:object_class]
|
31
|
+
raise "No 'object_id' was given." if !d.data[:object_id]
|
32
|
+
|
33
|
+
obj = d.ob.get(d.data[:object_class], d.data[:object_id])
|
34
|
+
user = d.ob.get(:User, d.data[:user_id])
|
35
|
+
end
|
36
|
+
|
37
|
+
def object
|
38
|
+
return ob.get_try(self, :object_id, self[:object_class])
|
39
|
+
end
|
40
|
+
|
41
|
+
def add_after(d)
|
42
|
+
self.object.send_notify_new_comment(self) if self.object.class.name == "Knjtasks::Task"
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class Knjtasks::Customer < Knj::Datarow
|
2
|
+
has_many [
|
3
|
+
{:class => :Project, :col => :customer_id, :depends => true}
|
4
|
+
]
|
5
|
+
|
6
|
+
def self.add(d)
|
7
|
+
d.data[:date_added] = Time.new if !d.data[:date_added]
|
8
|
+
end
|
9
|
+
|
10
|
+
def html
|
11
|
+
return "<a href=\"?show=customer_show&customer_id=#{id}\">#{name.html}</a>"
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Knjtasks::Project < Knj::Datarow
|
2
|
+
has_one [
|
3
|
+
{:class => :User, :col => :added_user_id, :method => :added_user, :required => true},
|
4
|
+
{:class => :Customer, :col => :customer_id, :method => :customer, :required => true}
|
5
|
+
]
|
6
|
+
|
7
|
+
has_many [
|
8
|
+
{:class => :Task, :col => :project_id, :depends => true},
|
9
|
+
{:class => :User_project_link, :col => :project_id, :method => :users, :autodelete => true, :depends => true}
|
10
|
+
]
|
11
|
+
|
12
|
+
def self.add(d)
|
13
|
+
raise _("Invalid name given.") if d.data[:name].to_s.strip.length <= 0
|
14
|
+
|
15
|
+
d.data[:added_user_id] = _site.user.id if !d.data[:added_user_id] and _site.user
|
16
|
+
d.data[:added_date] = Time.new if !d.data[:added_date]
|
17
|
+
end
|
18
|
+
|
19
|
+
def html
|
20
|
+
return "<a href=\"?show=project_show&project_id=#{id}\">#{name.html}</a>"
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
class Knjtasks::Task < Knj::Datarow
|
2
|
+
has_many [
|
3
|
+
[:Timelog, :task_id],
|
4
|
+
[:Task_assigned_user, :task_id, :assigned_users],
|
5
|
+
[:Task_check, :task_id, :checks],
|
6
|
+
[:User_task_list_link, :task_id, :user_lists]
|
7
|
+
]
|
8
|
+
has_one [
|
9
|
+
{:class => :Project, :required => true},
|
10
|
+
:User
|
11
|
+
]
|
12
|
+
|
13
|
+
def initialize(*args, &blk)
|
14
|
+
super(*args, &blk)
|
15
|
+
self[:priority] = 1 if self[:priority].to_i <= 0 or self[:priority].to_i > 10
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.add(d)
|
19
|
+
raise _("No project-ID was given.") if d.data[:project_id].to_i <= 0
|
20
|
+
raise _("Invalid name was given.") if d.data[:name].to_s.strip.length <= 0
|
21
|
+
|
22
|
+
d.data[:user_id] = _site.user.id if _site.user
|
23
|
+
d.data[:date_added] = Time.now if !d.data[:date_added]
|
24
|
+
d.data[:priority] = 1 if d.data[:priority].to_i <= 0 or d.data[:priority].to_i > 10
|
25
|
+
|
26
|
+
begin
|
27
|
+
task = d.ob.get(:Project, d.data[:project_id])
|
28
|
+
rescue Errno::ENOENT
|
29
|
+
raise sprintf(_("A project with the given project-ID could not be found: '%s'."), d.data[:project_id])
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.type_opts(d)
|
34
|
+
return {
|
35
|
+
:feature => _("Feature"),
|
36
|
+
:bug => _("Bug report"),
|
37
|
+
:question => _("Question")
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.status_opts(d)
|
42
|
+
return {
|
43
|
+
:open => _("Open"),
|
44
|
+
:confirmed => _("Confirmed"),
|
45
|
+
:waiting => _("Waiting"),
|
46
|
+
:closed => _("Closed")
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
#Sends a notification about a newly added comment to a task.
|
51
|
+
def send_notify_new_comment(comment)
|
52
|
+
self.notify_emails.each do |data|
|
53
|
+
subj = "#{sprintf(_hb.gettext.gettext("Task #%1$s: %2$s", data[:user].locale), self.id, self.name)} - #{sprintf(_hb.gettext.gettext("New comment from: %s", data[:user].locale), comment.user.name)}"
|
54
|
+
|
55
|
+
if !self.user
|
56
|
+
user_html = "[#{_hb.gettext.gettext("no user", data[:user].locale)}]"
|
57
|
+
else
|
58
|
+
user_html = comment.user.name.html
|
59
|
+
end
|
60
|
+
|
61
|
+
html = ""
|
62
|
+
|
63
|
+
html += sprintf(_hb.gettext.gettext("A new comment has been written to the task '%s'.", data[:user].locale), self.name)
|
64
|
+
html += "<br /><br />"
|
65
|
+
|
66
|
+
html += "<b>#{_hb.gettext.gettext("Author", data[:user].locale)}:</b><br />"
|
67
|
+
html += "#{user_html}<br /><br />"
|
68
|
+
|
69
|
+
html += "<b>#{_hb.gettext.gettext("Task", data[:user].locale)}:</b><br />"
|
70
|
+
html += "<a href=\"#{url}\">#{url}</a><br /><br />"
|
71
|
+
|
72
|
+
html += "<b>#{_hb.gettext.gettext("Comment", data[:user].locale)}</b><br />"
|
73
|
+
html += comment[:comment]
|
74
|
+
|
75
|
+
_hb.mail(:to => data[:email], :subject => subj, :html => html)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
#Sends a
|
80
|
+
def send_notify_assigned(user_assigned, user_by)
|
81
|
+
return false if user_assigned[:email].to_s.strip.length <= 0
|
82
|
+
|
83
|
+
subj = sprintf(_hb.gettext.gettext("You have been assigned to: %s", user_assigned.locale), self.name)
|
84
|
+
|
85
|
+
html = ""
|
86
|
+
|
87
|
+
html += "<b>#{_hb.gettext.gettext("Assigned by", user_assigned.locale)}:</b><br />"
|
88
|
+
html += "#{user_by.name}<br /><br />"
|
89
|
+
|
90
|
+
html += "<b>#{_hb.gettext.gettext("Task", user_assigned.locale)}:</b><br />"
|
91
|
+
html += "<a href=\"#{url}\">#{url}</a><br /><br />"
|
92
|
+
|
93
|
+
html += "<b>#{_hb.gettext.gettext("Description", user_assigned.locale)}</b><br />"
|
94
|
+
html += self[:descr]
|
95
|
+
|
96
|
+
_hb.mail(:to => user_assigned[:email], :subject => subj, :html => html)
|
97
|
+
end
|
98
|
+
|
99
|
+
#Returns the emails of the assigned users and the owner as an array.
|
100
|
+
def notify_emails
|
101
|
+
emails = {}
|
102
|
+
emails[self.user[:email]] = self.user if self.user and self.user[:email].to_s.strip.length > 0
|
103
|
+
|
104
|
+
assigned_users.each do |link|
|
105
|
+
user = link.user
|
106
|
+
next if !user or user[:email].to_s.strip.length <= 0
|
107
|
+
|
108
|
+
emails[user[:email]] = user
|
109
|
+
end
|
110
|
+
|
111
|
+
ret = []
|
112
|
+
emails.each do |email, user|
|
113
|
+
ret << {
|
114
|
+
:email => email,
|
115
|
+
:user => user
|
116
|
+
}
|
117
|
+
end
|
118
|
+
|
119
|
+
return ret
|
120
|
+
end
|
121
|
+
|
122
|
+
def url
|
123
|
+
return "#{_site.args[:url]}/?show=task_show&task_id=#{id}"
|
124
|
+
end
|
125
|
+
|
126
|
+
def html
|
127
|
+
return "<a href=\"?show=task_show&task_id=#{id}\">#{name.html}</a>"
|
128
|
+
end
|
129
|
+
|
130
|
+
def comments(args = {})
|
131
|
+
return _ob.list(:Comment, {"object_lookup" => self}.merge(args))
|
132
|
+
end
|
133
|
+
|
134
|
+
def has_access?(user = _site.user)
|
135
|
+
return false if !user
|
136
|
+
return true if user.has_rank?("admin")
|
137
|
+
return true if self[:user_id].to_s == user.id.to_s
|
138
|
+
return false
|
139
|
+
end
|
140
|
+
|
141
|
+
def status_str
|
142
|
+
return ob.static(:Task, :status_opts)[self[:status].to_sym]
|
143
|
+
end
|
144
|
+
|
145
|
+
def has_view_access?(user)
|
146
|
+
return false if !user
|
147
|
+
return true if self.has_access?(user)
|
148
|
+
|
149
|
+
task_link = ob.get_by(:Task_assigned_user, {
|
150
|
+
"user" => user,
|
151
|
+
"task" => self
|
152
|
+
})
|
153
|
+
return true if task_link
|
154
|
+
|
155
|
+
project_link = ob.get_by(:User_project_link, {
|
156
|
+
"user" => user,
|
157
|
+
"project" => self.project
|
158
|
+
})
|
159
|
+
return true if project_link
|
160
|
+
|
161
|
+
return false
|
162
|
+
end
|
163
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
class Knjtasks::Task_assigned_user < Knj::Datarow
|
2
|
+
has_one [
|
3
|
+
{:class => :User, :required => true},
|
4
|
+
{:class => :Task, :required => true}
|
5
|
+
]
|
6
|
+
|
7
|
+
def self.list(d)
|
8
|
+
sql = "SELECT #{table}.* FROM #{table}"
|
9
|
+
|
10
|
+
join_task = true if d.args["orderby"] == "project_task_names"
|
11
|
+
join_task = true if d.args["task_status_not"]
|
12
|
+
|
13
|
+
if join_task
|
14
|
+
orderby = "project_task_names"
|
15
|
+
d.args.delete("orderby")
|
16
|
+
|
17
|
+
sql += "
|
18
|
+
LEFT JOIN Task ON
|
19
|
+
Task.id = #{table}.task_id
|
20
|
+
|
21
|
+
LEFT JOIN Project ON
|
22
|
+
Project.id = Task.project_id
|
23
|
+
"
|
24
|
+
end
|
25
|
+
|
26
|
+
sql += " WHERE 1=1"
|
27
|
+
|
28
|
+
ret = list_helper(d)
|
29
|
+
d.args.each do |key, val|
|
30
|
+
case key
|
31
|
+
when "task_status_not"
|
32
|
+
sql += " AND Task.status != '#{d.db.esc(val)}'"
|
33
|
+
else
|
34
|
+
raise sprintf(_("Invalid key: %s."), key)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
sql += ret[:sql_where]
|
39
|
+
|
40
|
+
if orderby == "task_name"
|
41
|
+
sql += " ORDER BY Project.name, Task.name"
|
42
|
+
else
|
43
|
+
sql += ret[:sql_order]
|
44
|
+
end
|
45
|
+
|
46
|
+
sql += ret[:sql_limit]
|
47
|
+
|
48
|
+
return d.ob.list_bysql(table, sql)
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.add(d)
|
52
|
+
link = d.ob.get_by(:Task_assigned_user, {
|
53
|
+
"task_id" => d.data[:task_id],
|
54
|
+
"user_id" => d.data[:user_id]
|
55
|
+
})
|
56
|
+
raise _("That user is already assigned to that task.") if link
|
57
|
+
end
|
58
|
+
|
59
|
+
def add_after(d)
|
60
|
+
task.send_notify_assigned(user, _site.user)
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Knjtasks::Task_check < Knj::Datarow
|
2
|
+
has_one [
|
3
|
+
{:class => :User, :col => :added_user_id, :method => :user_added, :required => true},
|
4
|
+
:Task
|
5
|
+
]
|
6
|
+
|
7
|
+
def self.list(d)
|
8
|
+
sql = "SELECT * FROM #{table} WHERE 1=1"
|
9
|
+
|
10
|
+
ret = list_helper(d)
|
11
|
+
d.args.each do |key, val|
|
12
|
+
raise sprintf(_("Invalid key: %s."), key)
|
13
|
+
end
|
14
|
+
|
15
|
+
sql += ret[:sql_where]
|
16
|
+
sql += ret[:sql_order]
|
17
|
+
sql += ret[:sql_limit]
|
18
|
+
|
19
|
+
return d.ob.list_bysql(:Task_check, sql)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.add(d)
|
23
|
+
d.data[:added_user_id] = _site.user.id if !d.data[:added_user_id] and _site.user
|
24
|
+
d.data[:date_added] = Time.now if !d.data[:date_added]
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
class Knjtasks::Timelog < Knj::Datarow
|
2
|
+
has_one [
|
3
|
+
:Task,
|
4
|
+
:User
|
5
|
+
]
|
6
|
+
|
7
|
+
def self.list(d)
|
8
|
+
sql = "SELECT"
|
9
|
+
|
10
|
+
join_tasks = true if d.args["project_id"]
|
11
|
+
|
12
|
+
if d.args[:count]
|
13
|
+
count = true
|
14
|
+
d.args.delete(:count)
|
15
|
+
sql += "
|
16
|
+
SUM(TIME_TO_SEC(Timelog.time)) AS sum_time,
|
17
|
+
SUM(TIME_TO_SEC(Timelog.time_transport)) AS sum_time_transport,
|
18
|
+
SUM(Timelog.transport_length) AS sum_transport_length
|
19
|
+
"
|
20
|
+
else
|
21
|
+
sql += " Timelog.*"
|
22
|
+
end
|
23
|
+
|
24
|
+
sql += " FROM Timelog"
|
25
|
+
|
26
|
+
if join_tasks
|
27
|
+
sql += "
|
28
|
+
LEFT JOIN Task ON
|
29
|
+
Task.id = Timelog.task_id
|
30
|
+
"
|
31
|
+
end
|
32
|
+
|
33
|
+
sql += " WHERE 1=1"
|
34
|
+
|
35
|
+
ret = list_helper(d)
|
36
|
+
d.args.each do |key, val|
|
37
|
+
case key
|
38
|
+
when "project_id"
|
39
|
+
if val.is_a?(Array)
|
40
|
+
sql += " AND Task.project_id IN (" + Knj::ArrayExt.join(:arr => val, :sep => ",", :surr => "'", :callback => proc{|data| d.db.esc(data)}) + ")"
|
41
|
+
else
|
42
|
+
sql += " AND Task.project_id = '#{d.db.esc(val)}'"
|
43
|
+
end
|
44
|
+
else
|
45
|
+
raise sprintf(_("Invalid key: %s."), key)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
sql += ret[:sql_where]
|
50
|
+
sql += ret[:sql_order]
|
51
|
+
|
52
|
+
if count
|
53
|
+
return d.db.query(sql).fetch
|
54
|
+
end
|
55
|
+
|
56
|
+
sql += ret[:sql_limit]
|
57
|
+
|
58
|
+
return d.ob.list_bysql(:Timelog, sql)
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.add(d)
|
62
|
+
d.data[:user_id] = _site.user.id if !d.data[:user_id] and _site.user
|
63
|
+
raise _("No comment has been written.") if d.data[:comment].to_s.length <= 0
|
64
|
+
task = d.ob.get(:Task, d.data[:task_id])
|
65
|
+
end
|
66
|
+
|
67
|
+
def html(args = {})
|
68
|
+
if args[:key] == :id_localized
|
69
|
+
name = Knj::Locales.number_out(id, 0)
|
70
|
+
elsif args[:key]
|
71
|
+
name = self[args[:key]].html
|
72
|
+
else
|
73
|
+
name = sprintf(_("Timelog %s"), Knj::Locales.number_out(id, 0))
|
74
|
+
end
|
75
|
+
|
76
|
+
return "<a href=\"javascript: timelog_edit('#{id}');\">#{name}</a>"
|
77
|
+
end
|
78
|
+
|
79
|
+
def comment_html
|
80
|
+
return Php4r.nl2br(Knj::Web.html(self[:comment]))
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
class Knjtasks::User < Knj::Datarow
|
2
|
+
has_many [
|
3
|
+
{:class => :Task, :col => :user_id, :depends => true},
|
4
|
+
{:class => :Task_assigned_user, :col => :user_id, :method => :assigned_to_tasks, :depends => true},
|
5
|
+
{:class => :User_rank_link, :col => :user_id, :method => :ranks, :depends => true},
|
6
|
+
{:class => :User_project_link, :col => :user_id, :method => :projects, :depends => true},
|
7
|
+
[:User_task_list_link, :user_id, :user_lists]
|
8
|
+
]
|
9
|
+
|
10
|
+
def delete
|
11
|
+
raise _("Cannot delete user because that user has created tasks.") if ob.get_by(:Task, {"user" => self})
|
12
|
+
end
|
13
|
+
|
14
|
+
def name
|
15
|
+
if self[:name].to_s.length > 0
|
16
|
+
return self[:name]
|
17
|
+
elsif self[:username].to_s.length > 0
|
18
|
+
return self[:username]
|
19
|
+
end
|
20
|
+
|
21
|
+
raise "Could not figure out a name?"
|
22
|
+
end
|
23
|
+
|
24
|
+
def locale
|
25
|
+
return self[:locale] if self[:locale].to_s.length > 0
|
26
|
+
return "en_GB"
|
27
|
+
end
|
28
|
+
|
29
|
+
def has_rank?(rank_str)
|
30
|
+
rank = self.ob.get_by(:User_rank, {
|
31
|
+
"id_str" => rank_str
|
32
|
+
})
|
33
|
+
return false if !rank
|
34
|
+
|
35
|
+
rank_link = self.ob.get_by(:User_rank_link, {
|
36
|
+
"user" => self,
|
37
|
+
"rank" => rank
|
38
|
+
})
|
39
|
+
return false if !rank_link
|
40
|
+
|
41
|
+
return true
|
42
|
+
end
|
43
|
+
|
44
|
+
def has_email?
|
45
|
+
return Knj::Strings.is_email?(self[:email])
|
46
|
+
end
|
47
|
+
|
48
|
+
def html
|
49
|
+
name_str = self[:name]
|
50
|
+
if name_str.to_s.strip.length <= 0
|
51
|
+
name_str = self[:username]
|
52
|
+
end
|
53
|
+
|
54
|
+
if name_str.to_s.strip.length <= 0
|
55
|
+
name_str = "[#{_("no name")}]"
|
56
|
+
end
|
57
|
+
|
58
|
+
return "<a href=\"?show=user_show&user_id=#{id}\">#{name_str.html}</a>"
|
59
|
+
end
|
60
|
+
|
61
|
+
def has_view_access?(user)
|
62
|
+
return false if !user
|
63
|
+
return true if user.has_rank?("admin")
|
64
|
+
|
65
|
+
res = _db.query("
|
66
|
+
SELECT
|
67
|
+
*
|
68
|
+
|
69
|
+
FROM
|
70
|
+
User_project_link AS user_link,
|
71
|
+
User_project_link AS my_link
|
72
|
+
|
73
|
+
WHERE
|
74
|
+
user_link.user_id = '#{_db.esc(user.id)}' AND
|
75
|
+
my_link.user_id = '#{_db.esc(self.id)}' AND
|
76
|
+
user_link.project_id = my_link.project_id
|
77
|
+
|
78
|
+
LIMIT
|
79
|
+
1
|
80
|
+
").fetch
|
81
|
+
return true if res
|
82
|
+
|
83
|
+
return false
|
84
|
+
end
|
85
|
+
|
86
|
+
def customers
|
87
|
+
customers = {}
|
88
|
+
self.ob.list(:Project, {
|
89
|
+
[:User_project_link, "user_id"] => self.id
|
90
|
+
}) do |project|
|
91
|
+
customer = project.customer
|
92
|
+
next if !customer or customers.key?(customer.id)
|
93
|
+
customers[customer.id] = customer
|
94
|
+
end
|
95
|
+
|
96
|
+
customers = customers.values.to_a
|
97
|
+
customers.sort do |cust1, cust2|
|
98
|
+
cust1.name.downcase <=> cust2.name.downcase
|
99
|
+
end
|
100
|
+
|
101
|
+
return customers
|
102
|
+
end
|
103
|
+
|
104
|
+
#A list of all relevant users for this user (from the same customer).
|
105
|
+
def users_list
|
106
|
+
users = {}
|
107
|
+
|
108
|
+
self.customers.each do |customer|
|
109
|
+
customer.projects do |project|
|
110
|
+
self.ob.list(:User, {
|
111
|
+
[:User_project_link, "project_id"] => project.id
|
112
|
+
}) do |user|
|
113
|
+
users[user.id] = user
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
users = users.values
|
119
|
+
users.sort do |user1, user2|
|
120
|
+
user1.name.downcase <=> user2.name.downcase
|
121
|
+
end
|
122
|
+
|
123
|
+
return users
|
124
|
+
end
|
125
|
+
end
|