knjtasks 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +18 -0
  4. data/Gemfile.lock +66 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.rdoc +19 -0
  7. data/Rakefile +49 -0
  8. data/VERSION +1 -0
  9. data/files/database_schema.rb +174 -0
  10. data/lib/knjtasks.rb +172 -0
  11. data/locales/da_DK/LC_MESSAGES/default.mo +0 -0
  12. data/locales/da_DK/LC_MESSAGES/default.po +1153 -0
  13. data/locales/da_DK/title.txt +1 -0
  14. data/locales/en_GB/title.txt +1 -0
  15. data/models/class_comment.rb +44 -0
  16. data/models/class_customer.rb +13 -0
  17. data/models/class_email_check.rb +7 -0
  18. data/models/class_project.rb +22 -0
  19. data/models/class_task.rb +163 -0
  20. data/models/class_task_assigned_user.rb +62 -0
  21. data/models/class_task_check.rb +26 -0
  22. data/models/class_timelog.rb +82 -0
  23. data/models/class_user.rb +125 -0
  24. data/models/class_user_project_link.rb +66 -0
  25. data/models/class_user_rank.rb +3 -0
  26. data/models/class_user_rank_link.rb +17 -0
  27. data/models/class_user_task_list_link.rb +17 -0
  28. data/pages/admin.rhtml +7 -0
  29. data/pages/comment_edit.rhtml +121 -0
  30. data/pages/comment_update_id_per_obj.rhtml +41 -0
  31. data/pages/customer_edit.rhtml +69 -0
  32. data/pages/customer_search.rhtml +80 -0
  33. data/pages/customer_show.rhtml +50 -0
  34. data/pages/frontpage.rhtml +198 -0
  35. data/pages/project_edit.rhtml +129 -0
  36. data/pages/project_search.rhtml +82 -0
  37. data/pages/project_show.rhtml +203 -0
  38. data/pages/task_check_edit.rhtml +98 -0
  39. data/pages/task_edit.rhtml +168 -0
  40. data/pages/task_search.rhtml +131 -0
  41. data/pages/task_show.rhtml +454 -0
  42. data/pages/timelog_edit.rhtml +134 -0
  43. data/pages/timelog_search.rhtml +318 -0
  44. data/pages/user_edit.rhtml +223 -0
  45. data/pages/user_login.rhtml +83 -0
  46. data/pages/user_profile.rhtml +89 -0
  47. data/pages/user_rank_search.rhtml +95 -0
  48. data/pages/user_search.rhtml +136 -0
  49. data/pages/user_show.rhtml +87 -0
  50. data/pages/workstatus.rhtml +320 -0
  51. data/scripts/fckeditor_validate_login.rb +23 -0
  52. data/spec/knjtasks_spec.rb +115 -0
  53. data/spec/spec_helper.rb +12 -0
  54. data/threads/thread_mail_task_comments.rb +114 -0
  55. data/www/api/task.rhtml +9 -0
  56. data/www/api/user.rhtml +20 -0
  57. data/www/clean.rhtml +14 -0
  58. data/www/css/default.css +186 -0
  59. data/www/gfx/body_bg.jpg +0 -0
  60. data/www/gfx/button_bg.png +0 -0
  61. data/www/gfx/main_box_design.png +0 -0
  62. data/www/gfx/main_box_left.png +0 -0
  63. data/www/gfx/main_box_right.png +0 -0
  64. data/www/gfx/main_box_top.png +0 -0
  65. data/www/gfx/main_box_top_left.png +0 -0
  66. data/www/gfx/main_box_top_right.png +0 -0
  67. data/www/index.rhtml +154 -0
  68. data/www/js/default.js +112 -0
  69. metadata +208 -0
@@ -0,0 +1,198 @@
1
+ <%
2
+ print _site.header(_("Frontpage"))
3
+
4
+ headlines = [
5
+ {
6
+ "sort" => "name",
7
+ "sortval" => "name",
8
+ "title" => _("Task")
9
+ },{
10
+ "sort" => "project",
11
+ "sortval" => {:table => :Project, :col => :name},
12
+ "title" => _("Project")
13
+ },{
14
+ "sort" => "priority",
15
+ "sortval" => "priority",
16
+ "title" => _("Priority")
17
+ },{
18
+ "sort" => "author",
19
+ "sortval" => {:table => :User, :col => :name},
20
+ "title" => _("Author")
21
+ },{
22
+ "sort" => "date",
23
+ "sortval" => "date_added",
24
+ "title" => _("Date")
25
+ },{
26
+ "sort" => "status",
27
+ "sortval" => "status",
28
+ "title" => _("Status")
29
+ }
30
+ ]
31
+
32
+ if _site.has_rank?("admin")
33
+ headlines += [
34
+ {
35
+ "title" => "#{_("Hours")} / #{_("Driving")}"
36
+ },{
37
+ "title" => _("Transport length")
38
+ }
39
+ ]
40
+ end
41
+
42
+ tasks_assigned_links = _ob.list(:Task_assigned_user, {"user" => _site.user, "task_status_not" => "closed"})
43
+
44
+ tasks = []
45
+
46
+ tasks_assigned_links.each do |assigned_link|
47
+ tasks << assigned_link.task if tasks.index(assigned_link.task) == nil
48
+ end
49
+
50
+ tasks_owner = _ob.list(:Task, {"user" => _site.user, "status_not" => "closed"}) do |task|
51
+ tasks << task if tasks.index(task) == nil
52
+ end
53
+
54
+ task_status_hash = _ob.static(:Task, :status_opts)
55
+
56
+ tasks.sort! do |a, b|
57
+ res = nil
58
+
59
+ if _get["sort"] == "project" or _get["sort"].to_s.length <= 0
60
+ res = a.project.name.downcase <=> b.project.name.downcase if a.project and b.project
61
+ if res == nil or res == 0
62
+ res = a.name.downcase <=> b.name.downcase
63
+ end
64
+ elsif _get["sort"] == "name"
65
+ res = a.name.downcase <=> b.name.downcase
66
+ elsif _get["sort"] == "date"
67
+ adate = a.date_added
68
+ bdate = b.date_added
69
+
70
+ if !adate
71
+ res = -1
72
+ elsif !bdate
73
+ res = 1
74
+ else
75
+ res = a.date_added <=> b.date_added
76
+ end
77
+ elsif _get["sort"] == "author"
78
+ res = a.user.name <=> b.user.name
79
+ elsif _get["sort"] == "status"
80
+ res = task_status_hash[a[:status].to_sym] <=> task_status_hash[b[:status].to_sym]
81
+ elsif _get["sort"] == "priority"
82
+ res = a[:priority].to_i <=> b[:priority].to_i
83
+ else
84
+ raise "Dont know how to sort the tasks."
85
+ end
86
+
87
+ if _get["sortmode"] == "desc"
88
+ if res == 1
89
+ res = -1
90
+ elsif res == -1
91
+ res = 1
92
+ end
93
+ end
94
+
95
+ res
96
+ end
97
+ %>
98
+
99
+ <%=_site.boxt(_("Tasks"))%>
100
+ <div style="padding-bottom: 15px;">
101
+ <input type="button" value="<%=_"Add new"%>" onclick="location.href='?show=task_edit';" />
102
+ </div>
103
+
104
+ <table class="list">
105
+ <thead>
106
+ <tr>
107
+ <%
108
+ headlines.each do |headline|
109
+ html = "<th>"
110
+
111
+ if headline["sort"]
112
+ html << "<a href=\"/?show=frontpage&amp;sort=#{headline["sort"]}"
113
+
114
+ if _get["sort"] == headline["sort"] and _get["sortmode"] != "desc"
115
+ html << "&amp;sortmode=desc"
116
+ end
117
+
118
+ html << "\">"
119
+ end
120
+
121
+ html << headline["title"]
122
+
123
+ if headline["sort"]
124
+ html << "</a>"
125
+ end
126
+
127
+ html << "</th>"
128
+
129
+ print html
130
+ end
131
+ %>
132
+ </tr>
133
+ </thead>
134
+ <tbody>
135
+ <%
136
+ tasks_count = 0
137
+ tasks.each do |task|
138
+ next if !task.has_view_access?(_site.user)
139
+ count = task.timelogs(:count => true)
140
+ tasks_count += 1
141
+
142
+ total_hours = count[:sum_time].to_f / 3600
143
+ total_hours_transport = count[:sum_time_transport].to_f / 3600
144
+ total_transport_length = count[:sum_transport_length].to_i
145
+
146
+ %>
147
+ <tr>
148
+ <td>
149
+ <%if task[:status].to_s == "open"%>
150
+ <b>
151
+ <%end%>
152
+
153
+ <%=task.html%>
154
+
155
+ <%if task[:status].to_s == "open"%>
156
+ </b>
157
+ <%end%>
158
+ </td>
159
+ <td class="nowrap">
160
+ <%=task.project_html%>
161
+ </td>
162
+ <td class="nowrap">
163
+ <%=_hb.num(task[:priority], 0)%>
164
+ </td>
165
+ <td class="nowrap">
166
+ <%=task.user_html%>
167
+ </td>
168
+ <td class="nowrap">
169
+ <%=task.date_added_str(:time => false)%>
170
+ </td>
171
+ <td>
172
+ <%=_ob.static(:Task, :status_opts)[task[:status].to_sym]%>
173
+ </td>
174
+ <%if _site.has_rank?("admin")%>
175
+ <td class="nowrap">
176
+ <%=Knj::Locales.number_out(total_hours, 2)%> / <%=Knj::Locales.number_out(total_hours_transport, 2)%>
177
+ </td>
178
+ <td class="nowrap">
179
+ <%=Knj::Locales.number_out(total_transport_length, 0)%>
180
+ </td>
181
+ <%end%>
182
+ </tr>
183
+ <%
184
+ end
185
+
186
+ if tasks_count <= 0
187
+ %>
188
+ <tr>
189
+ <td colspan="<%=headlines.length%>" class="error">
190
+ <%=_("No tasks were found.")%>
191
+ </td>
192
+ </tr>
193
+ <%
194
+ end
195
+ %>
196
+ </tbody>
197
+ </table>
198
+ <%=_site.boxb%>
@@ -0,0 +1,129 @@
1
+ <%
2
+ if !_site.has_rank?("admin")
3
+ _hb.alert(_("You are not an administrator and cannot view this page.")).back
4
+ end
5
+
6
+ if _get["choice"] == "dosave"
7
+ if _post["texdeadline"] != ""
8
+ date_deadline = Datet.in(_post["texdeadline"])
9
+ else
10
+ date_deadline = nil
11
+ end
12
+
13
+ save_hash = {
14
+ :name => _post["texname"],
15
+ :descr => _post["texdescr"],
16
+ :customer_id => _post["selcustomer"],
17
+ :date_deadline => date_deadline
18
+ }
19
+ end
20
+
21
+ date_deadline_str = ""
22
+
23
+ if _get["project_id"].to_i > 0
24
+ begin
25
+ project = _ob.get(:Project, _get["project_id"])
26
+ rescue Errno::ENOENT
27
+ _hb.alert(_("That project could not be found in the database.")).back
28
+ end
29
+
30
+ title = sprintf(_("Edit project: %s."), project.name.html)
31
+
32
+ if project.date_deadline
33
+ date_deadline_str = project.date_deadline_str(:time => false)
34
+ end
35
+
36
+ if _get["choice"] == "dosave"
37
+ project.update(save_hash)
38
+ _hb.redirect("?show=project_edit&project_id=#{project.id}")
39
+ end
40
+
41
+ if _get["choice"] == "dodelete"
42
+ _ob.delete(project)
43
+ _hb.redirect("?show=project_search")
44
+ end
45
+ else
46
+ title = _("Add new project")
47
+
48
+ if _get["choice"] == "dosave"
49
+ begin
50
+ project = _ob.add(:Project, save_hash)
51
+ _hb.redirect("?show=project_edit&project_id=#{project.id}")
52
+ rescue => e
53
+ _hb.alert(e.message).back
54
+ end
55
+ end
56
+ end
57
+
58
+ print _site.header(title)
59
+ %>
60
+
61
+ <form method="post" action="?show=project_edit&amp;choice=dosave<%if project; print "&amp;project_id=#{project.id}"; end%>">
62
+
63
+ <%=_site.boxt(_("Enter details"), "500px")%>
64
+ <table class="form">
65
+ <%
66
+ print Knj::Web.inputs([{
67
+ :title => _("Name"),
68
+ :name => :texname,
69
+ :value => [project, :name],
70
+ :descr => _("The name of the project as it should appear in this system.")
71
+ },{
72
+ :title => _("Deadline"),
73
+ :name => :texdeadline,
74
+ :value => date_deadline_str,
75
+ :descr => _("The deadline of the project.")
76
+ }])
77
+
78
+ if _site.args[:customers]
79
+ print Knj::Web.inputs([{
80
+ :title => _("Customer"),
81
+ :name => :selcustomer,
82
+ :value => [project, :customer_id],
83
+ :descr => _("The customer that this project belongs under."),
84
+ :opts => _ob.list_optshash(:Customer, {:none => true})
85
+ }])
86
+ end
87
+
88
+ if project
89
+ if project.added_user
90
+ project_user_html = project.added_user.html
91
+ else
92
+ project_user_html = "[#{_("no user")}]"
93
+ end
94
+
95
+ print Knj::Web.inputs([{
96
+ :title => _("Added by"),
97
+ :type => :info,
98
+ :value => project_user_html,
99
+ :descr => _("The user that added this project.")
100
+ }])
101
+ end
102
+
103
+ print Knj::Web.inputs([{
104
+ :title => _("Description"),
105
+ :name => :texdescr,
106
+ :value => [project, :descr],
107
+ :type => :fckeditor,
108
+ :height => 400,
109
+ :descr => _("A description of the project to tell what it is about.")
110
+ }])
111
+ %>
112
+ <tr>
113
+ <td colspan="2" class="buttons">
114
+ <%if project%>
115
+ <input type="button" value="<%=_("Show")%>" onclick="location.href='<%=project.url%>';" />
116
+ <input type="button" value="<%=_("Add task")%>" onclick="location.href='?show=task_edit&amp;project_id=<%=project.id%>';" />
117
+ <input type="button" value="<%=_("Delete")%>" onclick="if (confirm('<%=_("Do you want to delete this project?")%>')){location.href='?show=project_edit&amp;project_id=<%=project.id%>&amp;choice=dodelete';}" />
118
+ <%end%>
119
+ <input type="submit" value="<%=_("Save")%>" />
120
+ </td>
121
+ </tr>
122
+ </table>
123
+ <%=_site.boxb%>
124
+
125
+ </form>
126
+
127
+ <script type="text/javascript">
128
+ $("#texname").focus();
129
+ </script>
@@ -0,0 +1,82 @@
1
+ <%
2
+ _hb.alert(_("You do not have permission to view this page.")).back if !_site.has_rank?("admin")
3
+
4
+ print _site.header(_("Search for project"))
5
+ %>
6
+
7
+ <form method="get">
8
+ <%=Knj::Web.hiddens([{:name => :show, :value => :project_search}, {:name => :choice, :value => :dosearch}])%>
9
+
10
+ <%=_site.boxt(_("Enter criteria"), "350px")%>
11
+ <table class="form">
12
+ <%
13
+ print Knj::Web.inputs([{
14
+ :title => _("Name"),
15
+ :name => :texname,
16
+ :value => _get["texname"],
17
+ :descr => _("A part of the name of the project you are looking for.")
18
+ }])
19
+ %>
20
+ <tr>
21
+ <td colspan="2" class="buttons">
22
+ <input type="button" value="<%=_("Add new")%>" onclick="location.href='?show=project_edit';" />
23
+ <input type="submit" value="<%=_("Search")%>" />
24
+ </td>
25
+ </tr>
26
+ </table>
27
+ <%=_site.boxb%>
28
+
29
+ </form>
30
+
31
+ <script type="text/javascript">
32
+ $("#texname").focus();
33
+ </script>
34
+
35
+ <%
36
+ if _get["choice"] == "dosearch"
37
+ args = {"orderby" => "name"}
38
+
39
+ if _get["texname"].to_s.length > 0
40
+ args["name_search"] = _get["texname"]
41
+ end
42
+
43
+ projects = _ob.list(:Project, args)
44
+
45
+ %>
46
+ <br />
47
+
48
+ <%=_site.boxt("Projects", "500px")%>
49
+ <table class="form">
50
+ <thead>
51
+ <tr>
52
+ <th><%=_("Name")%></th>
53
+ </tr>
54
+ </thead>
55
+ <tbody>
56
+ <%
57
+ projects.each do |project|
58
+ %>
59
+ <tr>
60
+ <td>
61
+ <%=project.html%>
62
+ </td>
63
+ </tr>
64
+ <%
65
+ end
66
+
67
+ if projects.empty?
68
+ %>
69
+ <tr>
70
+ <td colspan="1" class="error">
71
+ <%=_("No projects were found.")%>
72
+ </td>
73
+ </tr>
74
+ <%
75
+ end
76
+ %>
77
+ </tbody>
78
+ </table>
79
+ <%=_site.boxb%>
80
+ <%
81
+ end
82
+ %>
@@ -0,0 +1,203 @@
1
+ <%
2
+ project = _ob.get(:Project, _get["project_id"]) if _get["project_id"].to_i > 0
3
+
4
+ if _get["choice"] == "getassignedusers"
5
+ users = project.users("orderby" => "user_name")
6
+
7
+ %>
8
+ <table class="list">
9
+ <thead>
10
+ <tr>
11
+ <th><%=_"User"%></th>
12
+ <%if _site.has_rank?("admin")%>
13
+ <th><%=_"Actions"%></th>
14
+ <%end%>
15
+ </tr>
16
+ </thead>
17
+ <tbody>
18
+ <%
19
+ users.each do |link|
20
+ %>
21
+ <tr>
22
+ <td>
23
+ <%=link.user.html%>
24
+ </td>
25
+ <td>
26
+ (<a href="javascript: if (confirm('<%=_"Do you want to remove this user from the project?"%>')){project_remove_assigned_user('<%=link.id%>');}"><%=_"remove"%></a>)
27
+ </td>
28
+ </tr>
29
+ <%
30
+ end
31
+
32
+ if users.empty?
33
+ %>
34
+ <tr>
35
+ <td colspan="1" class="error">
36
+ <%=_"No users were found."%>
37
+ </td>
38
+ </tr>
39
+ <%
40
+ end
41
+ %>
42
+ </tbody>
43
+ </table>
44
+ <%
45
+
46
+ exit
47
+ end
48
+
49
+ if _get["choice"] == "doremoveassigneduser"
50
+ Php4r.die(_("You do not have access to this project.")) if !_site.has_rank?("admin")
51
+ link = _ob.get(:User_project_link, _get["link_id"])
52
+ _ob.delete(link)
53
+ exit
54
+ end
55
+
56
+ if _get["choice"] == "doassignuser"
57
+ Php4r.die(_("You do not have access to this project.")) if !_site.has_rank?("admin")
58
+
59
+ begin
60
+ link = _ob.add(:User_project_link, {
61
+ :project_id => project.id,
62
+ :user_id => _get["user_id"]
63
+ })
64
+ rescue Errno::EEXIST => e
65
+ print e.message
66
+ exit
67
+ end
68
+
69
+ exit
70
+ end
71
+
72
+ tasks = project.tasks("orderby" => [["date_added", "desc"], "name"])
73
+
74
+ print _site.header(sprintf(_("Show project: %s."), project.name.html))
75
+ %>
76
+
77
+ <table cellspacing="0" cellpadding="0">
78
+ <tr>
79
+ <td style="vertical-align: top;">
80
+ <%=_site.boxt(_("Actions"), 350)%>
81
+ <%if _site.has_rank?("admin")%>
82
+ <input type="button" value="<%=_"Edit project"%>" onclick="location.href='?show=project_edit&amp;project_id=<%=project.id%>';" />
83
+ <%end%>
84
+
85
+ <input type="button" value="<%=_"Add task"%>" onclick="location.href='?show=task_edit&amp;project_id=<%=project.id%>';" />
86
+ <%=_site.boxb%>
87
+
88
+ <br />
89
+
90
+ <%=_site.boxt(_("Information"), 350)%>
91
+ <table class="form">
92
+ <%
93
+ print Knj::Web.inputs([{
94
+ :title => _("Added by"),
95
+ :type => :info,
96
+ :value => project.added_user_html
97
+ },{
98
+ :title => _("Date"),
99
+ :type => :info,
100
+ :value => project.added_date_str(:time => false)
101
+ }])
102
+
103
+ if project.date_deadline
104
+ print _hb.inputs({
105
+ :title => _("Deadline"),
106
+ :type => :info,
107
+ :value => project.date_deadline_str(:time => false)
108
+ })
109
+ end
110
+ %>
111
+ </table>
112
+ <%=_site.boxb%>
113
+ </td>
114
+ <td style="vertical-align: top; padding-left: 15px;">
115
+ <%=_site.boxt(_("Users"), 350)%>
116
+ <div style="padding-bottom: 15px;">
117
+ <input type="button" value="<%=_"Assign user"%>" onclick="modal({title: '<%=_"Assign user to task"%>', url: 'clean.rhtml?show=user_search&amp;ajaxsearch=true&amp;jscallback=project_show_assign_user_choose'});" />
118
+ </div>
119
+
120
+ <div id="divassignedusers">
121
+ <div class="error">
122
+ <%=_"Loading - please wait..."%>
123
+ </div>
124
+ </div>
125
+ <%=_site.boxb%>
126
+ </td>
127
+ </tr>
128
+ </table>
129
+
130
+ <br />
131
+
132
+ <%=_site.boxt(_("Tasks"))%>
133
+ <table class="list">
134
+ <thead>
135
+ <tr>
136
+ <th><%=_"Task"%></th>
137
+ <th><%=_"Author"%></th>
138
+ <th><%=_"Status"%></th>
139
+ <th><%=_"Date"%></th>
140
+ </tr>
141
+ </thead>
142
+ <tbody>
143
+ <%
144
+ count = 0
145
+ tasks.each do |task|
146
+ next if !task.has_view_access?(_site.user)
147
+ count += 1
148
+
149
+ %>
150
+ <tr>
151
+ <td>
152
+ <%=task.html%>
153
+ </td>
154
+ <td>
155
+ <%=task.user_html%>
156
+ </td>
157
+ <td>
158
+ <%=_ob.static(:Task, :status_opts)[task[:status].to_sym].html%>
159
+ </td>
160
+ <td>
161
+ <%=task.date_added_str(:time => false)%>
162
+ </td>
163
+ </tr>
164
+ <%
165
+ end
166
+
167
+ if count <= 0
168
+ %>
169
+ <tr>
170
+ <td colspan="2" class="error">
171
+ <%=_("No tasks were found.")%>
172
+ </td>
173
+ </tr>
174
+ <%
175
+ end
176
+ %>
177
+ </tbody>
178
+ </table>
179
+ <%=_site.boxb%>
180
+
181
+ <script type="text/javascript">
182
+ function load_assigned_users(){
183
+ $.ajax({type: "GET", url: "/clean.rhtml?show=project_show&project_id=<%=project.id%>&choice=getassignedusers", async: true, cache: false, complete: function(data){
184
+ $("#divassignedusers").slideUp("fast", function(){
185
+ $("#divassignedusers").html(data.responseText);
186
+ $("#divassignedusers").slideDown("fast");
187
+ });
188
+ }});
189
+ }
190
+
191
+ function project_show_assign_user_choose(user_id){
192
+ modal_close();
193
+ project_assign_user("<%=project.id%>", user_id);
194
+ }
195
+
196
+ events.connect("do_project_assigned_users_update", function(){
197
+ load_assigned_users();
198
+ });
199
+
200
+ $(document).ready(function(){
201
+ load_assigned_users();
202
+ });
203
+ </script>