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,66 @@
1
+ class Knjtasks::User_project_link < Knj::Datarow
2
+ has_one [
3
+ :User,
4
+ :Project
5
+ ]
6
+
7
+ def self.list(d)
8
+ if d.args["orderby"] == "user_name"
9
+ join_users = true
10
+ orderby = "User.name"
11
+ d.args.delete("orderby")
12
+ end
13
+
14
+ sql = "SELECT User_project_link.* FROM User_project_link"
15
+
16
+ if join_users
17
+ sql += "
18
+ LEFT JOIN User ON
19
+ User.id = User_project_link.user_id
20
+ "
21
+ end
22
+
23
+ sql += " WHERE 1=1"
24
+
25
+ ret = list_helper(d)
26
+ d.args.each do |key, val|
27
+ raise sprintf(_("Invalid key: '%s'."), key)
28
+ end
29
+
30
+ sql += ret[:sql_where]
31
+
32
+ sql += " GROUP BY User_project_link.id"
33
+
34
+ if orderby
35
+ sql += " ORDER BY #{orderby}"
36
+ else
37
+ sql += ret[:sql_order]
38
+ end
39
+
40
+ sql += ret[:sql_limit]
41
+
42
+ return d.ob.list_bysql(:User_project_link, sql)
43
+ end
44
+
45
+ def self.add(d)
46
+ user = d.ob.get(:User, d.data[:user_id])
47
+ project = d.ob.get(:Project, d.data[:project_id])
48
+
49
+ exists = d.ob.get_by(:User_project_link, {
50
+ "user" => user,
51
+ "project" => project
52
+ })
53
+ raise Errno::EEXIST, _("That user is already assigned to that project.") if exists
54
+ end
55
+
56
+ def add_after(d)
57
+ if self.user.has_email?
58
+ subj = sprintf(_hb.gettext.gettext("Assigned to project: %s", self.user.locale), self.project.name)
59
+
60
+ html = ""
61
+ html += sprintf(_hb.gettext.gettext("You have been assigned to the project: '%s'.", self.user.locale), self.project.name)
62
+
63
+ _hb.mail(:to => self.user[:email], :subject => subj, :html => html)
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,3 @@
1
+ class Knjtasks::User_rank < Knj::Datarow
2
+
3
+ end
@@ -0,0 +1,17 @@
1
+ class Knjtasks::User_rank_link < Knj::Datarow
2
+ has_one [
3
+ :User,
4
+ {:class => :User_rank, :col => :rank_id, :method => :rank}
5
+ ]
6
+
7
+ def self.add(d)
8
+ user = d.ob.get(:User, d.data[:user_id])
9
+ rank = d.ob.get(:User_rank, d.data[:rank_id])
10
+
11
+ link = d.ob.get_by(:User_rank_link, {
12
+ "user" => user,
13
+ "rank" => rank
14
+ })
15
+ raise _("That user already have that rank.") if link
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ class Knjtasks::User_task_list_link < Knj::Datarow
2
+ has_one [
3
+ :Task,
4
+ :User
5
+ ]
6
+
7
+ def self.add(d)
8
+ task = d.ob.get(:Task, d.data[:task_id])
9
+ user = d.ob.get(:User, d.data[:user_id])
10
+
11
+ link = d.ob.get_by(:User_task_list_link, {
12
+ "task" => task,
13
+ "user" => user
14
+ })
15
+ raise _("That user has already listed that task.") if link
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ <%
2
+ _hb.alert(_("You do not have permission to view this page.")).back if !_site.has_rank?("admin")
3
+
4
+ print _site.header(_("Administration"))
5
+ %>
6
+
7
+ <a href="?show=comment_update_id_per_obj"><%=_"Comments"%> - <%=_"Update ID per object"%></a><br />
@@ -0,0 +1,121 @@
1
+ <%
2
+ if _get["choice"] == "dosave"
3
+ save_hash = {
4
+ :comment => _post["texcomment"]
5
+ }
6
+ end
7
+
8
+ if _get["comment_id"].to_i > 0
9
+ comment = _ob.get(:Comment, _get["comment_id"])
10
+ url = "&comment_id=#{comment.id}"
11
+
12
+ if _get["choice"] == "dosave"
13
+ comment.update(save_hash)
14
+ exit
15
+ end
16
+
17
+ if _get["choice"] == "dodelete"
18
+ _ob.delete(comment)
19
+ exit
20
+ end
21
+ else
22
+ url = "&object_class=#{_get["object_class"]}&object_id=#{_get["object_id"]}"
23
+
24
+ if _get["choice"] == "dosave"
25
+ if _post.has_key?("seltaskstatus")
26
+ task = _ob.get(:Task, _get["object_id"])
27
+ last_comment = task.comments("orderby" => [["date_saved", "desc"]], "limit" => 1)
28
+
29
+ if last_comment.empty?
30
+ save_hash[:id_per_obj] = 1
31
+ else
32
+ save_hash[:id_per_obj] = last_comment.first[:id_per_obj].to_i + 1
33
+ end
34
+
35
+ if task[:status] != _post["seltaskstatus"]
36
+ task[:status] = _post["seltaskstatus"]
37
+ save_hash[:comment] = "#{_post["texcomment"]}<div style=\"padding-top: 15px;\">#{sprintf(_("Changed the task-status to '%s'."), task.status_str)}</div>"
38
+ end
39
+ end
40
+
41
+ save_hash[:object_class] = _get["object_class"]
42
+ save_hash[:object_id] = _get["object_id"]
43
+ comment = _ob.add(:Comment, save_hash)
44
+ exit
45
+ end
46
+ end
47
+ %>
48
+
49
+ <form id="form_comment" method="get" onsubmit="return do_save_comment();">
50
+
51
+ <%=_site.boxt(_("Enter details"))%>
52
+ <table class="form">
53
+ <%
54
+ print _hb.inputs({
55
+ :title => _("Comment"),
56
+ :name => :texcomment,
57
+ :value => [comment, :comment],
58
+ :type => :fckeditor,
59
+ :height => 380
60
+ })
61
+
62
+ if _get["object_class"] == "Task"
63
+ task = _ob.get(:Task, _get["object_id"])
64
+
65
+ print _hb.inputs({
66
+ :title => _("Task status"),
67
+ :name => :seltaskstatus,
68
+ :value => task[:status],
69
+ :opts => _ob.static(:Task, :status_opts),
70
+ :descr => _("If you want to change the status of the task as well, then you should choose the new status here.")
71
+ })
72
+ end
73
+ %>
74
+ <tr>
75
+ <td colspan="2" class="buttons">
76
+ <input type="submit" value="<%=_("Save")%>" />
77
+ </td>
78
+ </tr>
79
+ </table>
80
+ <%=_site.boxb%>
81
+
82
+ </form>
83
+
84
+ <script type="text/javascript">
85
+ function do_save_comment(){
86
+ comment_val = FCKeditorAPI.GetInstance("texcomment").GetHTML();
87
+ if (comment_val.length <= 0){
88
+ alert("<%=_('Please write a comment before saving.')%>");
89
+ return false;
90
+ }
91
+
92
+ $.ajax({
93
+ type: "POST",
94
+ url: "clean.rhtml?show=comment_edit&choice=dosave<%=url%>",
95
+ data: forms_inputs_read($("#form_comment")),
96
+ complete: function(data){
97
+ if (data.responseText.length > 0){
98
+ alert(data.responseText);
99
+ }else{
100
+ events.call("on_comment_added");
101
+ events.call("do_comments_update");
102
+ modal_close();
103
+ }
104
+ }
105
+ });
106
+ return false;
107
+ }
108
+
109
+ modal_on_opened(function(){
110
+ try{
111
+ fckeditor_set_focus();
112
+ }catch(err){
113
+ setTimeout("fckeditor_set_focus", 100);
114
+ }
115
+ });
116
+
117
+ function fckeditor_set_focus(){
118
+ oFCKeditor = FCKeditorAPI.GetInstance("texcomment");
119
+ oFCKeditor.Focus();
120
+ }
121
+ </script>
@@ -0,0 +1,41 @@
1
+ <%
2
+ _hb.alert(_("You do not have permission to view this page.")).back if !_site.has_rank?("admin")
3
+
4
+ if _get["choice"] == "doupdate"
5
+ objs = {}
6
+ _db.q("SELECT * FROM Comment WHERE id_per_obj = 0") do |comment_data|
7
+ objs[comment_data[:object_class]] = {} if !objs.has_key?(comment_data[:object_class])
8
+ objs[comment_data[:object_class]][comment_data[:object_id]] = true if !objs[comment_data[:object_class]].has_key?(comment_data[:object_id])
9
+ end
10
+
11
+ objs.each do |class_name, class_ids|
12
+ class_ids.each do |class_id, temp_val|
13
+ _db.q("SELECT * FROM Task") do |task_data|
14
+ count = 0
15
+ _db.q("SELECT * FROM Comment WHERE object_class = 'Task' AND object_id = '#{task_data[:id]}' ORDER BY date_saved") do |comment_data|
16
+ count += 1
17
+ count = comment_data[:id_per_obj].to_i if comment_data[:id_per_obj].to_i > count
18
+ _db.update(:Comment, {:id_per_obj => count}, {:id => comment_data[:id]}) if comment_data[:id_per_obj].to_i == 0
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ _hb.alert(_("Done")).redirect("?show=comment_update_id_per_obj")
25
+ end
26
+
27
+ print _site.header(_("Update comment IDs"))
28
+ %>
29
+
30
+ <%=_site.boxt(_("Actions"), 350)%>
31
+ <table class="form">
32
+ <%
33
+
34
+ %>
35
+ <tr>
36
+ <td colspan="2" class="buttons">
37
+ <input type="button" value="<%=_"Update"%>" onclick="location.href='?show=comment_update_id_per_obj&amp;choice=doupdate';" />
38
+ </td>
39
+ </tr>
40
+ </table>
41
+ <%=_site.boxb%>
@@ -0,0 +1,69 @@
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
+ save_hash = {
8
+ :name => _post["texname"]
9
+ }
10
+ end
11
+
12
+ if _get["customer_id"].to_i > 0
13
+ customer = _ob.get(:Customer, _get["customer_id"])
14
+ title = sprintf(_("Edit customer: %s"), customer.name.html)
15
+
16
+ if _get["choice"] == "dosave"
17
+ customer.update(save_hash)
18
+ _hb.redirect("?show=customer_edit&customer_id#{customer.id}")
19
+ end
20
+
21
+ if _get["choice"] == "dodelete"
22
+ _hb.on_error_go_back do
23
+ _ob.delete(customer)
24
+ _hb.redirect("?show=customer_search")
25
+ end
26
+ end
27
+ else
28
+ title = _("Add new customer")
29
+
30
+ if _get["choice"] == "dosave"
31
+ _hb.on_error_go_back do
32
+ customer = _ob.add(:Customer, save_hash)
33
+ _hb.redirect("?show=customer_edit&customer_id=#{customer.id}")
34
+ end
35
+ end
36
+ end
37
+
38
+ print _site.header(title)
39
+ %>
40
+
41
+ <form method="post" action="?show=customer_edit&amp;choice=dosave<%if customer; print "&amp;customer_id=#{customer.id}"; end%>">
42
+
43
+ <%=_site.boxt(_("Enter details"), "350px")%>
44
+ <table class="form">
45
+ <%
46
+ print Knj::Web.inputs([{
47
+ :title => _("Name"),
48
+ :name => :texname,
49
+ :value => [customer, :name],
50
+ :descr => _("The name of the customer as it should appear in the system.")
51
+ }])
52
+ %>
53
+ <tr>
54
+ <td colspan="2" class="buttons">
55
+ <%if customer%>
56
+ <input type="button" value="<%=_("Show")%>" onclick="location.href='?show=customer_show&amp;customer_id=<%=customer.id%>';" />
57
+ <input type="button" value="<%=_("Delete")%>" onclick="if (confirm('<%=_("Do you want to delete this customer?")%>')){location.href='?show=customer_edit&amp;customer_id=<%=customer.id%>&amp;choice=dodelete';}" />
58
+ <%end%>
59
+ <input type="submit" value="<%=_("Save")%>" />
60
+ </td>
61
+ </tr>
62
+ </table>
63
+ <%=_site.boxb%>
64
+
65
+ </form>
66
+
67
+ <script type="text/javascript">
68
+ $("#texname").focus();
69
+ </script>
@@ -0,0 +1,80 @@
1
+ <%
2
+ print _site.header(_("Search for customers"))
3
+ %>
4
+
5
+ <form method="get">
6
+ <%=Knj::Web.hiddens([{:name => :show, :value => :customer_search}, {:name => :choice, :value => :dosearch}])%>
7
+
8
+ <%=_site.boxt(_("Enter criteria"), "350px")%>
9
+ <table class="form">
10
+ <%
11
+ print Knj::Web.inputs([{
12
+ :title => _("Name"),
13
+ :name => :texname,
14
+ :value => _get["texname"],
15
+ :descr => _("A part of the customers name which you are looking for.")
16
+ }])
17
+ %>
18
+ <tr>
19
+ <td colspan="2" class="buttons">
20
+ <input type="button" value="<%=_("Add new customer")%>" onclick="location.href='?show=customer_edit';" />
21
+ <input type="submit" value="<%=_("Search")%>" />
22
+ </td>
23
+ </tr>
24
+ </table>
25
+ <%=_site.boxb%>
26
+
27
+ </form>
28
+
29
+ <script type="text/javascript">
30
+ $("#texname").focus();
31
+ </script>
32
+
33
+ <%
34
+ if _get["choice"] == "dosearch"
35
+ args = {"orderby" => "name"}
36
+
37
+ if _get["texname"].to_s.length > 0
38
+ args["name_search"] = _get["texname"]
39
+ end
40
+
41
+ customers = _ob.list(:Customer, args)
42
+
43
+ %>
44
+ <br />
45
+
46
+ <%=_site.boxt(_("Results"), "350px")%>
47
+ <table class="list">
48
+ <thead>
49
+ <tr>
50
+ <th><%=_("Customer")%></th>
51
+ </tr>
52
+ </thead>
53
+ <tbody>
54
+ <%
55
+ customers.each do |customer|
56
+ %>
57
+ <tr>
58
+ <td>
59
+ <%=customer.html%>
60
+ </td>
61
+ </tr>
62
+ <%
63
+ end
64
+
65
+ if customers.empty?
66
+ %>
67
+ <tr>
68
+ <td colspan="1" class="error">
69
+ <%=_("No customers were found.")%>
70
+ </td>
71
+ </tr>
72
+ <%
73
+ end
74
+ %>
75
+ </tbody>
76
+ </table>
77
+ <%=_site.boxb%>
78
+ <%
79
+ end
80
+ %>
@@ -0,0 +1,50 @@
1
+ <%
2
+ begin
3
+ customer = _ob.get(:Customer, _get["customer_id"])
4
+ rescue
5
+ _hb.alert(_("That customer do not exist.")).back
6
+ end
7
+
8
+ print _site.header(sprintf(_("Show customer: %s"), customer.name.html))
9
+ %>
10
+
11
+ <%=_site.boxt(_("Actions"), "350px")%>
12
+ <input type="button" value="<%=_("Edit customer")%>" onclick="location.href='?show=customer_edit&amp;customer_id=<%=customer.id%>';" />
13
+ <%=_site.boxb%>
14
+
15
+ <br />
16
+
17
+ <%=_site.boxt(_("Projects"), "350px")%>
18
+ <table class="list">
19
+ <thead>
20
+ <tr>
21
+ <th><%=_("Project")%></th>
22
+ </tr>
23
+ </thead>
24
+ <tbody>
25
+ <%
26
+ projects = customer.projects
27
+
28
+ projects.each do |project|
29
+ %>
30
+ <tr>
31
+ <td>
32
+ <%=project.html%>
33
+ </td>
34
+ </tr>
35
+ <%
36
+ end
37
+
38
+ if projects.empty?
39
+ %>
40
+ <tr>
41
+ <td colspan="1" class="error">
42
+ <%=_("No projects has been added for this customer.")%>
43
+ </td>
44
+ </tr>
45
+ <%
46
+ end
47
+ %>
48
+ </tbody>
49
+ </table>
50
+ <%=_site.boxb%>