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,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,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
|
data/pages/admin.rhtml
ADDED
@@ -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&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&choice=dosave<%if customer; print "&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&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&customer_id=<%=customer.id%>&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&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%>
|