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,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%>