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 @@ | |
| 1 | 
            +
            Danish
         | 
| @@ -0,0 +1 @@ | |
| 1 | 
            +
            English
         | 
| @@ -0,0 +1,44 @@ | |
| 1 | 
            +
            class Knjtasks::Comment < Knj::Datarow
         | 
| 2 | 
            +
              has_one [
         | 
| 3 | 
            +
                {:class => :User, :required => true}
         | 
| 4 | 
            +
              ]
         | 
| 5 | 
            +
              
         | 
| 6 | 
            +
              def self.list(d)
         | 
| 7 | 
            +
                sql = "SELECT * FROM Comment WHERE 1=1"
         | 
| 8 | 
            +
                
         | 
| 9 | 
            +
                ret = list_helper(d)
         | 
| 10 | 
            +
                d.args.each do |key, val|
         | 
| 11 | 
            +
                  case key
         | 
| 12 | 
            +
                    when "object_lookup"
         | 
| 13 | 
            +
                      sql += " AND object_class = '#{val.table}' AND object_id = '#{d.db.esc(val.id)}'"
         | 
| 14 | 
            +
                    else
         | 
| 15 | 
            +
                      raise sprintf(_("Invalid key: %s."), key)
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
                
         | 
| 19 | 
            +
                sql += ret[:sql_where]
         | 
| 20 | 
            +
                sql += ret[:sql_order]
         | 
| 21 | 
            +
                sql += ret[:sql_limit]
         | 
| 22 | 
            +
                
         | 
| 23 | 
            +
                return d.ob.list_bysql(:Comment, sql)
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
              
         | 
| 26 | 
            +
              def self.add(d)
         | 
| 27 | 
            +
                d.data[:user_id ] = _site.user.id if !d.data[:user_id] and _site.user
         | 
| 28 | 
            +
                d.data[:date_saved] = Time.new if !d.data[:date_saved]
         | 
| 29 | 
            +
                
         | 
| 30 | 
            +
                raise "No 'object_class' was given." if !d.data[:object_class]
         | 
| 31 | 
            +
                raise "No 'object_id' was given." if !d.data[:object_id]
         | 
| 32 | 
            +
                
         | 
| 33 | 
            +
                obj = d.ob.get(d.data[:object_class], d.data[:object_id])
         | 
| 34 | 
            +
                user = d.ob.get(:User, d.data[:user_id])
         | 
| 35 | 
            +
              end
         | 
| 36 | 
            +
              
         | 
| 37 | 
            +
              def object
         | 
| 38 | 
            +
                return ob.get_try(self, :object_id, self[:object_class])
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
              
         | 
| 41 | 
            +
              def add_after(d)
         | 
| 42 | 
            +
                self.object.send_notify_new_comment(self) if self.object.class.name == "Knjtasks::Task"
         | 
| 43 | 
            +
              end
         | 
| 44 | 
            +
            end
         | 
| @@ -0,0 +1,13 @@ | |
| 1 | 
            +
            class Knjtasks::Customer < Knj::Datarow
         | 
| 2 | 
            +
              has_many [
         | 
| 3 | 
            +
                {:class => :Project, :col => :customer_id, :depends => true}
         | 
| 4 | 
            +
              ]
         | 
| 5 | 
            +
              
         | 
| 6 | 
            +
              def self.add(d)
         | 
| 7 | 
            +
                d.data[:date_added] = Time.new if !d.data[:date_added]
         | 
| 8 | 
            +
              end
         | 
| 9 | 
            +
              
         | 
| 10 | 
            +
              def html
         | 
| 11 | 
            +
                return "<a href=\"?show=customer_show&customer_id=#{id}\">#{name.html}</a>"
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
            end
         | 
| @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            class Knjtasks::Project < Knj::Datarow
         | 
| 2 | 
            +
              has_one [
         | 
| 3 | 
            +
                {:class => :User, :col => :added_user_id, :method => :added_user, :required => true},
         | 
| 4 | 
            +
                {:class => :Customer, :col => :customer_id, :method => :customer, :required => true}
         | 
| 5 | 
            +
              ]
         | 
| 6 | 
            +
              
         | 
| 7 | 
            +
              has_many [
         | 
| 8 | 
            +
                {:class => :Task, :col => :project_id, :depends => true},
         | 
| 9 | 
            +
                {:class => :User_project_link, :col => :project_id, :method => :users, :autodelete => true, :depends => true}
         | 
| 10 | 
            +
              ]
         | 
| 11 | 
            +
              
         | 
| 12 | 
            +
              def self.add(d)
         | 
| 13 | 
            +
                raise _("Invalid name given.") if d.data[:name].to_s.strip.length <= 0
         | 
| 14 | 
            +
                
         | 
| 15 | 
            +
                d.data[:added_user_id] = _site.user.id if !d.data[:added_user_id] and _site.user
         | 
| 16 | 
            +
                d.data[:added_date] = Time.new if !d.data[:added_date]
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
              
         | 
| 19 | 
            +
              def html
         | 
| 20 | 
            +
                return "<a href=\"?show=project_show&project_id=#{id}\">#{name.html}</a>"
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
            end
         | 
| @@ -0,0 +1,163 @@ | |
| 1 | 
            +
            class Knjtasks::Task < Knj::Datarow
         | 
| 2 | 
            +
              has_many [
         | 
| 3 | 
            +
                [:Timelog, :task_id],
         | 
| 4 | 
            +
                [:Task_assigned_user, :task_id, :assigned_users],
         | 
| 5 | 
            +
                [:Task_check, :task_id, :checks],
         | 
| 6 | 
            +
                [:User_task_list_link, :task_id, :user_lists]
         | 
| 7 | 
            +
              ]
         | 
| 8 | 
            +
              has_one [
         | 
| 9 | 
            +
                {:class => :Project, :required => true},
         | 
| 10 | 
            +
                :User
         | 
| 11 | 
            +
              ]
         | 
| 12 | 
            +
              
         | 
| 13 | 
            +
              def initialize(*args, &blk)
         | 
| 14 | 
            +
                super(*args, &blk)
         | 
| 15 | 
            +
                self[:priority] = 1 if self[:priority].to_i <= 0 or self[:priority].to_i > 10
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
              
         | 
| 18 | 
            +
              def self.add(d)
         | 
| 19 | 
            +
                raise _("No project-ID was given.") if d.data[:project_id].to_i <= 0
         | 
| 20 | 
            +
                raise _("Invalid name was given.") if d.data[:name].to_s.strip.length <= 0
         | 
| 21 | 
            +
                
         | 
| 22 | 
            +
                d.data[:user_id] = _site.user.id if _site.user
         | 
| 23 | 
            +
                d.data[:date_added] = Time.now if !d.data[:date_added]
         | 
| 24 | 
            +
                d.data[:priority] = 1 if d.data[:priority].to_i <= 0 or d.data[:priority].to_i > 10
         | 
| 25 | 
            +
                
         | 
| 26 | 
            +
                begin
         | 
| 27 | 
            +
                  task = d.ob.get(:Project, d.data[:project_id])
         | 
| 28 | 
            +
                rescue Errno::ENOENT
         | 
| 29 | 
            +
                  raise sprintf(_("A project with the given project-ID could not be found: '%s'."), d.data[:project_id])
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
              
         | 
| 33 | 
            +
              def self.type_opts(d)
         | 
| 34 | 
            +
                return {
         | 
| 35 | 
            +
                  :feature => _("Feature"),
         | 
| 36 | 
            +
                  :bug => _("Bug report"),
         | 
| 37 | 
            +
                  :question => _("Question")
         | 
| 38 | 
            +
                }
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
              
         | 
| 41 | 
            +
              def self.status_opts(d)
         | 
| 42 | 
            +
                return {
         | 
| 43 | 
            +
                  :open => _("Open"),
         | 
| 44 | 
            +
                  :confirmed => _("Confirmed"),
         | 
| 45 | 
            +
                  :waiting => _("Waiting"),
         | 
| 46 | 
            +
                  :closed => _("Closed")
         | 
| 47 | 
            +
                }
         | 
| 48 | 
            +
              end
         | 
| 49 | 
            +
              
         | 
| 50 | 
            +
              #Sends a notification about a newly added comment to a task.
         | 
| 51 | 
            +
              def send_notify_new_comment(comment)
         | 
| 52 | 
            +
                self.notify_emails.each do |data|
         | 
| 53 | 
            +
                  subj = "#{sprintf(_hb.gettext.gettext("Task #%1$s: %2$s", data[:user].locale), self.id, self.name)} - #{sprintf(_hb.gettext.gettext("New comment from: %s", data[:user].locale), comment.user.name)}"
         | 
| 54 | 
            +
                  
         | 
| 55 | 
            +
                  if !self.user
         | 
| 56 | 
            +
                    user_html = "[#{_hb.gettext.gettext("no user", data[:user].locale)}]"
         | 
| 57 | 
            +
                  else
         | 
| 58 | 
            +
                    user_html = comment.user.name.html
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
                  
         | 
| 61 | 
            +
                  html = ""
         | 
| 62 | 
            +
                  
         | 
| 63 | 
            +
                  html += sprintf(_hb.gettext.gettext("A new comment has been written to the task '%s'.", data[:user].locale), self.name)
         | 
| 64 | 
            +
                  html += "<br /><br />"
         | 
| 65 | 
            +
                  
         | 
| 66 | 
            +
                  html += "<b>#{_hb.gettext.gettext("Author", data[:user].locale)}:</b><br />"
         | 
| 67 | 
            +
                  html += "#{user_html}<br /><br />"
         | 
| 68 | 
            +
                  
         | 
| 69 | 
            +
                  html += "<b>#{_hb.gettext.gettext("Task", data[:user].locale)}:</b><br />"
         | 
| 70 | 
            +
                  html += "<a href=\"#{url}\">#{url}</a><br /><br />"
         | 
| 71 | 
            +
                  
         | 
| 72 | 
            +
                  html += "<b>#{_hb.gettext.gettext("Comment", data[:user].locale)}</b><br />"
         | 
| 73 | 
            +
                  html += comment[:comment]
         | 
| 74 | 
            +
                  
         | 
| 75 | 
            +
                  _hb.mail(:to => data[:email], :subject => subj, :html => html)
         | 
| 76 | 
            +
                end
         | 
| 77 | 
            +
              end
         | 
| 78 | 
            +
              
         | 
| 79 | 
            +
              #Sends a 
         | 
| 80 | 
            +
              def send_notify_assigned(user_assigned, user_by)
         | 
| 81 | 
            +
                return false if user_assigned[:email].to_s.strip.length <= 0
         | 
| 82 | 
            +
                
         | 
| 83 | 
            +
                subj = sprintf(_hb.gettext.gettext("You have been assigned to: %s", user_assigned.locale), self.name)
         | 
| 84 | 
            +
                
         | 
| 85 | 
            +
                html = ""
         | 
| 86 | 
            +
                
         | 
| 87 | 
            +
                html += "<b>#{_hb.gettext.gettext("Assigned by", user_assigned.locale)}:</b><br />"
         | 
| 88 | 
            +
                html += "#{user_by.name}<br /><br />"
         | 
| 89 | 
            +
                
         | 
| 90 | 
            +
                html += "<b>#{_hb.gettext.gettext("Task", user_assigned.locale)}:</b><br />"
         | 
| 91 | 
            +
                html += "<a href=\"#{url}\">#{url}</a><br /><br />"
         | 
| 92 | 
            +
                
         | 
| 93 | 
            +
                html += "<b>#{_hb.gettext.gettext("Description", user_assigned.locale)}</b><br />"
         | 
| 94 | 
            +
                html += self[:descr]
         | 
| 95 | 
            +
                
         | 
| 96 | 
            +
                _hb.mail(:to => user_assigned[:email], :subject => subj, :html => html)
         | 
| 97 | 
            +
              end
         | 
| 98 | 
            +
              
         | 
| 99 | 
            +
              #Returns the emails of the assigned users and the owner as an array.
         | 
| 100 | 
            +
              def notify_emails
         | 
| 101 | 
            +
                emails = {}
         | 
| 102 | 
            +
                emails[self.user[:email]] = self.user if self.user and self.user[:email].to_s.strip.length > 0
         | 
| 103 | 
            +
                
         | 
| 104 | 
            +
                assigned_users.each do |link|
         | 
| 105 | 
            +
                  user = link.user
         | 
| 106 | 
            +
                  next if !user or user[:email].to_s.strip.length <= 0
         | 
| 107 | 
            +
                  
         | 
| 108 | 
            +
                  emails[user[:email]] = user
         | 
| 109 | 
            +
                end
         | 
| 110 | 
            +
                
         | 
| 111 | 
            +
                ret = []
         | 
| 112 | 
            +
                emails.each do |email, user|
         | 
| 113 | 
            +
                  ret << {
         | 
| 114 | 
            +
                    :email => email,
         | 
| 115 | 
            +
                    :user => user
         | 
| 116 | 
            +
                  }
         | 
| 117 | 
            +
                end
         | 
| 118 | 
            +
                
         | 
| 119 | 
            +
                return ret
         | 
| 120 | 
            +
              end
         | 
| 121 | 
            +
              
         | 
| 122 | 
            +
              def url
         | 
| 123 | 
            +
                return "#{_site.args[:url]}/?show=task_show&task_id=#{id}"
         | 
| 124 | 
            +
              end
         | 
| 125 | 
            +
              
         | 
| 126 | 
            +
              def html
         | 
| 127 | 
            +
                return "<a href=\"?show=task_show&task_id=#{id}\">#{name.html}</a>"
         | 
| 128 | 
            +
              end
         | 
| 129 | 
            +
              
         | 
| 130 | 
            +
              def comments(args = {})
         | 
| 131 | 
            +
                return _ob.list(:Comment, {"object_lookup" => self}.merge(args))
         | 
| 132 | 
            +
              end
         | 
| 133 | 
            +
              
         | 
| 134 | 
            +
              def has_access?(user = _site.user)
         | 
| 135 | 
            +
                return false if !user
         | 
| 136 | 
            +
                return true if user.has_rank?("admin")
         | 
| 137 | 
            +
                return true if self[:user_id].to_s == user.id.to_s
         | 
| 138 | 
            +
                return false
         | 
| 139 | 
            +
              end
         | 
| 140 | 
            +
              
         | 
| 141 | 
            +
              def status_str
         | 
| 142 | 
            +
                return ob.static(:Task, :status_opts)[self[:status].to_sym]
         | 
| 143 | 
            +
              end
         | 
| 144 | 
            +
              
         | 
| 145 | 
            +
              def has_view_access?(user)
         | 
| 146 | 
            +
                return false if !user
         | 
| 147 | 
            +
                return true if self.has_access?(user)
         | 
| 148 | 
            +
                
         | 
| 149 | 
            +
                task_link = ob.get_by(:Task_assigned_user, {
         | 
| 150 | 
            +
                  "user" => user,
         | 
| 151 | 
            +
                  "task" => self
         | 
| 152 | 
            +
                })
         | 
| 153 | 
            +
                return true if task_link
         | 
| 154 | 
            +
                
         | 
| 155 | 
            +
                project_link = ob.get_by(:User_project_link, {
         | 
| 156 | 
            +
                  "user" => user,
         | 
| 157 | 
            +
                  "project" => self.project
         | 
| 158 | 
            +
                })
         | 
| 159 | 
            +
                return true if project_link
         | 
| 160 | 
            +
                
         | 
| 161 | 
            +
                return false
         | 
| 162 | 
            +
              end
         | 
| 163 | 
            +
            end
         | 
| @@ -0,0 +1,62 @@ | |
| 1 | 
            +
            class Knjtasks::Task_assigned_user < Knj::Datarow
         | 
| 2 | 
            +
              has_one [
         | 
| 3 | 
            +
                {:class => :User, :required => true},
         | 
| 4 | 
            +
                {:class => :Task, :required => true}
         | 
| 5 | 
            +
              ]
         | 
| 6 | 
            +
              
         | 
| 7 | 
            +
              def self.list(d)
         | 
| 8 | 
            +
                sql = "SELECT #{table}.* FROM #{table}"
         | 
| 9 | 
            +
                
         | 
| 10 | 
            +
                join_task = true if d.args["orderby"] == "project_task_names"
         | 
| 11 | 
            +
                join_task = true if d.args["task_status_not"]
         | 
| 12 | 
            +
                
         | 
| 13 | 
            +
                if join_task
         | 
| 14 | 
            +
                  orderby = "project_task_names"
         | 
| 15 | 
            +
                  d.args.delete("orderby")
         | 
| 16 | 
            +
                  
         | 
| 17 | 
            +
                  sql += "
         | 
| 18 | 
            +
                    LEFT JOIN Task ON
         | 
| 19 | 
            +
                      Task.id = #{table}.task_id
         | 
| 20 | 
            +
                    
         | 
| 21 | 
            +
                    LEFT JOIN Project ON
         | 
| 22 | 
            +
                      Project.id = Task.project_id
         | 
| 23 | 
            +
                  "
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
                
         | 
| 26 | 
            +
                sql += " WHERE 1=1"
         | 
| 27 | 
            +
                
         | 
| 28 | 
            +
                ret = list_helper(d)
         | 
| 29 | 
            +
                d.args.each do |key, val|
         | 
| 30 | 
            +
                  case key
         | 
| 31 | 
            +
                    when "task_status_not"
         | 
| 32 | 
            +
                      sql += " AND Task.status != '#{d.db.esc(val)}'"
         | 
| 33 | 
            +
                    else
         | 
| 34 | 
            +
                      raise sprintf(_("Invalid key: %s."), key)
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
                
         | 
| 38 | 
            +
                sql += ret[:sql_where]
         | 
| 39 | 
            +
                
         | 
| 40 | 
            +
                if orderby == "task_name"
         | 
| 41 | 
            +
                  sql += " ORDER BY Project.name, Task.name"
         | 
| 42 | 
            +
                else
         | 
| 43 | 
            +
                  sql += ret[:sql_order]
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
                
         | 
| 46 | 
            +
                sql += ret[:sql_limit]
         | 
| 47 | 
            +
                
         | 
| 48 | 
            +
                return d.ob.list_bysql(table, sql)
         | 
| 49 | 
            +
              end
         | 
| 50 | 
            +
              
         | 
| 51 | 
            +
              def self.add(d)
         | 
| 52 | 
            +
                link = d.ob.get_by(:Task_assigned_user, {
         | 
| 53 | 
            +
                  "task_id" => d.data[:task_id],
         | 
| 54 | 
            +
                  "user_id" => d.data[:user_id]
         | 
| 55 | 
            +
                })
         | 
| 56 | 
            +
                raise _("That user is already assigned to that task.") if link
         | 
| 57 | 
            +
              end
         | 
| 58 | 
            +
              
         | 
| 59 | 
            +
              def add_after(d)
         | 
| 60 | 
            +
                task.send_notify_assigned(user, _site.user)
         | 
| 61 | 
            +
              end
         | 
| 62 | 
            +
            end
         | 
| @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            class Knjtasks::Task_check < Knj::Datarow
         | 
| 2 | 
            +
              has_one [
         | 
| 3 | 
            +
                {:class => :User, :col => :added_user_id, :method => :user_added, :required => true},
         | 
| 4 | 
            +
                :Task
         | 
| 5 | 
            +
              ]
         | 
| 6 | 
            +
              
         | 
| 7 | 
            +
              def self.list(d)
         | 
| 8 | 
            +
                sql = "SELECT * FROM #{table} WHERE 1=1"
         | 
| 9 | 
            +
                
         | 
| 10 | 
            +
                ret = list_helper(d)
         | 
| 11 | 
            +
                d.args.each do |key, val|
         | 
| 12 | 
            +
                  raise sprintf(_("Invalid key: %s."), key)
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
                
         | 
| 15 | 
            +
                sql += ret[:sql_where]
         | 
| 16 | 
            +
                sql += ret[:sql_order]
         | 
| 17 | 
            +
                sql += ret[:sql_limit]
         | 
| 18 | 
            +
                
         | 
| 19 | 
            +
                return d.ob.list_bysql(:Task_check, sql)
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
              
         | 
| 22 | 
            +
              def self.add(d)
         | 
| 23 | 
            +
                d.data[:added_user_id] = _site.user.id if !d.data[:added_user_id] and _site.user
         | 
| 24 | 
            +
                d.data[:date_added] = Time.now if !d.data[:date_added]
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
            end
         | 
| @@ -0,0 +1,82 @@ | |
| 1 | 
            +
            class Knjtasks::Timelog < Knj::Datarow
         | 
| 2 | 
            +
              has_one [
         | 
| 3 | 
            +
                :Task,
         | 
| 4 | 
            +
                :User
         | 
| 5 | 
            +
              ]
         | 
| 6 | 
            +
              
         | 
| 7 | 
            +
              def self.list(d)
         | 
| 8 | 
            +
                sql = "SELECT"
         | 
| 9 | 
            +
                
         | 
| 10 | 
            +
                join_tasks = true if d.args["project_id"]
         | 
| 11 | 
            +
                
         | 
| 12 | 
            +
                if d.args[:count]
         | 
| 13 | 
            +
                  count = true
         | 
| 14 | 
            +
                  d.args.delete(:count)
         | 
| 15 | 
            +
                  sql += "
         | 
| 16 | 
            +
                    SUM(TIME_TO_SEC(Timelog.time)) AS sum_time,
         | 
| 17 | 
            +
                    SUM(TIME_TO_SEC(Timelog.time_transport)) AS sum_time_transport,
         | 
| 18 | 
            +
                    SUM(Timelog.transport_length) AS sum_transport_length
         | 
| 19 | 
            +
                  "
         | 
| 20 | 
            +
                else
         | 
| 21 | 
            +
                  sql += " Timelog.*"
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
                
         | 
| 24 | 
            +
                sql += " FROM Timelog"
         | 
| 25 | 
            +
                
         | 
| 26 | 
            +
                if join_tasks
         | 
| 27 | 
            +
                  sql += "
         | 
| 28 | 
            +
                    LEFT JOIN Task ON
         | 
| 29 | 
            +
                      Task.id = Timelog.task_id
         | 
| 30 | 
            +
                  "
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
                
         | 
| 33 | 
            +
                sql += " WHERE 1=1"
         | 
| 34 | 
            +
                
         | 
| 35 | 
            +
                ret = list_helper(d)
         | 
| 36 | 
            +
                d.args.each do |key, val|
         | 
| 37 | 
            +
                  case key
         | 
| 38 | 
            +
                    when "project_id"
         | 
| 39 | 
            +
                      if val.is_a?(Array)
         | 
| 40 | 
            +
                        sql += " AND Task.project_id IN (" + Knj::ArrayExt.join(:arr => val, :sep => ",", :surr => "'", :callback => proc{|data| d.db.esc(data)}) + ")"
         | 
| 41 | 
            +
                      else
         | 
| 42 | 
            +
                        sql += " AND Task.project_id = '#{d.db.esc(val)}'"
         | 
| 43 | 
            +
                      end
         | 
| 44 | 
            +
                    else
         | 
| 45 | 
            +
                      raise sprintf(_("Invalid key: %s."), key)
         | 
| 46 | 
            +
                  end
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
                
         | 
| 49 | 
            +
                sql += ret[:sql_where]
         | 
| 50 | 
            +
                sql += ret[:sql_order]
         | 
| 51 | 
            +
                
         | 
| 52 | 
            +
                if count
         | 
| 53 | 
            +
                  return d.db.query(sql).fetch
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
                
         | 
| 56 | 
            +
                sql += ret[:sql_limit]
         | 
| 57 | 
            +
                
         | 
| 58 | 
            +
                return d.ob.list_bysql(:Timelog, sql)
         | 
| 59 | 
            +
              end
         | 
| 60 | 
            +
              
         | 
| 61 | 
            +
              def self.add(d)
         | 
| 62 | 
            +
                d.data[:user_id] = _site.user.id if !d.data[:user_id] and _site.user
         | 
| 63 | 
            +
                raise _("No comment has been written.") if d.data[:comment].to_s.length <= 0
         | 
| 64 | 
            +
                task = d.ob.get(:Task, d.data[:task_id])
         | 
| 65 | 
            +
              end
         | 
| 66 | 
            +
              
         | 
| 67 | 
            +
              def html(args = {})
         | 
| 68 | 
            +
                if args[:key] == :id_localized
         | 
| 69 | 
            +
                  name = Knj::Locales.number_out(id, 0)
         | 
| 70 | 
            +
                elsif args[:key]
         | 
| 71 | 
            +
                  name = self[args[:key]].html
         | 
| 72 | 
            +
                else
         | 
| 73 | 
            +
                  name = sprintf(_("Timelog %s"), Knj::Locales.number_out(id, 0))
         | 
| 74 | 
            +
                end
         | 
| 75 | 
            +
                
         | 
| 76 | 
            +
                return "<a href=\"javascript: timelog_edit('#{id}');\">#{name}</a>"
         | 
| 77 | 
            +
              end
         | 
| 78 | 
            +
              
         | 
| 79 | 
            +
              def comment_html
         | 
| 80 | 
            +
                return Php4r.nl2br(Knj::Web.html(self[:comment]))
         | 
| 81 | 
            +
              end
         | 
| 82 | 
            +
            end
         | 
| @@ -0,0 +1,125 @@ | |
| 1 | 
            +
            class Knjtasks::User < Knj::Datarow
         | 
| 2 | 
            +
              has_many [
         | 
| 3 | 
            +
                {:class => :Task, :col => :user_id, :depends => true},
         | 
| 4 | 
            +
                {:class => :Task_assigned_user, :col => :user_id, :method => :assigned_to_tasks, :depends => true},
         | 
| 5 | 
            +
                {:class => :User_rank_link, :col => :user_id, :method => :ranks, :depends => true},
         | 
| 6 | 
            +
                {:class => :User_project_link, :col => :user_id, :method => :projects, :depends => true},
         | 
| 7 | 
            +
                [:User_task_list_link, :user_id, :user_lists]
         | 
| 8 | 
            +
              ]
         | 
| 9 | 
            +
              
         | 
| 10 | 
            +
              def delete
         | 
| 11 | 
            +
                raise _("Cannot delete user because that user has created tasks.") if ob.get_by(:Task, {"user" => self})
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
              
         | 
| 14 | 
            +
              def name
         | 
| 15 | 
            +
                if self[:name].to_s.length > 0
         | 
| 16 | 
            +
                  return self[:name]
         | 
| 17 | 
            +
                elsif self[:username].to_s.length > 0
         | 
| 18 | 
            +
                  return self[:username]
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
                
         | 
| 21 | 
            +
                raise "Could not figure out a name?"
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
              
         | 
| 24 | 
            +
              def locale
         | 
| 25 | 
            +
                return self[:locale] if self[:locale].to_s.length > 0
         | 
| 26 | 
            +
                return "en_GB"
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
              
         | 
| 29 | 
            +
              def has_rank?(rank_str)
         | 
| 30 | 
            +
                rank = self.ob.get_by(:User_rank, {
         | 
| 31 | 
            +
                  "id_str" => rank_str
         | 
| 32 | 
            +
                })
         | 
| 33 | 
            +
                return false if !rank
         | 
| 34 | 
            +
                
         | 
| 35 | 
            +
                rank_link = self.ob.get_by(:User_rank_link, {
         | 
| 36 | 
            +
                  "user" => self,
         | 
| 37 | 
            +
                  "rank" => rank
         | 
| 38 | 
            +
                })
         | 
| 39 | 
            +
                return false if !rank_link
         | 
| 40 | 
            +
                
         | 
| 41 | 
            +
                return true
         | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
              
         | 
| 44 | 
            +
              def has_email?
         | 
| 45 | 
            +
                return Knj::Strings.is_email?(self[:email])
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
              
         | 
| 48 | 
            +
              def html
         | 
| 49 | 
            +
                name_str = self[:name]
         | 
| 50 | 
            +
                if name_str.to_s.strip.length <= 0
         | 
| 51 | 
            +
                  name_str = self[:username]
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
                
         | 
| 54 | 
            +
                if name_str.to_s.strip.length <= 0
         | 
| 55 | 
            +
                  name_str = "[#{_("no name")}]"
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
                
         | 
| 58 | 
            +
                return "<a href=\"?show=user_show&user_id=#{id}\">#{name_str.html}</a>"
         | 
| 59 | 
            +
              end
         | 
| 60 | 
            +
              
         | 
| 61 | 
            +
              def has_view_access?(user)
         | 
| 62 | 
            +
                return false if !user
         | 
| 63 | 
            +
                return true if user.has_rank?("admin")
         | 
| 64 | 
            +
                
         | 
| 65 | 
            +
                res = _db.query("
         | 
| 66 | 
            +
                  SELECT
         | 
| 67 | 
            +
                    *
         | 
| 68 | 
            +
                  
         | 
| 69 | 
            +
                  FROM
         | 
| 70 | 
            +
                    User_project_link AS user_link,
         | 
| 71 | 
            +
                    User_project_link AS my_link
         | 
| 72 | 
            +
                  
         | 
| 73 | 
            +
                  WHERE
         | 
| 74 | 
            +
                    user_link.user_id = '#{_db.esc(user.id)}' AND
         | 
| 75 | 
            +
                    my_link.user_id = '#{_db.esc(self.id)}' AND
         | 
| 76 | 
            +
                    user_link.project_id = my_link.project_id
         | 
| 77 | 
            +
                  
         | 
| 78 | 
            +
                  LIMIT
         | 
| 79 | 
            +
                    1
         | 
| 80 | 
            +
                ").fetch
         | 
| 81 | 
            +
                return true if res
         | 
| 82 | 
            +
                
         | 
| 83 | 
            +
                return false
         | 
| 84 | 
            +
              end
         | 
| 85 | 
            +
              
         | 
| 86 | 
            +
              def customers
         | 
| 87 | 
            +
                customers = {}
         | 
| 88 | 
            +
                self.ob.list(:Project, {
         | 
| 89 | 
            +
                  [:User_project_link, "user_id"] => self.id
         | 
| 90 | 
            +
                }) do |project|
         | 
| 91 | 
            +
                  customer = project.customer
         | 
| 92 | 
            +
                  next if !customer or customers.key?(customer.id)
         | 
| 93 | 
            +
                  customers[customer.id] = customer
         | 
| 94 | 
            +
                end
         | 
| 95 | 
            +
                
         | 
| 96 | 
            +
                customers = customers.values.to_a
         | 
| 97 | 
            +
                customers.sort do |cust1, cust2|
         | 
| 98 | 
            +
                  cust1.name.downcase <=> cust2.name.downcase
         | 
| 99 | 
            +
                end
         | 
| 100 | 
            +
                
         | 
| 101 | 
            +
                return customers
         | 
| 102 | 
            +
              end
         | 
| 103 | 
            +
              
         | 
| 104 | 
            +
              #A list of all relevant users for this user (from the same customer).
         | 
| 105 | 
            +
              def users_list
         | 
| 106 | 
            +
                users = {}
         | 
| 107 | 
            +
                
         | 
| 108 | 
            +
                self.customers.each do |customer|
         | 
| 109 | 
            +
                  customer.projects do |project|
         | 
| 110 | 
            +
                    self.ob.list(:User, {
         | 
| 111 | 
            +
                      [:User_project_link, "project_id"] => project.id
         | 
| 112 | 
            +
                    }) do |user|
         | 
| 113 | 
            +
                      users[user.id] = user
         | 
| 114 | 
            +
                    end
         | 
| 115 | 
            +
                  end
         | 
| 116 | 
            +
                end
         | 
| 117 | 
            +
                
         | 
| 118 | 
            +
                users = users.values
         | 
| 119 | 
            +
                users.sort do |user1, user2|
         | 
| 120 | 
            +
                  user1.name.downcase <=> user2.name.downcase
         | 
| 121 | 
            +
                end
         | 
| 122 | 
            +
                
         | 
| 123 | 
            +
                return users
         | 
| 124 | 
            +
              end
         | 
| 125 | 
            +
            end
         |