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.
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>