confuddle 0.0.1
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/.gitignore +18 -0
 - data/.passwd_to_unfuddle.example.yml +7 -0
 - data/README.md +40 -0
 - data/bin/un +833 -0
 - data/bin/un.cmd +1 -0
 - data/confuddle.gemspec +22 -0
 - data/lib/graft/README.rdoc +138 -0
 - data/lib/graft/Rakefile +43 -0
 - data/lib/graft/lib/graft/core_ext/hash.rb +9 -0
 - data/lib/graft/lib/graft/json.rb +14 -0
 - data/lib/graft/lib/graft/json/attribute.rb +18 -0
 - data/lib/graft/lib/graft/json/model.rb +28 -0
 - data/lib/graft/lib/graft/model.rb +43 -0
 - data/lib/graft/lib/graft/version.rb +13 -0
 - data/lib/graft/lib/graft/xml.rb +19 -0
 - data/lib/graft/lib/graft/xml/attribute.rb +55 -0
 - data/lib/graft/lib/graft/xml/model.rb +49 -0
 - data/lib/graft/lib/graft/xml/type.rb +91 -0
 - data/lib/graft/test/test_helper.rb +38 -0
 - data/lib/graft/test/unit/core_ext/hash_test.rb +29 -0
 - data/lib/graft/test/unit/json/attribute_test.rb +51 -0
 - data/lib/graft/test/unit/json/model_test.rb +86 -0
 - data/lib/graft/test/unit/xml/attribute_test.rb +161 -0
 - data/lib/graft/test/unit/xml/model_test.rb +173 -0
 - data/lib/graft/test/unit/xml/type_test.rb +65 -0
 - data/lib/unfuzzle/.gitignore +4 -0
 - data/lib/unfuzzle/README.rdoc +129 -0
 - data/lib/unfuzzle/Rakefile +39 -0
 - data/lib/unfuzzle/lib/unfuzzle.rb +87 -0
 - data/lib/unfuzzle/lib/unfuzzle/comment.rb +37 -0
 - data/lib/unfuzzle/lib/unfuzzle/component.rb +31 -0
 - data/lib/unfuzzle/lib/unfuzzle/milestone.rb +54 -0
 - data/lib/unfuzzle/lib/unfuzzle/person.rb +20 -0
 - data/lib/unfuzzle/lib/unfuzzle/priority.rb +30 -0
 - data/lib/unfuzzle/lib/unfuzzle/project.rb +62 -0
 - data/lib/unfuzzle/lib/unfuzzle/request.rb +75 -0
 - data/lib/unfuzzle/lib/unfuzzle/response.rb +25 -0
 - data/lib/unfuzzle/lib/unfuzzle/severity.rb +31 -0
 - data/lib/unfuzzle/lib/unfuzzle/ticket.rb +156 -0
 - data/lib/unfuzzle/lib/unfuzzle/ticket_report.rb +29 -0
 - data/lib/unfuzzle/lib/unfuzzle/time_entry.rb +75 -0
 - data/lib/unfuzzle/lib/unfuzzle/version.rb +13 -0
 - data/lib/unfuzzle/test/fixtures/component.xml +8 -0
 - data/lib/unfuzzle/test/fixtures/components.xml +17 -0
 - data/lib/unfuzzle/test/fixtures/milestone.xml +12 -0
 - data/lib/unfuzzle/test/fixtures/milestones.xml +25 -0
 - data/lib/unfuzzle/test/fixtures/project.xml +17 -0
 - data/lib/unfuzzle/test/fixtures/projects.xml +35 -0
 - data/lib/unfuzzle/test/fixtures/severities.xml +24 -0
 - data/lib/unfuzzle/test/fixtures/severity.xml +8 -0
 - data/lib/unfuzzle/test/fixtures/ticket.xml +25 -0
 - data/lib/unfuzzle/test/fixtures/tickets.xml +51 -0
 - data/lib/unfuzzle/test/test_helper.rb +60 -0
 - data/lib/unfuzzle/test/unit/unfuzzle/component_test.rb +36 -0
 - data/lib/unfuzzle/test/unit/unfuzzle/milestone_test.rb +100 -0
 - data/lib/unfuzzle/test/unit/unfuzzle/priority_test.rb +25 -0
 - data/lib/unfuzzle/test/unit/unfuzzle/project_test.rb +87 -0
 - data/lib/unfuzzle/test/unit/unfuzzle/request_test.rb +104 -0
 - data/lib/unfuzzle/test/unit/unfuzzle/response_test.rb +37 -0
 - data/lib/unfuzzle/test/unit/unfuzzle/severity_test.rb +36 -0
 - data/lib/unfuzzle/test/unit/unfuzzle/ticket_test.rb +181 -0
 - data/lib/unfuzzle/test/unit/unfuzzle_test.rb +39 -0
 - data/lib/unfuzzle/unfuzzle.gemspec +31 -0
 - data/lib/version.rb +3 -0
 - metadata +176 -0
 
    
        data/.gitignore
    ADDED
    
    
    
        data/README.md
    ADDED
    
    | 
         @@ -0,0 +1,40 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            Console Unfuddle
         
     | 
| 
      
 2 
     | 
    
         
            +
            ================
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            Utility for work with unfuddle.com account from console
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            1. gem install confuddle
         
     | 
| 
      
 7 
     | 
    
         
            +
            2. un install
         
     | 
| 
      
 8 
     | 
    
         
            +
            3. Edit HOME_DIR/.passwd_to_unfuddle.yml and fill with your own values
         
     | 
| 
      
 9 
     | 
    
         
            +
            4. $ un projects
         
     | 
| 
      
 10 
     | 
    
         
            +
            and set for each project aliases "un alias"
         
     | 
| 
      
 11 
     | 
    
         
            +
            and set current project "un curr"
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            Tasks:
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                un addcm NUMBER                       # add ticket comment
         
     | 
| 
      
 16 
     | 
    
         
            +
                un addt NUMBER HOURS COMMENT [DATE]   # add time
         
     | 
| 
      
 17 
     | 
    
         
            +
                un alias PROJECT_ID ALIAS             # set project alias
         
     | 
| 
      
 18 
     | 
    
         
            +
                un all [REGEXP]                       # show all tickets for current project
         
     | 
| 
      
 19 
     | 
    
         
            +
                un alla [REGEXP]                      # show all (in all projects) tickets
         
     | 
| 
      
 20 
     | 
    
         
            +
                un assi TICKETS [NEW_ASSIGNEE]        # update tickets assingee
         
     | 
| 
      
 21 
     | 
    
         
            +
                un at PERIOD                          # show all times report for account (PERIOD = [tm lm tw lw y [0-9]+])
         
     | 
| 
      
 22 
     | 
    
         
            +
                un atm PERIOD                         # show my times report for account (PERIOD = [tm lm tw lw y [0-9]+])
         
     | 
| 
      
 23 
     | 
    
         
            +
                un clear                              # clear caches
         
     | 
| 
      
 24 
     | 
    
         
            +
                un curr ID_OR_ALIAS                   # set current project id
         
     | 
| 
      
 25 
     | 
    
         
            +
                un help [TASK]                        # Describe available tasks or one specific task
         
     | 
| 
      
 26 
     | 
    
         
            +
                un my                                 # show tickets assignee to me for current project
         
     | 
| 
      
 27 
     | 
    
         
            +
                un mya                                # show tickets (in all projects) assignee to me
         
     | 
| 
      
 28 
     | 
    
         
            +
                un new ALIAS TITLE [ASSIGNEE] [PRIO]  # create ticket
         
     | 
| 
      
 29 
     | 
    
         
            +
                un notify PARAMS                      # Notify about changes with tickets by Gnome-Notify, PARAMS='status,comments'
         
     | 
| 
      
 30 
     | 
    
         
            +
                un op TICKET_ID                       # Open selected ticked from current project in browser
         
     | 
| 
      
 31 
     | 
    
         
            +
                un projects                           # show all projects for your account
         
     | 
| 
      
 32 
     | 
    
         
            +
                un show NUMBER [t]                    # show ticket by number, [t] - show TimeEntries
         
     | 
| 
      
 33 
     | 
    
         
            +
                un t PERIOD                           # show all times report (PERIOD = [tm lm tw lw y [0-9]+])
         
     | 
| 
      
 34 
     | 
    
         
            +
                un tm PERIOD                          # show my times report (PERIOD = [tm lm tw lw y [0-9]+])
         
     | 
| 
      
 35 
     | 
    
         
            +
                un upd TICKETS NEW_STATUS             # update tickets statuses
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
            Used gems:
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                unfuzzle by Patrick Reagan of Viget Labs
         
     | 
| 
      
 40 
     | 
    
         
            +
                grapt by Patrick Reagan
         
     | 
    
        data/bin/un
    ADDED
    
    | 
         @@ -0,0 +1,833 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #!/usr/bin/env ruby
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            # Console Unfuddle
         
     | 
| 
      
 4 
     | 
    
         
            +
            # by Makarchev K. 2011
         
     | 
| 
      
 5 
     | 
    
         
            +
            # by Varamashvili M. 2011
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            WIN = RUBY_PLATFORM['mingw'] || RUBY_PLATFORM['mswin']
         
     | 
| 
      
 8 
     | 
    
         
            +
            MAC = RUBY_PLATFORM['darwin']
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            $KCODE='u' if RUBY_VERSION <= "1.8.7"
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            require 'rubygems'
         
     | 
| 
      
 13 
     | 
    
         
            +
            require 'yaml'
         
     | 
| 
      
 14 
     | 
    
         
            +
            require 'active_support'
         
     | 
| 
      
 15 
     | 
    
         
            +
            require 'active_support/time'
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            if(WIN)
         
     | 
| 
      
 18 
     | 
    
         
            +
              require 'iconv'
         
     | 
| 
      
 19 
     | 
    
         
            +
              require 'win32console'
         
     | 
| 
      
 20 
     | 
    
         
            +
              require File.expand_path(File.join(File.dirname(__FILE__), %w(.. lib unfuzzle lib unfuzzle) ))
         
     | 
| 
      
 21 
     | 
    
         
            +
            else
         
     | 
| 
      
 22 
     | 
    
         
            +
              dirname = File.symlink?(__FILE__) ? File.dirname(File.readlink(__FILE__)) : File.dirname(__FILE__)
         
     | 
| 
      
 23 
     | 
    
         
            +
              require File.expand_path(File.join(dirname, %w(.. lib unfuzzle lib unfuzzle) ))
         
     | 
| 
      
 24 
     | 
    
         
            +
            end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            require 'thor'
         
     | 
| 
      
 27 
     | 
    
         
            +
            require 'readline'
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            class Unfuddle < Thor
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
              UNFUDDLE_ENC = "utf-8"
         
     | 
| 
      
 32 
     | 
    
         
            +
              WIN_ENC = "cp866"
         
     | 
| 
      
 33 
     | 
    
         
            +
              CMD_WIN_ENC = "windows-1251"
         
     | 
| 
      
 34 
     | 
    
         
            +
              HOME_DIR = ENV['HOME']
         
     | 
| 
      
 35 
     | 
    
         
            +
              PASS_FILE = File.expand_path("#{HOME_DIR}/.passwd_to_unfuddle.yml")
         
     | 
| 
      
 36 
     | 
    
         
            +
              CACHED_PEOPLE = "#{HOME_DIR}/.cached_people.yml"
         
     | 
| 
      
 37 
     | 
    
         
            +
              CACHED_PROJECTS = "#{HOME_DIR}/.cached_projects.yml"
         
     | 
| 
      
 38 
     | 
    
         
            +
              CACHED_TICKETS = "#{HOME_DIR}/.cached_tickets.yml"
         
     | 
| 
      
 39 
     | 
    
         
            +
              CACHED_PERIOD = 10.days
         
     | 
| 
      
 40 
     | 
    
         
            +
              CACHED_PROJECTS_PERIOD = 10.days
         
     | 
| 
      
 41 
     | 
    
         
            +
              CACHED_TICKETS_PERIOD = 60 * 60
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
              attr_accessor :default_project_id, :projects_aliases
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
              def initialize(*args)
         
     | 
| 
      
 46 
     | 
    
         
            +
                task_name = args[2][:current_task].name rescue 'unknown'
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                unless task_name == 'install'
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                  get_config
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                  unless me_id
         
     | 
| 
      
 53 
     | 
    
         
            +
                    say "Error: no matches for me", :red, true
         
     | 
| 
      
 54 
     | 
    
         
            +
                    exit 1
         
     | 
| 
      
 55 
     | 
    
         
            +
                  end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                  @started_at = Time.now
         
     | 
| 
      
 58 
     | 
    
         
            +
                end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                super
         
     | 
| 
      
 61 
     | 
    
         
            +
              end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
            private
         
     | 
| 
      
 65 
     | 
    
         
            +
              def get_config
         
     | 
| 
      
 66 
     | 
    
         
            +
                unless File.exists?(PASS_FILE)
         
     | 
| 
      
 67 
     | 
    
         
            +
                  say "Error: not found #{PASS_FILE}, call `un install`", :red, true
         
     | 
| 
      
 68 
     | 
    
         
            +
                  exit 1
         
     | 
| 
      
 69 
     | 
    
         
            +
                end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                cfg = YAML.load_file(PASS_FILE)
         
     | 
| 
      
 72 
     | 
    
         
            +
                Unfuzzle.subdomain = cfg['subdomain']
         
     | 
| 
      
 73 
     | 
    
         
            +
                Unfuzzle.username  = cfg['username']
         
     | 
| 
      
 74 
     | 
    
         
            +
                Unfuzzle.password  = cfg['password']
         
     | 
| 
      
 75 
     | 
    
         
            +
                Unfuzzle.use_ssl   = true
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                self.default_project_id = cfg['default_project_id']
         
     | 
| 
      
 78 
     | 
    
         
            +
                self.default_project_id = cached_projects.keys.first if default_project_id.blank? || ([self.default_project_id] & cached_projects.keys).empty?
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                self.projects_aliases = cfg['projects_aliases'] || {}
         
     | 
| 
      
 81 
     | 
    
         
            +
              end
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
              def set_config
         
     | 
| 
      
 84 
     | 
    
         
            +
                h = {}
         
     | 
| 
      
 85 
     | 
    
         
            +
                h['subdomain'] = Unfuzzle.subdomain
         
     | 
| 
      
 86 
     | 
    
         
            +
                h['username'] = Unfuzzle.username
         
     | 
| 
      
 87 
     | 
    
         
            +
                h['password'] = Unfuzzle.password
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                h['default_project_id'] = self.default_project_id
         
     | 
| 
      
 90 
     | 
    
         
            +
                h['projects_aliases'] = self.projects_aliases
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                File.open(PASS_FILE, "w+"){ |file| file.puts(h.to_yaml) }
         
     | 
| 
      
 93 
     | 
    
         
            +
              end
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
              if WIN    
         
     | 
| 
      
 96 
     | 
    
         
            +
                def say(*args)
         
     | 
| 
      
 97 
     | 
    
         
            +
                  args[0] = Iconv.new(WIN_ENC, UNFUDDLE_ENC).iconv(args.at(0).to_s) rescue args.at(0).to_s
         
     | 
| 
      
 98 
     | 
    
         
            +
                  super
         
     | 
| 
      
 99 
     | 
    
         
            +
                end
         
     | 
| 
      
 100 
     | 
    
         
            +
              end
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
              def enc_input(text)
         
     | 
| 
      
 103 
     | 
    
         
            +
                if WIN
         
     | 
| 
      
 104 
     | 
    
         
            +
                  Iconv.new(UNFUDDLE_ENC, WIN_ENC).iconv(text.to_s)
         
     | 
| 
      
 105 
     | 
    
         
            +
                else
         
     | 
| 
      
 106 
     | 
    
         
            +
                  text
         
     | 
| 
      
 107 
     | 
    
         
            +
                end    
         
     | 
| 
      
 108 
     | 
    
         
            +
              end
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
              def enc_cmd(text)
         
     | 
| 
      
 111 
     | 
    
         
            +
                if WIN
         
     | 
| 
      
 112 
     | 
    
         
            +
                  Iconv.new(UNFUDDLE_ENC, CMD_WIN_ENC).iconv(text.to_s)
         
     | 
| 
      
 113 
     | 
    
         
            +
                else
         
     | 
| 
      
 114 
     | 
    
         
            +
                  text
         
     | 
| 
      
 115 
     | 
    
         
            +
                end    
         
     | 
| 
      
 116 
     | 
    
         
            +
              end
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
              def color(prio)
         
     | 
| 
      
 119 
     | 
    
         
            +
                case prio
         
     | 
| 
      
 120 
     | 
    
         
            +
                  when 1; :blue
         
     | 
| 
      
 121 
     | 
    
         
            +
                  when 2; :cyan
         
     | 
| 
      
 122 
     | 
    
         
            +
                  when 3; nil
         
     | 
| 
      
 123 
     | 
    
         
            +
                  when 4; :red
         
     | 
| 
      
 124 
     | 
    
         
            +
                  when 5; :on_red
         
     | 
| 
      
 125 
     | 
    
         
            +
                end
         
     | 
| 
      
 126 
     | 
    
         
            +
              end
         
     | 
| 
      
 127 
     | 
    
         
            +
             
     | 
| 
      
 128 
     | 
    
         
            +
              def read_text
         
     | 
| 
      
 129 
     | 
    
         
            +
                lines = []
         
     | 
| 
      
 130 
     | 
    
         
            +
                while line = Readline::readline("> ")
         
     | 
| 
      
 131 
     | 
    
         
            +
                  lines << line
         
     | 
| 
      
 132 
     | 
    
         
            +
                end
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
              rescue Interrupt => e
         
     | 
| 
      
 135 
     | 
    
         
            +
              ensure
         
     | 
| 
      
 136 
     | 
    
         
            +
                return enc_input(lines * "\n")
         
     | 
| 
      
 137 
     | 
    
         
            +
              end
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
              # people {id => name}
         
     | 
| 
      
 140 
     | 
    
         
            +
              def people
         
     | 
| 
      
 141 
     | 
    
         
            +
                @people ||= {}.tap do |h|
         
     | 
| 
      
 142 
     | 
    
         
            +
                  cached_people.each{|id, data| h[id] = data[:name] }
         
     | 
| 
      
 143 
     | 
    
         
            +
                end
         
     | 
| 
      
 144 
     | 
    
         
            +
              end
         
     | 
| 
      
 145 
     | 
    
         
            +
             
     | 
| 
      
 146 
     | 
    
         
            +
              # cached people
         
     | 
| 
      
 147 
     | 
    
         
            +
              def cached_people
         
     | 
| 
      
 148 
     | 
    
         
            +
                return @cached_people if @cached_people
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
      
 150 
     | 
    
         
            +
                # cached peoples
         
     | 
| 
      
 151 
     | 
    
         
            +
                if File.exists?(CACHED_PEOPLE) && File.ctime(CACHED_PEOPLE) > (Time.now - CACHED_PERIOD)
         
     | 
| 
      
 152 
     | 
    
         
            +
                  @cached_people = YAML.load_file(CACHED_PEOPLE)
         
     | 
| 
      
 153 
     | 
    
         
            +
                else
         
     | 
| 
      
 154 
     | 
    
         
            +
                  people = Unfuzzle::Person.all
         
     | 
| 
      
 155 
     | 
    
         
            +
                  @cached_people = {}
         
     | 
| 
      
 156 
     | 
    
         
            +
                  people.each do |person|
         
     | 
| 
      
 157 
     | 
    
         
            +
                    name = if person.last_name.to_s.blank?
         
     | 
| 
      
 158 
     | 
    
         
            +
                      person.first_name.to_s.split(" ").reverse.join(" ")
         
     | 
| 
      
 159 
     | 
    
         
            +
                    else
         
     | 
| 
      
 160 
     | 
    
         
            +
                      person.last_name.to_s + " " + person.first_name.to_s
         
     | 
| 
      
 161 
     | 
    
         
            +
                    end
         
     | 
| 
      
 162 
     | 
    
         
            +
                    name = name.split(" ")
         
     | 
| 
      
 163 
     | 
    
         
            +
                    if name.size > 0
         
     | 
| 
      
 164 
     | 
    
         
            +
                      name[1] = name[1].to_s.mb_chars[0].to_s + "."
         
     | 
| 
      
 165 
     | 
    
         
            +
                    end
         
     | 
| 
      
 166 
     | 
    
         
            +
                    name = name.join(" ")
         
     | 
| 
      
 167 
     | 
    
         
            +
                    @cached_people[person.id] = {:name => name, :login => person.username}
         
     | 
| 
      
 168 
     | 
    
         
            +
                  end
         
     | 
| 
      
 169 
     | 
    
         
            +
                  File.open(CACHED_PEOPLE, 'w'){|f| f.write(YAML.dump(@cached_people))}
         
     | 
| 
      
 170 
     | 
    
         
            +
                end
         
     | 
| 
      
 171 
     | 
    
         
            +
             
     | 
| 
      
 172 
     | 
    
         
            +
                @cached_people
         
     | 
| 
      
 173 
     | 
    
         
            +
              end
         
     | 
| 
      
 174 
     | 
    
         
            +
              
         
     | 
| 
      
 175 
     | 
    
         
            +
              # my id
         
     | 
| 
      
 176 
     | 
    
         
            +
              def me_id
         
     | 
| 
      
 177 
     | 
    
         
            +
                @me_id ||= cached_people.detect{|id, data| data[:login] == Unfuzzle.username}.at(0)
         
     | 
| 
      
 178 
     | 
    
         
            +
              end
         
     | 
| 
      
 179 
     | 
    
         
            +
             
     | 
| 
      
 180 
     | 
    
         
            +
              def me  
         
     | 
| 
      
 181 
     | 
    
         
            +
                @me ||= people[me_id]
         
     | 
| 
      
 182 
     | 
    
         
            +
              end
         
     | 
| 
      
 183 
     | 
    
         
            +
             
     | 
| 
      
 184 
     | 
    
         
            +
             
     | 
| 
      
 185 
     | 
    
         
            +
              def cached_projects
         
     | 
| 
      
 186 
     | 
    
         
            +
                return @cached_projects if @cached_projects
         
     | 
| 
      
 187 
     | 
    
         
            +
             
     | 
| 
      
 188 
     | 
    
         
            +
                # cached peoples
         
     | 
| 
      
 189 
     | 
    
         
            +
                if File.exists?(CACHED_PROJECTS) && File.ctime(CACHED_PROJECTS) > (Time.now - CACHED_PROJECTS_PERIOD)
         
     | 
| 
      
 190 
     | 
    
         
            +
                  @cached_projects = YAML.load_file(CACHED_PROJECTS)
         
     | 
| 
      
 191 
     | 
    
         
            +
                else
         
     | 
| 
      
 192 
     | 
    
         
            +
                  projects = Unfuzzle.projects
         
     | 
| 
      
 193 
     | 
    
         
            +
                  @cached_projects = {}
         
     | 
| 
      
 194 
     | 
    
         
            +
                  projects.each do |project|
         
     | 
| 
      
 195 
     | 
    
         
            +
                    @cached_projects[project.id] = project.name
         
     | 
| 
      
 196 
     | 
    
         
            +
                  end
         
     | 
| 
      
 197 
     | 
    
         
            +
                  File.open(CACHED_PROJECTS, 'w'){|f| f.write(YAML.dump(@cached_projects))}
         
     | 
| 
      
 198 
     | 
    
         
            +
                end
         
     | 
| 
      
 199 
     | 
    
         
            +
             
     | 
| 
      
 200 
     | 
    
         
            +
                @cached_projects
         
     | 
| 
      
 201 
     | 
    
         
            +
              end
         
     | 
| 
      
 202 
     | 
    
         
            +
             
     | 
| 
      
 203 
     | 
    
         
            +
              def cached_tickets(params)
         
     | 
| 
      
 204 
     | 
    
         
            +
                return @cached_tickets if @cached_tickets
         
     | 
| 
      
 205 
     | 
    
         
            +
                if File.exists?(CACHED_TICKETS)
         
     | 
| 
      
 206 
     | 
    
         
            +
                  yaml = YAML.load_file(CACHED_TICKETS)
         
     | 
| 
      
 207 
     | 
    
         
            +
                  @cached_tickets = yaml[params.to_s] || []
         
     | 
| 
      
 208 
     | 
    
         
            +
                else
         
     | 
| 
      
 209 
     | 
    
         
            +
                  @cached_tickets = []
         
     | 
| 
      
 210 
     | 
    
         
            +
                end
         
     | 
| 
      
 211 
     | 
    
         
            +
                @cached_tickets
         
     | 
| 
      
 212 
     | 
    
         
            +
              end
         
     | 
| 
      
 213 
     | 
    
         
            +
             
     | 
| 
      
 214 
     | 
    
         
            +
              def set_cached_tickets(t, params)
         
     | 
| 
      
 215 
     | 
    
         
            +
                yaml = if File.exists?(CACHED_TICKETS)
         
     | 
| 
      
 216 
     | 
    
         
            +
                  YAML.load_file(CACHED_TICKETS)
         
     | 
| 
      
 217 
     | 
    
         
            +
                else
         
     | 
| 
      
 218 
     | 
    
         
            +
                  {}
         
     | 
| 
      
 219 
     | 
    
         
            +
                end
         
     | 
| 
      
 220 
     | 
    
         
            +
             
     | 
| 
      
 221 
     | 
    
         
            +
                yaml[params.to_s] = t.map(&:to_hash)
         
     | 
| 
      
 222 
     | 
    
         
            +
             
     | 
| 
      
 223 
     | 
    
         
            +
                File.open(CACHED_TICKETS, 'w'){|f| f.write(YAML.dump(yaml))}
         
     | 
| 
      
 224 
     | 
    
         
            +
              end
         
     | 
| 
      
 225 
     | 
    
         
            +
             
     | 
| 
      
 226 
     | 
    
         
            +
              # number with alias
         
     | 
| 
      
 227 
     | 
    
         
            +
              def number_with_a(ticket)
         
     | 
| 
      
 228 
     | 
    
         
            +
                number_with_a_by_params(ticket.project_id, ticket.number)
         
     | 
| 
      
 229 
     | 
    
         
            +
              end
         
     | 
| 
      
 230 
     | 
    
         
            +
             
     | 
| 
      
 231 
     | 
    
         
            +
              def number_with_a_by_params(project_id, number)
         
     | 
| 
      
 232 
     | 
    
         
            +
                return number.to_s if project_id == self.default_project_id
         
     | 
| 
      
 233 
     | 
    
         
            +
                self.projects_aliases[ project_id ].to_s + number.to_s
         
     | 
| 
      
 234 
     | 
    
         
            +
              end
         
     | 
| 
      
 235 
     | 
    
         
            +
             
     | 
| 
      
 236 
     | 
    
         
            +
              def find_project_id_by_alias(al)
         
     | 
| 
      
 237 
     | 
    
         
            +
                return default_project_id if al.blank?
         
     | 
| 
      
 238 
     | 
    
         
            +
             
     | 
| 
      
 239 
     | 
    
         
            +
                res = self.projects_aliases.detect{|k,v| v == al}
         
     | 
| 
      
 240 
     | 
    
         
            +
                if res.present?
         
     | 
| 
      
 241 
     | 
    
         
            +
                  res.first.to_i
         
     | 
| 
      
 242 
     | 
    
         
            +
                else
         
     | 
| 
      
 243 
     | 
    
         
            +
                  default_project_id
         
     | 
| 
      
 244 
     | 
    
         
            +
                end
         
     | 
| 
      
 245 
     | 
    
         
            +
              end
         
     | 
| 
      
 246 
     | 
    
         
            +
             
     | 
| 
      
 247 
     | 
    
         
            +
              # parse number 
         
     | 
| 
      
 248 
     | 
    
         
            +
              # f1234 -> [project_id, 1234]
         
     | 
| 
      
 249 
     | 
    
         
            +
              # p1235 -> [project_id, 1235]
         
     | 
| 
      
 250 
     | 
    
         
            +
              # 1235  -> [default_project_id, 1235]
         
     | 
| 
      
 251 
     | 
    
         
            +
              def parse_number(entered_number)
         
     | 
| 
      
 252 
     | 
    
         
            +
                entered_number.to_s =~ /(.*?)([0-9]+)/i
         
     | 
| 
      
 253 
     | 
    
         
            +
                prj = $1.to_s
         
     | 
| 
      
 254 
     | 
    
         
            +
                num = $2.to_s
         
     | 
| 
      
 255 
     | 
    
         
            +
             
     | 
| 
      
 256 
     | 
    
         
            +
                if prj.blank?
         
     | 
| 
      
 257 
     | 
    
         
            +
                  [default_project_id, num.to_i]
         
     | 
| 
      
 258 
     | 
    
         
            +
                else
         
     | 
| 
      
 259 
     | 
    
         
            +
                  [find_project_id_by_alias(prj), num.to_i]
         
     | 
| 
      
 260 
     | 
    
         
            +
                end
         
     | 
| 
      
 261 
     | 
    
         
            +
              end
         
     | 
| 
      
 262 
     | 
    
         
            +
             
         
     | 
| 
      
 263 
     | 
    
         
            +
              # === Methods ===
         
     | 
| 
      
 264 
     | 
    
         
            +
             
     | 
| 
      
 265 
     | 
    
         
            +
              # find persons by regexp, if blank than find me
         
     | 
| 
      
 266 
     | 
    
         
            +
              def find_persons(regx = "")
         
     | 
| 
      
 267 
     | 
    
         
            +
                return nil if regx.nil?
         
     | 
| 
      
 268 
     | 
    
         
            +
             
     | 
| 
      
 269 
     | 
    
         
            +
                res = []
         
     | 
| 
      
 270 
     | 
    
         
            +
                if regx == ""
         
     | 
| 
      
 271 
     | 
    
         
            +
                  return [me_id]
         
     | 
| 
      
 272 
     | 
    
         
            +
                else
         
     | 
| 
      
 273 
     | 
    
         
            +
                  regx = enc_cmd(regx)
         
     | 
| 
      
 274 
     | 
    
         
            +
                  res = people.select{|id, login| login.mb_chars.downcase =~ /#{regx.mb_chars.strip.downcase}/i}
         
     | 
| 
      
 275 
     | 
    
         
            +
                end
         
     | 
| 
      
 276 
     | 
    
         
            +
             
     | 
| 
      
 277 
     | 
    
         
            +
                if !res.empty?
         
     | 
| 
      
 278 
     | 
    
         
            +
                  res.map &:first
         
     | 
| 
      
 279 
     | 
    
         
            +
                else
         
     | 
| 
      
 280 
     | 
    
         
            +
                  say "no peoples matched #{regx}"
         
     | 
| 
      
 281 
     | 
    
         
            +
                  []
         
     | 
| 
      
 282 
     | 
    
         
            +
                end
         
     | 
| 
      
 283 
     | 
    
         
            +
              end
         
     | 
| 
      
 284 
     | 
    
         
            +
             
     | 
| 
      
 285 
     | 
    
         
            +
              def show_projects #!
         
     | 
| 
      
 286 
     | 
    
         
            +
                projects = Unfuzzle.projects
         
     | 
| 
      
 287 
     | 
    
         
            +
             
     | 
| 
      
 288 
     | 
    
         
            +
                say "    ", nil, false
         
     | 
| 
      
 289 
     | 
    
         
            +
                say "id".ljust(10), nil, false
         
     | 
| 
      
 290 
     | 
    
         
            +
                say "name".ljust(20), nil, false
         
     | 
| 
      
 291 
     | 
    
         
            +
                say 'title'.ljust(20), nil, false
         
     | 
| 
      
 292 
     | 
    
         
            +
                say "disk-usage".ljust(20), nil, false
         
     | 
| 
      
 293 
     | 
    
         
            +
                say "alias"
         
     | 
| 
      
 294 
     | 
    
         
            +
             
     | 
| 
      
 295 
     | 
    
         
            +
                projects.each do |project|
         
     | 
| 
      
 296 
     | 
    
         
            +
                  say project.id.to_i == self.default_project_id ? "  * " : "    ", nil, false
         
     | 
| 
      
 297 
     | 
    
         
            +
                  say project.id.to_s.ljust(10), :yellow, false
         
     | 
| 
      
 298 
     | 
    
         
            +
                  say project.slug.ljust(20), :green, false
         
     | 
| 
      
 299 
     | 
    
         
            +
                  say project.name.ljust(20), nil, false
         
     | 
| 
      
 300 
     | 
    
         
            +
                  say project.disk_usage.to_s.ljust(20), nil, false
         
     | 
| 
      
 301 
     | 
    
         
            +
                  say projects_aliases[project.id].to_s
         
     | 
| 
      
 302 
     | 
    
         
            +
                end
         
     | 
| 
      
 303 
     | 
    
         
            +
              end
         
     | 
| 
      
 304 
     | 
    
         
            +
             
     | 
| 
      
 305 
     | 
    
         
            +
              # Ticket Heads
         
     | 
| 
      
 306 
     | 
    
         
            +
             
     | 
| 
      
 307 
     | 
    
         
            +
              def render_ticket_head(ticket)
         
     | 
| 
      
 308 
     | 
    
         
            +
                color = color(ticket.priority)
         
     | 
| 
      
 309 
     | 
    
         
            +
                say number_with_a(ticket).to_s.ljust(9), :yellow, false
         
     | 
| 
      
 310 
     | 
    
         
            +
                say ticket.title.mb_chars[0..60].ljust(65), color, false
         
     | 
| 
      
 311 
     | 
    
         
            +
                say ticket.status.ljust(14), color, false
         
     | 
| 
      
 312 
     | 
    
         
            +
                say people[ticket.reporter_id].to_s.mb_chars.ljust(15), color, false
         
     | 
| 
      
 313 
     | 
    
         
            +
                say people[ticket.assignee_id].to_s.mb_chars.ljust(15), color, false
         
     | 
| 
      
 314 
     | 
    
         
            +
                say ticket.hours.to_s, color, true
         
     | 
| 
      
 315 
     | 
    
         
            +
              end
         
     | 
| 
      
 316 
     | 
    
         
            +
              
         
     | 
| 
      
 317 
     | 
    
         
            +
              def render_ticket_heads(tickets)
         
     | 
| 
      
 318 
     | 
    
         
            +
                groups = {}
         
     | 
| 
      
 319 
     | 
    
         
            +
                tickets.each do |ticket|
         
     | 
| 
      
 320 
     | 
    
         
            +
                  groups[ticket.status] ||= []
         
     | 
| 
      
 321 
     | 
    
         
            +
                  groups[ticket.status] << ticket
         
     | 
| 
      
 322 
     | 
    
         
            +
                end
         
     | 
| 
      
 323 
     | 
    
         
            +
                
         
     | 
| 
      
 324 
     | 
    
         
            +
                groups.each do |group, tickets|
         
     | 
| 
      
 325 
     | 
    
         
            +
                  tickets = tickets.sort_by{|t| t.number.to_i}
         
     | 
| 
      
 326 
     | 
    
         
            +
                  tickets.each{|ticket| render_ticket_head(ticket) }
         
     | 
| 
      
 327 
     | 
    
         
            +
                  say ''
         
     | 
| 
      
 328 
     | 
    
         
            +
                end
         
     | 
| 
      
 329 
     | 
    
         
            +
              end
         
     | 
| 
      
 330 
     | 
    
         
            +
             
     | 
| 
      
 331 
     | 
    
         
            +
              def render_ticket_heads_by_people(t)
         
     | 
| 
      
 332 
     | 
    
         
            +
                groups = {}
         
     | 
| 
      
 333 
     | 
    
         
            +
                t.each do |ticket|
         
     | 
| 
      
 334 
     | 
    
         
            +
                  groups[ticket.assignee_id] ||= []
         
     | 
| 
      
 335 
     | 
    
         
            +
                  groups[ticket.assignee_id] << ticket
         
     | 
| 
      
 336 
     | 
    
         
            +
                end
         
     | 
| 
      
 337 
     | 
    
         
            +
             
     | 
| 
      
 338 
     | 
    
         
            +
                groups.each do |ass_id, tickets|
         
     | 
| 
      
 339 
     | 
    
         
            +
                  say "============== #{people[ass_id].to_s.mb_chars} ================ (#{tickets.size}) tickets", :on_red, true
         
     | 
| 
      
 340 
     | 
    
         
            +
                  render_ticket_heads tickets
         
     | 
| 
      
 341 
     | 
    
         
            +
                  say ''
         
     | 
| 
      
 342 
     | 
    
         
            +
                end
         
     | 
| 
      
 343 
     | 
    
         
            +
              end
         
     | 
| 
      
 344 
     | 
    
         
            +
             
     | 
| 
      
 345 
     | 
    
         
            +
              def render_ticket_heads_by_project(t)
         
     | 
| 
      
 346 
     | 
    
         
            +
                groups = {}
         
     | 
| 
      
 347 
     | 
    
         
            +
                t.each do |ticket|
         
     | 
| 
      
 348 
     | 
    
         
            +
                  groups[ticket.project_id] ||= []
         
     | 
| 
      
 349 
     | 
    
         
            +
                  groups[ticket.project_id] << ticket
         
     | 
| 
      
 350 
     | 
    
         
            +
                end
         
     | 
| 
      
 351 
     | 
    
         
            +
             
     | 
| 
      
 352 
     | 
    
         
            +
                groups.each do |project_id, tickets|
         
     | 
| 
      
 353 
     | 
    
         
            +
                  say "Project => #{cached_projects[project_id]}: ", :yellow, true
         
     | 
| 
      
 354 
     | 
    
         
            +
                  render_ticket_heads_by_people tickets
         
     | 
| 
      
 355 
     | 
    
         
            +
                  say ''
         
     | 
| 
      
 356 
     | 
    
         
            +
                end
         
     | 
| 
      
 357 
     | 
    
         
            +
              end
         
     | 
| 
      
 358 
     | 
    
         
            +
             
     | 
| 
      
 359 
     | 
    
         
            +
              def show_all_active_tickets(name = nil, all_projects = false) #!
         
     | 
| 
      
 360 
     | 
    
         
            +
                ass_ids = find_persons(name == "" ? nil : name) || []
         
     | 
| 
      
 361 
     | 
    
         
            +
                t = Unfuzzle::Ticket.all_by_dinamic_report(all_projects ? nil : [default_project_id], false)
         
     | 
| 
      
 362 
     | 
    
         
            +
                t.reject!{|ticket| !ass_ids.blank? && !ass_ids.include?(ticket.assignee_id) }
         
     | 
| 
      
 363 
     | 
    
         
            +
                render_ticket_heads_by_project t
         
     | 
| 
      
 364 
     | 
    
         
            +
              end  
         
     | 
| 
      
 365 
     | 
    
         
            +
              
         
     | 
| 
      
 366 
     | 
    
         
            +
              def show_my_tickets(all_projects = false) #!
         
     | 
| 
      
 367 
     | 
    
         
            +
                t = Unfuzzle::Ticket.all_by_dinamic_report(all_projects ? nil : [default_project_id], true)
         
     | 
| 
      
 368 
     | 
    
         
            +
                render_ticket_heads_by_project t
         
     | 
| 
      
 369 
     | 
    
         
            +
              end
         
     | 
| 
      
 370 
     | 
    
         
            +
             
     | 
| 
      
 371 
     | 
    
         
            +
              # TimeEntry
         
     | 
| 
      
 372 
     | 
    
         
            +
             
     | 
| 
      
 373 
     | 
    
         
            +
              def render_times(times, sum_only = false)
         
     | 
| 
      
 374 
     | 
    
         
            +
                times = times.sort_by{|t| t.date.to_s }
         
     | 
| 
      
 375 
     | 
    
         
            +
             
     | 
| 
      
 376 
     | 
    
         
            +
                sum = 0
         
     | 
| 
      
 377 
     | 
    
         
            +
                title_present = false
         
     | 
| 
      
 378 
     | 
    
         
            +
             
     | 
| 
      
 379 
     | 
    
         
            +
                times.each do |time|
         
     | 
| 
      
 380 
     | 
    
         
            +
                  unless sum_only
         
     | 
| 
      
 381 
     | 
    
         
            +
                    #say time.ticket_id.to_s.ljust(8), :yellow, false
         
     | 
| 
      
 382 
     | 
    
         
            +
                    title_present = true if time.title.present?
         
     | 
| 
      
 383 
     | 
    
         
            +
                    say time.title.to_s.mb_chars[0..30].ljust(34), :yellow, false if title_present
         
     | 
| 
      
 384 
     | 
    
         
            +
                    say time.description.mb_chars[0..50].ljust(54), nil, false
         
     | 
| 
      
 385 
     | 
    
         
            +
                    say (time.hours.to_s + " h.").ljust(9), nil, false
         
     | 
| 
      
 386 
     | 
    
         
            +
                    say people[time.person_id].to_s.mb_chars.ljust(13), nil, false
         
     | 
| 
      
 387 
     | 
    
         
            +
                    say time.date, nil
         
     | 
| 
      
 388 
     | 
    
         
            +
                  end
         
     | 
| 
      
 389 
     | 
    
         
            +
                  
         
     | 
| 
      
 390 
     | 
    
         
            +
                  sum += time.hours.to_f      
         
     | 
| 
      
 391 
     | 
    
         
            +
                end
         
     | 
| 
      
 392 
     | 
    
         
            +
                
         
     | 
| 
      
 393 
     | 
    
         
            +
                say ''.ljust(34), nil, false if title_present
         
     | 
| 
      
 394 
     | 
    
         
            +
                say ''.ljust(54), nil, false
         
     | 
| 
      
 395 
     | 
    
         
            +
                say (sum.to_s + " h.").ljust(10), :red, true
         
     | 
| 
      
 396 
     | 
    
         
            +
                
         
     | 
| 
      
 397 
     | 
    
         
            +
                sum
         
     | 
| 
      
 398 
     | 
    
         
            +
              end
         
     | 
| 
      
 399 
     | 
    
         
            +
              
         
     | 
| 
      
 400 
     | 
    
         
            +
              def render_people_times(times, sum_only = false)
         
     | 
| 
      
 401 
     | 
    
         
            +
                groups = {}
         
     | 
| 
      
 402 
     | 
    
         
            +
                times.each do |time|
         
     | 
| 
      
 403 
     | 
    
         
            +
                  groups[time.person_id] ||= []
         
     | 
| 
      
 404 
     | 
    
         
            +
                  groups[time.person_id] << time
         
     | 
| 
      
 405 
     | 
    
         
            +
                end
         
     | 
| 
      
 406 
     | 
    
         
            +
                
         
     | 
| 
      
 407 
     | 
    
         
            +
                groups.each do |group, times|
         
     | 
| 
      
 408 
     | 
    
         
            +
                  say "============== #{people[group].to_s.mb_chars} ================", :on_red, true
         
     | 
| 
      
 409 
     | 
    
         
            +
                  render_times(times, sum_only)
         
     | 
| 
      
 410 
     | 
    
         
            +
                  say ''
         
     | 
| 
      
 411 
     | 
    
         
            +
                end
         
     | 
| 
      
 412 
     | 
    
         
            +
              end
         
     | 
| 
      
 413 
     | 
    
         
            +
             
     | 
| 
      
 414 
     | 
    
         
            +
              def filter_times(times, for_id = nil)
         
     | 
| 
      
 415 
     | 
    
         
            +
                times.select do |time|
         
     | 
| 
      
 416 
     | 
    
         
            +
                  time.person_id == for_id
         
     | 
| 
      
 417 
     | 
    
         
            +
                end
         
     | 
| 
      
 418 
     | 
    
         
            +
              end
         
     | 
| 
      
 419 
     | 
    
         
            +
             
     | 
| 
      
 420 
     | 
    
         
            +
              def times_report(me = false, period = 0, sum_only=false)
         
     | 
| 
      
 421 
     | 
    
         
            +
                p = periods(period)
         
     | 
| 
      
 422 
     | 
    
         
            +
                t = Unfuzzle::TimeEntry.time_invested(default_project_id, p.at(0), p.at(1))
         
     | 
| 
      
 423 
     | 
    
         
            +
                t = filter_times(t, me_id) if me
         
     | 
| 
      
 424 
     | 
    
         
            +
                render_people_times(t, sum_only)
         
     | 
| 
      
 425 
     | 
    
         
            +
              end
         
     | 
| 
      
 426 
     | 
    
         
            +
             
     | 
| 
      
 427 
     | 
    
         
            +
              def all_times_report(me = false, period = 0, sum_only=false)
         
     | 
| 
      
 428 
     | 
    
         
            +
                p = periods(period)
         
     | 
| 
      
 429 
     | 
    
         
            +
                t = Unfuzzle::TimeEntry.all_time_invested(p.at(0), p.at(1))
         
     | 
| 
      
 430 
     | 
    
         
            +
                t = filter_times(t, me_id) if me
         
     | 
| 
      
 431 
     | 
    
         
            +
                render_people_times(t, sum_only)
         
     | 
| 
      
 432 
     | 
    
         
            +
              end
         
     | 
| 
      
 433 
     | 
    
         
            +
             
     | 
| 
      
 434 
     | 
    
         
            +
              def periods(period)
         
     | 
| 
      
 435 
     | 
    
         
            +
                case period
         
     | 
| 
      
 436 
     | 
    
         
            +
                  when 'ty' then [Time.now.beginning_of_year, Time.now]
         
     | 
| 
      
 437 
     | 
    
         
            +
                  when 'ly' then [(Time.now.beginning_of_year-1.seconds).beginning_of_year, (Time.now.beginning_of_year-1.seconds)]
         
     | 
| 
      
 438 
     | 
    
         
            +
                  when 'tm' then [Time.now.beginning_of_month, Time.now]
         
     | 
| 
      
 439 
     | 
    
         
            +
                  when 'lm' then [(Time.now.beginning_of_month-1.seconds).beginning_of_month, (Time.now.beginning_of_month-1.seconds)]
         
     | 
| 
      
 440 
     | 
    
         
            +
                  when 'tw' then [Time.now.beginning_of_week, Time.now]
         
     | 
| 
      
 441 
     | 
    
         
            +
                  when 'lw' then [(Time.now.beginning_of_week-1.seconds).beginning_of_week, (Time.now.beginning_of_week-1.seconds)]
         
     | 
| 
      
 442 
     | 
    
         
            +
                  when 'y' then [(Time.new - 1.day).beginning_of_day, ((Time.new - 1.day).end_of_day)]
         
     | 
| 
      
 443 
     | 
    
         
            +
                  else [Time.now - period.to_i.days, Time.now]
         
     | 
| 
      
 444 
     | 
    
         
            +
                end
         
     | 
| 
      
 445 
     | 
    
         
            +
              end
         
     | 
| 
      
 446 
     | 
    
         
            +
             
     | 
| 
      
 447 
     | 
    
         
            +
              # Ticket
         
     | 
| 
      
 448 
     | 
    
         
            +
             
     | 
| 
      
 449 
     | 
    
         
            +
              def render_comment(cm)
         
     | 
| 
      
 450 
     | 
    
         
            +
                say people[cm.author_id].to_s.mb_chars, :on_blue, false
         
     | 
| 
      
 451 
     | 
    
         
            +
                say "  " + cm.created_at.to_s, nil, true
         
     | 
| 
      
 452 
     | 
    
         
            +
                say cm.body.mb_chars, nil, true
         
     | 
| 
      
 453 
     | 
    
         
            +
              end
         
     | 
| 
      
 454 
     | 
    
         
            +
             
     | 
| 
      
 455 
     | 
    
         
            +
              def render_ticket(t, comments = [], time_entries = [])
         
     | 
| 
      
 456 
     | 
    
         
            +
                color = color(t.priority)
         
     | 
| 
      
 457 
     | 
    
         
            +
             
     | 
| 
      
 458 
     | 
    
         
            +
                say number_with_a(t).to_s, :on_red
         
     | 
| 
      
 459 
     | 
    
         
            +
                say t.title.to_s.mb_chars, :on_blue
         
     | 
| 
      
 460 
     | 
    
         
            +
                say cached_projects[t.project_id].to_s, color, true
         
     | 
| 
      
 461 
     | 
    
         
            +
                say t.status, color
         
     | 
| 
      
 462 
     | 
    
         
            +
                say t.priority_name, color    
         
     | 
| 
      
 463 
     | 
    
         
            +
                say people[t.reporter_id].to_s + " => " + people[t.assignee_id].to_s, color, true
         
     | 
| 
      
 464 
     | 
    
         
            +
                say t.description.to_s.mb_chars, color, true
         
     | 
| 
      
 465 
     | 
    
         
            +
                say t.hours.to_s + " h.", color
         
     | 
| 
      
 466 
     | 
    
         
            +
             
     | 
| 
      
 467 
     | 
    
         
            +
                if !time_entries.blank?
         
     | 
| 
      
 468 
     | 
    
         
            +
                  say ''
         
     | 
| 
      
 469 
     | 
    
         
            +
                  say "Time Entries: ", :blue, true
         
     | 
| 
      
 470 
     | 
    
         
            +
                  render_times(time_entries)
         
     | 
| 
      
 471 
     | 
    
         
            +
                end
         
     | 
| 
      
 472 
     | 
    
         
            +
             
     | 
| 
      
 473 
     | 
    
         
            +
                if !comments.blank?
         
     | 
| 
      
 474 
     | 
    
         
            +
                  say ''
         
     | 
| 
      
 475 
     | 
    
         
            +
                  say 'Comments: ', :on_red, true
         
     | 
| 
      
 476 
     | 
    
         
            +
                  comments.each{|cm| render_comment(cm) }
         
     | 
| 
      
 477 
     | 
    
         
            +
                end
         
     | 
| 
      
 478 
     | 
    
         
            +
              end
         
     | 
| 
      
 479 
     | 
    
         
            +
             
     | 
| 
      
 480 
     | 
    
         
            +
              def show_ticket(num, opt)
         
     | 
| 
      
 481 
     | 
    
         
            +
                prj, number = parse_number(num)
         
     | 
| 
      
 482 
     | 
    
         
            +
                t, cm = Unfuzzle::Ticket.find_first_by_project_id_and_number_with_comments(prj, number)
         
     | 
| 
      
 483 
     | 
    
         
            +
                times = (opt == "t") ? Unfuzzle::TimeEntry.all_for_ticket(t) : []
         
     | 
| 
      
 484 
     | 
    
         
            +
                render_ticket(t, cm, times)
         
     | 
| 
      
 485 
     | 
    
         
            +
              end
         
     | 
| 
      
 486 
     | 
    
         
            +
             
     | 
| 
      
 487 
     | 
    
         
            +
              def open_ticket_in_browser(num)
         
     | 
| 
      
 488 
     | 
    
         
            +
                prj, number = parse_number(num)
         
     | 
| 
      
 489 
     | 
    
         
            +
                url = "https://#{Unfuzzle.subdomain}.unfuddle.com/a#/projects/#{prj}/tickets/by_number/#{number}"
         
     | 
| 
      
 490 
     | 
    
         
            +
                if(WIN)
         
     | 
| 
      
 491 
     | 
    
         
            +
                  system("start #{url}")
         
     | 
| 
      
 492 
     | 
    
         
            +
                elsif(MAC)
         
     | 
| 
      
 493 
     | 
    
         
            +
                  system("open #{url}")
         
     | 
| 
      
 494 
     | 
    
         
            +
                else
         
     | 
| 
      
 495 
     | 
    
         
            +
                  system("xdg-open #{url}")
         
     | 
| 
      
 496 
     | 
    
         
            +
                end
         
     | 
| 
      
 497 
     | 
    
         
            +
              end
         
     | 
| 
      
 498 
     | 
    
         
            +
             
     | 
| 
      
 499 
     | 
    
         
            +
              # 
         
     | 
| 
      
 500 
     | 
    
         
            +
              def update_tickets(tickets, new_status)
         
     | 
| 
      
 501 
     | 
    
         
            +
                tickets = tickets.split(",").map &:strip
         
     | 
| 
      
 502 
     | 
    
         
            +
                if !tickets.blank? && !new_status.blank?
         
     | 
| 
      
 503 
     | 
    
         
            +
                  ts = tickets.map{|num| 
         
     | 
| 
      
 504 
     | 
    
         
            +
                    prj, number = parse_number(num)
         
     | 
| 
      
 505 
     | 
    
         
            +
                    Unfuzzle::Ticket.find_first_by_project_id_and_number(prj, number) rescue nil 
         
     | 
| 
      
 506 
     | 
    
         
            +
                  }.compact
         
     | 
| 
      
 507 
     | 
    
         
            +
                  say "Update tickets #{ts.map(&:number) * ','} to status #{new_status}"
         
     | 
| 
      
 508 
     | 
    
         
            +
             
     | 
| 
      
 509 
     | 
    
         
            +
                  ts.each do |t|
         
     | 
| 
      
 510 
     | 
    
         
            +
                    t.status = new_status
         
     | 
| 
      
 511 
     | 
    
         
            +
                    t.update
         
     | 
| 
      
 512 
     | 
    
         
            +
                    render_ticket(t)
         
     | 
| 
      
 513 
     | 
    
         
            +
                  end
         
     | 
| 
      
 514 
     | 
    
         
            +
                else
         
     | 
| 
      
 515 
     | 
    
         
            +
                  say "no one tickets"
         
     | 
| 
      
 516 
     | 
    
         
            +
                end
         
     | 
| 
      
 517 
     | 
    
         
            +
              end
         
     | 
| 
      
 518 
     | 
    
         
            +
              
         
     | 
| 
      
 519 
     | 
    
         
            +
              def update_tickets_assignee(tickets, new_assignee)
         
     | 
| 
      
 520 
     | 
    
         
            +
                tickets = tickets.split(",").map &:strip
         
     | 
| 
      
 521 
     | 
    
         
            +
                if !tickets.blank?
         
     | 
| 
      
 522 
     | 
    
         
            +
                  ts = tickets.map{|num| 
         
     | 
| 
      
 523 
     | 
    
         
            +
                    prj, number = parse_number(num)
         
     | 
| 
      
 524 
     | 
    
         
            +
                    Unfuzzle::Ticket.find_first_by_project_id_and_number(prj, number) rescue nil 
         
     | 
| 
      
 525 
     | 
    
         
            +
                  }.compact
         
     | 
| 
      
 526 
     | 
    
         
            +
             
         
     | 
| 
      
 527 
     | 
    
         
            +
                  # find person
         
     | 
| 
      
 528 
     | 
    
         
            +
                  ass_ids = find_persons(new_assignee)
         
     | 
| 
      
 529 
     | 
    
         
            +
                  exit 1 if ass_ids.size < 1
         
     | 
| 
      
 530 
     | 
    
         
            +
             
     | 
| 
      
 531 
     | 
    
         
            +
                  person = people[ass_ids.first]
         
     | 
| 
      
 532 
     | 
    
         
            +
             
     | 
| 
      
 533 
     | 
    
         
            +
                  say "Update tickets #{ts.map(&:number) * ','} to assignee #{person}"
         
     | 
| 
      
 534 
     | 
    
         
            +
             
     | 
| 
      
 535 
     | 
    
         
            +
                  ts.each do |t|
         
     | 
| 
      
 536 
     | 
    
         
            +
                    t.assignee_id = ass_ids.first
         
     | 
| 
      
 537 
     | 
    
         
            +
                    t.update
         
     | 
| 
      
 538 
     | 
    
         
            +
                    render_ticket(t)
         
     | 
| 
      
 539 
     | 
    
         
            +
                  end
         
     | 
| 
      
 540 
     | 
    
         
            +
                else
         
     | 
| 
      
 541 
     | 
    
         
            +
                  say "no one tickets"
         
     | 
| 
      
 542 
     | 
    
         
            +
                end
         
     | 
| 
      
 543 
     | 
    
         
            +
              end
         
     | 
| 
      
 544 
     | 
    
         
            +
              
         
     | 
| 
      
 545 
     | 
    
         
            +
              def new_ticket(title, assignee = "", priority = 3)
         
     | 
| 
      
 546 
     | 
    
         
            +
                # find user
         
     | 
| 
      
 547 
     | 
    
         
            +
                ass_id = find_persons(assignee).first
         
     | 
| 
      
 548 
     | 
    
         
            +
             
     | 
| 
      
 549 
     | 
    
         
            +
                prio = priority.blank? ? 3 : priority.to_i
         
     | 
| 
      
 550 
     | 
    
         
            +
             
     | 
| 
      
 551 
     | 
    
         
            +
                t = Unfuzzle::Ticket.new
         
     | 
| 
      
 552 
     | 
    
         
            +
                t.title = enc_cmd(title)
         
     | 
| 
      
 553 
     | 
    
         
            +
                t.assignee_id = ass_id
         
     | 
| 
      
 554 
     | 
    
         
            +
                t.reporter_id = find_persons.first # me
         
     | 
| 
      
 555 
     | 
    
         
            +
                t.priority = prio
         
     | 
| 
      
 556 
     | 
    
         
            +
                t.project_id = default_project_id
         
     | 
| 
      
 557 
     | 
    
         
            +
             
     | 
| 
      
 558 
     | 
    
         
            +
                say "Now enter description"    
         
     | 
| 
      
 559 
     | 
    
         
            +
                t.description = read_text
         
     | 
| 
      
 560 
     | 
    
         
            +
             
     | 
| 
      
 561 
     | 
    
         
            +
                say "Create ticket: ", nil, true
         
     | 
| 
      
 562 
     | 
    
         
            +
                say t.title, nil, true
         
     | 
| 
      
 563 
     | 
    
         
            +
                say t.description, nil, true
         
     | 
| 
      
 564 
     | 
    
         
            +
                say people[t.assignee_id]
         
     | 
| 
      
 565 
     | 
    
         
            +
                say ''
         
     | 
| 
      
 566 
     | 
    
         
            +
             
     | 
| 
      
 567 
     | 
    
         
            +
                t.create
         
     | 
| 
      
 568 
     | 
    
         
            +
                render_ticket(t)
         
     | 
| 
      
 569 
     | 
    
         
            +
              end
         
     | 
| 
      
 570 
     | 
    
         
            +
             
     | 
| 
      
 571 
     | 
    
         
            +
              def add_comment(number)
         
     | 
| 
      
 572 
     | 
    
         
            +
                prj, number = parse_number(number)
         
     | 
| 
      
 573 
     | 
    
         
            +
                t, cms = Unfuzzle::Ticket.find_first_by_project_id_and_number_with_comments(prj, number)
         
     | 
| 
      
 574 
     | 
    
         
            +
                
         
     | 
| 
      
 575 
     | 
    
         
            +
                say "Enter body of comment: ", :red, true
         
     | 
| 
      
 576 
     | 
    
         
            +
                text = read_text
         
     | 
| 
      
 577 
     | 
    
         
            +
                
         
     | 
| 
      
 578 
     | 
    
         
            +
                cm = Unfuzzle::Comment.new
         
     | 
| 
      
 579 
     | 
    
         
            +
                cm.body = text
         
     | 
| 
      
 580 
     | 
    
         
            +
                cm.author_id = me_id
         
     | 
| 
      
 581 
     | 
    
         
            +
                
         
     | 
| 
      
 582 
     | 
    
         
            +
                cm.create(t.project_id, t.id)
         
     | 
| 
      
 583 
     | 
    
         
            +
                
         
     | 
| 
      
 584 
     | 
    
         
            +
                cms += [cm]
         
     | 
| 
      
 585 
     | 
    
         
            +
                
         
     | 
| 
      
 586 
     | 
    
         
            +
                render_ticket(t, cms)
         
     | 
| 
      
 587 
     | 
    
         
            +
              end
         
     | 
| 
      
 588 
     | 
    
         
            +
             
     | 
| 
      
 589 
     | 
    
         
            +
              def add_time(number, hours, comment = "", date = "")
         
     | 
| 
      
 590 
     | 
    
         
            +
                prj, number = parse_number(number)
         
     | 
| 
      
 591 
     | 
    
         
            +
                t, cms = Unfuzzle::Ticket.find_first_by_project_id_and_number_with_comments(prj, number)
         
     | 
| 
      
 592 
     | 
    
         
            +
                
         
     | 
| 
      
 593 
     | 
    
         
            +
                time = Unfuzzle::TimeEntry.new
         
     | 
| 
      
 594 
     | 
    
         
            +
                time.description = enc_cmd(comment)
         
     | 
| 
      
 595 
     | 
    
         
            +
                time.hours = hours
         
     | 
| 
      
 596 
     | 
    
         
            +
                time.ticket_id = t.id
         
     | 
| 
      
 597 
     | 
    
         
            +
                time.date = date.blank? ?  Time.now.strftime("%Y-%m-%d") : date
         
     | 
| 
      
 598 
     | 
    
         
            +
                time.person_id = me_id
         
     | 
| 
      
 599 
     | 
    
         
            +
                
         
     | 
| 
      
 600 
     | 
    
         
            +
                time.create(t.project_id, t.id)
         
     | 
| 
      
 601 
     | 
    
         
            +
             
     | 
| 
      
 602 
     | 
    
         
            +
                times = Unfuzzle::TimeEntry.all_for_ticket(t)
         
     | 
| 
      
 603 
     | 
    
         
            +
                
         
     | 
| 
      
 604 
     | 
    
         
            +
                t.hours = (t.hours.to_f + time.hours.to_f).to_s
         
     | 
| 
      
 605 
     | 
    
         
            +
                render_ticket(t, cms, times)
         
     | 
| 
      
 606 
     | 
    
         
            +
              end
         
     | 
| 
      
 607 
     | 
    
         
            +
             
     | 
| 
      
 608 
     | 
    
         
            +
              def set_current(number)
         
     | 
| 
      
 609 
     | 
    
         
            +
                if cached_projects.keys.include?(number.to_i)
         
     | 
| 
      
 610 
     | 
    
         
            +
                  self.default_project_id = number.to_i
         
     | 
| 
      
 611 
     | 
    
         
            +
                  set_config
         
     | 
| 
      
 612 
     | 
    
         
            +
                  say "set current project to #{number}"
         
     | 
| 
      
 613 
     | 
    
         
            +
                  say ''
         
     | 
| 
      
 614 
     | 
    
         
            +
                  show_projects
         
     | 
| 
      
 615 
     | 
    
         
            +
                elsif projects_aliases.values.include?(number.to_s) # alias?
         
     | 
| 
      
 616 
     | 
    
         
            +
                  self.default_project_id = projects_aliases.detect{|k,v| v == number.to_s}.first rescue self.default_project_id
         
     | 
| 
      
 617 
     | 
    
         
            +
                  set_config
         
     | 
| 
      
 618 
     | 
    
         
            +
                  say "set current project to #{number}"
         
     | 
| 
      
 619 
     | 
    
         
            +
                  say ''
         
     | 
| 
      
 620 
     | 
    
         
            +
                  show_projects      
         
     | 
| 
      
 621 
     | 
    
         
            +
                else
         
     | 
| 
      
 622 
     | 
    
         
            +
                  say "bad number #{number}, should be in #{cached_projects.keys.inspect}"
         
     | 
| 
      
 623 
     | 
    
         
            +
                end
         
     | 
| 
      
 624 
     | 
    
         
            +
              end
         
     | 
| 
      
 625 
     | 
    
         
            +
             
     | 
| 
      
 626 
     | 
    
         
            +
              def set_alias(number, _alias)
         
     | 
| 
      
 627 
     | 
    
         
            +
                if cached_projects.keys.include?(number.to_i)
         
     | 
| 
      
 628 
     | 
    
         
            +
                  self.projects_aliases[number.to_i] = _alias
         
     | 
| 
      
 629 
     | 
    
         
            +
                  set_config
         
     | 
| 
      
 630 
     | 
    
         
            +
                  say "set project #{number} alias to #{_alias}"
         
     | 
| 
      
 631 
     | 
    
         
            +
                  say
         
     | 
| 
      
 632 
     | 
    
         
            +
                  show_projects
         
     | 
| 
      
 633 
     | 
    
         
            +
                else
         
     | 
| 
      
 634 
     | 
    
         
            +
                  say "bad number #{number}, should be in #{cached_projects.keys.inspect}"
         
     | 
| 
      
 635 
     | 
    
         
            +
                end
         
     | 
| 
      
 636 
     | 
    
         
            +
              end
         
     | 
| 
      
 637 
     | 
    
         
            +
             
     | 
| 
      
 638 
     | 
    
         
            +
              def notify_periodic(params = '')
         
     | 
| 
      
 639 
     | 
    
         
            +
                t = Unfuzzle::Ticket.all_by_dinamic_report(nil, true).map(&:to_hash)
         
     | 
| 
      
 640 
     | 
    
         
            +
             
     | 
| 
      
 641 
     | 
    
         
            +
                # options
         
     | 
| 
      
 642 
     | 
    
         
            +
                show_new = true # показывать новые созданные тикеты
         
     | 
| 
      
 643 
     | 
    
         
            +
                show_statuses = true # показывать изменения статусов тикетов
         
     | 
| 
      
 644 
     | 
    
         
            +
                show_closed = true # показывать какие были закрыты
         
     | 
| 
      
 645 
     | 
    
         
            +
                all_tickets = true # учитывать ли все тикеты (не только привязанные ко мне)
         
     | 
| 
      
 646 
     | 
    
         
            +
                my_tickets = true # делать нотификацию только тикетов которые созданы мной или на меня
         
     | 
| 
      
 647 
     | 
    
         
            +
                all_projects = true # тикеты брать со всех проектов или с текущего
         
     | 
| 
      
 648 
     | 
    
         
            +
             
     | 
| 
      
 649 
     | 
    
         
            +
                params = [show_new,show_statuses,show_closed,all_tickets,my_tickets,all_projects]
         
     | 
| 
      
 650 
     | 
    
         
            +
             
     | 
| 
      
 651 
     | 
    
         
            +
                t = Unfuzzle::Ticket.all_by_dinamic_report(all_projects ? nil : [default_project_id], !all_tickets).map(&:to_hash)
         
     | 
| 
      
 652 
     | 
    
         
            +
             
     | 
| 
      
 653 
     | 
    
         
            +
                cached = cached_tickets(params)
         
     | 
| 
      
 654 
     | 
    
         
            +
             
     | 
| 
      
 655 
     | 
    
         
            +
                if cached.size == 0
         
     | 
| 
      
 656 
     | 
    
         
            +
                  say "first time: caching ..."
         
     | 
| 
      
 657 
     | 
    
         
            +
                  set_cached_tickets(t, params)
         
     | 
| 
      
 658 
     | 
    
         
            +
                  return
         
     | 
| 
      
 659 
     | 
    
         
            +
                end
         
     | 
| 
      
 660 
     | 
    
         
            +
             
     | 
| 
      
 661 
     | 
    
         
            +
                if my_tickets
         
     | 
| 
      
 662 
     | 
    
         
            +
                  cached = cached.select{|c| c['assignee-id'] == me_id || c['reporter-id'] == me_id }
         
     | 
| 
      
 663 
     | 
    
         
            +
                  t = t.select{|c| c['assignee-id'] == me_id || c['reporter-id'] == me_id }
         
     | 
| 
      
 664 
     | 
    
         
            +
                end
         
     | 
| 
      
 665 
     | 
    
         
            +
             
     | 
| 
      
 666 
     | 
    
         
            +
                cached_h = {}
         
     | 
| 
      
 667 
     | 
    
         
            +
                t_h = {}
         
     | 
| 
      
 668 
     | 
    
         
            +
             
     | 
| 
      
 669 
     | 
    
         
            +
                # into hash
         
     | 
| 
      
 670 
     | 
    
         
            +
                cached.each{|c| k = [c['project-id'], c['number']]; cached_h[k] = c }
         
     | 
| 
      
 671 
     | 
    
         
            +
                t.each{|c| k = [c['project-id'], c['number']]; t_h[k] = c }
         
     | 
| 
      
 672 
     | 
    
         
            +
             
     | 
| 
      
 673 
     | 
    
         
            +
             
     | 
| 
      
 674 
     | 
    
         
            +
                message = []
         
     | 
| 
      
 675 
     | 
    
         
            +
             
     | 
| 
      
 676 
     | 
    
         
            +
                # new tickets
         
     | 
| 
      
 677 
     | 
    
         
            +
                if show_new && (t_h.keys - cached_h.keys).present?
         
     | 
| 
      
 678 
     | 
    
         
            +
                  (t_h.keys - cached_h.keys).each{|key| message << "New ticket #{number_with_a_by_params(key[0], key[1])}: '#{t_h[key]['summary']}'"}
         
     | 
| 
      
 679 
     | 
    
         
            +
                end
         
     | 
| 
      
 680 
     | 
    
         
            +
             
     | 
| 
      
 681 
     | 
    
         
            +
                # change status tickets
         
     | 
| 
      
 682 
     | 
    
         
            +
                chanched = []
         
     | 
| 
      
 683 
     | 
    
         
            +
                t_h.each{|key, value| chanched << key if cached_h[key] && value['status'] != cached_h[key]['status']}
         
     | 
| 
      
 684 
     | 
    
         
            +
             
     | 
| 
      
 685 
     | 
    
         
            +
                if show_statuses && chanched.present?
         
     | 
| 
      
 686 
     | 
    
         
            +
                  chanched.each{|key| message << "#{number_with_a_by_params(key[0], key[1])}: '#{t_h[key]['summary']}' =>  #{t_h[key]['status']}"}
         
     | 
| 
      
 687 
     | 
    
         
            +
                end
         
     | 
| 
      
 688 
     | 
    
         
            +
             
     | 
| 
      
 689 
     | 
    
         
            +
                # closed tickets
         
     | 
| 
      
 690 
     | 
    
         
            +
                if show_closed && (cached_h.keys - t_h.keys).present?
         
     | 
| 
      
 691 
     | 
    
         
            +
                  (cached_h.keys - t_h.keys).each{|key| message << "Closed ticket #{number_with_a_by_params(key[0], key[1])}: '#{cached_h[key]['summary']}'"}
         
     | 
| 
      
 692 
     | 
    
         
            +
                end
         
     | 
| 
      
 693 
     | 
    
         
            +
             
     | 
| 
      
 694 
     | 
    
         
            +
                message = message * "\n"
         
     | 
| 
      
 695 
     | 
    
         
            +
                notify_message(message)
         
     | 
| 
      
 696 
     | 
    
         
            +
             
     | 
| 
      
 697 
     | 
    
         
            +
                set_cached_tickets(t, params)
         
     | 
| 
      
 698 
     | 
    
         
            +
              end
         
     | 
| 
      
 699 
     | 
    
         
            +
             
     | 
| 
      
 700 
     | 
    
         
            +
              def notify_message(message)
         
     | 
| 
      
 701 
     | 
    
         
            +
                return if message.empty?
         
     | 
| 
      
 702 
     | 
    
         
            +
                if WIN
         
     | 
| 
      
 703 
     | 
    
         
            +
                  say message
         
     | 
| 
      
 704 
     | 
    
         
            +
             
     | 
| 
      
 705 
     | 
    
         
            +
                elsif MAC
         
     | 
| 
      
 706 
     | 
    
         
            +
                  system("growlnotify --name 'confuddle' -s -m '#{message}'")
         
     | 
| 
      
 707 
     | 
    
         
            +
             
     | 
| 
      
 708 
     | 
    
         
            +
                else
         
     | 
| 
      
 709 
     | 
    
         
            +
                  system("dbus-launch notify-send -t 5000 \"Unfuddle notification\" \"#{message}\"")
         
     | 
| 
      
 710 
     | 
    
         
            +
                end
         
     | 
| 
      
 711 
     | 
    
         
            +
              end
         
     | 
| 
      
 712 
     | 
    
         
            +
             
     | 
| 
      
 713 
     | 
    
         
            +
            public
         
     | 
| 
      
 714 
     | 
    
         
            +
             
     | 
| 
      
 715 
     | 
    
         
            +
              desc "projects", "show all projects for your account"
         
     | 
| 
      
 716 
     | 
    
         
            +
              def projects
         
     | 
| 
      
 717 
     | 
    
         
            +
                show_projects
         
     | 
| 
      
 718 
     | 
    
         
            +
              end
         
     | 
| 
      
 719 
     | 
    
         
            +
             
     | 
| 
      
 720 
     | 
    
         
            +
              desc "all [REGEXP]", "show all tickets for current project"
         
     | 
| 
      
 721 
     | 
    
         
            +
              def all(regexp = "")
         
     | 
| 
      
 722 
     | 
    
         
            +
                show_all_active_tickets(regexp)
         
     | 
| 
      
 723 
     | 
    
         
            +
              end
         
     | 
| 
      
 724 
     | 
    
         
            +
             
     | 
| 
      
 725 
     | 
    
         
            +
              desc "my", "show tickets assignee to me for current project"
         
     | 
| 
      
 726 
     | 
    
         
            +
              def my
         
     | 
| 
      
 727 
     | 
    
         
            +
                show_my_tickets
         
     | 
| 
      
 728 
     | 
    
         
            +
              end
         
     | 
| 
      
 729 
     | 
    
         
            +
             
     | 
| 
      
 730 
     | 
    
         
            +
              desc "alla [REGEXP]", "show all (in all projects) tickets"
         
     | 
| 
      
 731 
     | 
    
         
            +
              def alla(regexp = "")
         
     | 
| 
      
 732 
     | 
    
         
            +
                show_all_active_tickets(regexp, true)
         
     | 
| 
      
 733 
     | 
    
         
            +
              end
         
     | 
| 
      
 734 
     | 
    
         
            +
             
     | 
| 
      
 735 
     | 
    
         
            +
              desc "mya", "show tickets (in all projects) assignee to me"
         
     | 
| 
      
 736 
     | 
    
         
            +
              def mya
         
     | 
| 
      
 737 
     | 
    
         
            +
                show_my_tickets true
         
     | 
| 
      
 738 
     | 
    
         
            +
              end
         
     | 
| 
      
 739 
     | 
    
         
            +
             
     | 
| 
      
 740 
     | 
    
         
            +
              desc "show NUMBER [t]", "show ticket by number, [t] - show TimeEntries"
         
     | 
| 
      
 741 
     | 
    
         
            +
              def show(number, opt = "")
         
     | 
| 
      
 742 
     | 
    
         
            +
                show_ticket(number, opt)
         
     | 
| 
      
 743 
     | 
    
         
            +
              end
         
     | 
| 
      
 744 
     | 
    
         
            +
             
     | 
| 
      
 745 
     | 
    
         
            +
              # Upd
         
     | 
| 
      
 746 
     | 
    
         
            +
              desc "upd TICKETS NEW_STATUS", "update tickets statuses"
         
     | 
| 
      
 747 
     | 
    
         
            +
              def upd(tickets, new_status)
         
     | 
| 
      
 748 
     | 
    
         
            +
                update_tickets(tickets, new_status)
         
     | 
| 
      
 749 
     | 
    
         
            +
              end
         
     | 
| 
      
 750 
     | 
    
         
            +
             
     | 
| 
      
 751 
     | 
    
         
            +
              desc "assi TICKETS [NEW_ASSIGNEE]", "update tickets assingee"
         
     | 
| 
      
 752 
     | 
    
         
            +
              def assi(tickets, new_assignee = "")
         
     | 
| 
      
 753 
     | 
    
         
            +
                update_tickets_assignee(tickets, new_assignee)
         
     | 
| 
      
 754 
     | 
    
         
            +
              end
         
     | 
| 
      
 755 
     | 
    
         
            +
             
     | 
| 
      
 756 
     | 
    
         
            +
              desc "clear", "clear caches"
         
     | 
| 
      
 757 
     | 
    
         
            +
              def clear
         
     | 
| 
      
 758 
     | 
    
         
            +
                require 'fileutils'
         
     | 
| 
      
 759 
     | 
    
         
            +
                FileUtils.rm(CACHED_PEOPLE) rescue nil
         
     | 
| 
      
 760 
     | 
    
         
            +
                FileUtils.rm(CACHED_PROJECTS) rescue nil
         
     | 
| 
      
 761 
     | 
    
         
            +
                say "cached cleared"
         
     | 
| 
      
 762 
     | 
    
         
            +
              end
         
     | 
| 
      
 763 
     | 
    
         
            +
             
     | 
| 
      
 764 
     | 
    
         
            +
              # Times
         
     | 
| 
      
 765 
     | 
    
         
            +
              desc "tm PERIOD", "show my times report (PERIOD = [tm lm tw lw y [0-9]+])"
         
     | 
| 
      
 766 
     | 
    
         
            +
              def tm(period = 0, sum_only='')
         
     | 
| 
      
 767 
     | 
    
         
            +
                times_report(true, period, sum_only == 's')
         
     | 
| 
      
 768 
     | 
    
         
            +
              end
         
     | 
| 
      
 769 
     | 
    
         
            +
             
     | 
| 
      
 770 
     | 
    
         
            +
              desc "t PERIOD", "show all times report (PERIOD = [tm lm tw lw y [0-9]+])"
         
     | 
| 
      
 771 
     | 
    
         
            +
              def t(period = 0, sum_only='')
         
     | 
| 
      
 772 
     | 
    
         
            +
                times_report(false, period, sum_only == 's')
         
     | 
| 
      
 773 
     | 
    
         
            +
              end
         
     | 
| 
      
 774 
     | 
    
         
            +
             
     | 
| 
      
 775 
     | 
    
         
            +
              desc "atm PERIOD", "show my times report for account (PERIOD = [tm lm tw lw y [0-9]+])"
         
     | 
| 
      
 776 
     | 
    
         
            +
              def atm(period = 0, sum_only='')
         
     | 
| 
      
 777 
     | 
    
         
            +
                all_times_report(true, period, sum_only == 's')
         
     | 
| 
      
 778 
     | 
    
         
            +
              end
         
     | 
| 
      
 779 
     | 
    
         
            +
             
     | 
| 
      
 780 
     | 
    
         
            +
              desc "at PERIOD", "show all times report for account (PERIOD = [tm lm tw lw y [0-9]+])"
         
     | 
| 
      
 781 
     | 
    
         
            +
              def at(period = 0, sum_only='')
         
     | 
| 
      
 782 
     | 
    
         
            +
                all_times_report(false, period, sum_only == 's')
         
     | 
| 
      
 783 
     | 
    
         
            +
              end
         
     | 
| 
      
 784 
     | 
    
         
            +
             
     | 
| 
      
 785 
     | 
    
         
            +
              # Add
         
     | 
| 
      
 786 
     | 
    
         
            +
              desc "addt NUMBER HOURS COMMENT [DATE]", "add time"
         
     | 
| 
      
 787 
     | 
    
         
            +
              def addt(ticket_number, hours, comment, date = nil)
         
     | 
| 
      
 788 
     | 
    
         
            +
                add_time(ticket_number, hours, comment, date)
         
     | 
| 
      
 789 
     | 
    
         
            +
              end
         
     | 
| 
      
 790 
     | 
    
         
            +
             
     | 
| 
      
 791 
     | 
    
         
            +
              desc "addcm NUMBER", "add ticket comment"
         
     | 
| 
      
 792 
     | 
    
         
            +
              def addcm(ticket_number)
         
     | 
| 
      
 793 
     | 
    
         
            +
                add_comment(ticket_number)
         
     | 
| 
      
 794 
     | 
    
         
            +
              end
         
     | 
| 
      
 795 
     | 
    
         
            +
             
     | 
| 
      
 796 
     | 
    
         
            +
              desc "new TITLE [ASSIGNEE] [PRIO]", "create ticket"
         
     | 
| 
      
 797 
     | 
    
         
            +
              def new(title, assignee = "", priority = 3)
         
     | 
| 
      
 798 
     | 
    
         
            +
                new_ticket(title, assignee, priority)
         
     | 
| 
      
 799 
     | 
    
         
            +
              end
         
     | 
| 
      
 800 
     | 
    
         
            +
             
     | 
| 
      
 801 
     | 
    
         
            +
              desc "curr ID_OR_ALIAS", "set current project id"
         
     | 
| 
      
 802 
     | 
    
         
            +
              def curr(current)
         
     | 
| 
      
 803 
     | 
    
         
            +
                set_current(current)
         
     | 
| 
      
 804 
     | 
    
         
            +
              end
         
     | 
| 
      
 805 
     | 
    
         
            +
             
     | 
| 
      
 806 
     | 
    
         
            +
              desc "alias PROJECT_ID ALIAS", "set project alias"
         
     | 
| 
      
 807 
     | 
    
         
            +
              def alias(project_id, _alias)
         
     | 
| 
      
 808 
     | 
    
         
            +
                set_alias(project_id, _alias)
         
     | 
| 
      
 809 
     | 
    
         
            +
              end
         
     | 
| 
      
 810 
     | 
    
         
            +
             
     | 
| 
      
 811 
     | 
    
         
            +
              desc "op TICKET_ID", "Open selected ticked from current project in browser"
         
     | 
| 
      
 812 
     | 
    
         
            +
              def op(ticket_id)
         
     | 
| 
      
 813 
     | 
    
         
            +
                open_ticket_in_browser(ticket_id)
         
     | 
| 
      
 814 
     | 
    
         
            +
              end
         
     | 
| 
      
 815 
     | 
    
         
            +
             
     | 
| 
      
 816 
     | 
    
         
            +
              desc "notify PARAMS", "Notify about changes with tickets by Gnome-Notify, PARAMS='status,comments'"
         
     | 
| 
      
 817 
     | 
    
         
            +
              def notify(params = '')
         
     | 
| 
      
 818 
     | 
    
         
            +
                notify_periodic params
         
     | 
| 
      
 819 
     | 
    
         
            +
              end
         
     | 
| 
      
 820 
     | 
    
         
            +
              
         
     | 
| 
      
 821 
     | 
    
         
            +
              desc "install", "copy sample config into home"
         
     | 
| 
      
 822 
     | 
    
         
            +
              def install
         
     | 
| 
      
 823 
     | 
    
         
            +
                require 'fileutils'
         
     | 
| 
      
 824 
     | 
    
         
            +
                file = File.expand_path(File.join(File.dirname(__FILE__), %w(.. .passwd_to_unfuddle.example.yml) ))
         
     | 
| 
      
 825 
     | 
    
         
            +
                FileUtils.cp(file, PASS_FILE)
         
     | 
| 
      
 826 
     | 
    
         
            +
                say("Config copyed!", :green)
         
     | 
| 
      
 827 
     | 
    
         
            +
                say("Edit file #{PASS_FILE}!", :red)
         
     | 
| 
      
 828 
     | 
    
         
            +
              end
         
     | 
| 
      
 829 
     | 
    
         
            +
             
     | 
| 
      
 830 
     | 
    
         
            +
              default_task(:my) # by default
         
     | 
| 
      
 831 
     | 
    
         
            +
            end
         
     | 
| 
      
 832 
     | 
    
         
            +
             
     | 
| 
      
 833 
     | 
    
         
            +
            Unfuddle.start
         
     |