Class: Checkoff::Tasks
- Inherits:
-
Object
- Object
- Checkoff::Tasks
- Includes:
- Logging
- Defined in:
- lib/checkoff/tasks.rb
Overview
Pull tasks from Asana
Constant Summary collapse
- MINUTE =
60- HOUR =
MINUTE * 60
- DAY =
24 * HOUR
- REALLY_LONG_CACHE_TIME =
MINUTE * 30
- LONG_CACHE_TIME =
MINUTE * 15
- SHORT_CACHE_TIME =
MINUTE * 5
Instance Method Summary collapse
-
#add_task(name, workspace_gid: @workspaces.default_workspace_gid, assignee_gid: default_assignee_gid) ⇒ Asana::Resources::Task
Add a task.
- #all_dependent_tasks(task, extra_task_fields: []) ⇒ Array<Hash>
- #as_cache_key ⇒ Hash
- #date_or_time_field_by_name(task, field_name) ⇒ Date, ...
-
#gid_for_task(workspace_name, project_name, section_name, task_name) ⇒ String?
@sg-ignore.
- #h_to_task(task_data) ⇒ Asana::Resources::Task
- #in_period?(task, field_name, period) ⇒ Boolean
-
#in_portfolio_more_than_once?(task, portfolio_name, workspace_name: @workspaces.default_workspace.name) ⇒ Boolean
True if the task is in a project which is in the given portfolio.
-
#in_portfolio_named?(task, portfolio_name, workspace_name: @workspaces.default_workspace.name) ⇒ Boolean
True if the task is in a project which is in the given portfolio.
-
#incomplete_dependencies?(task) ⇒ Boolean
True if any of the task’s dependencies are marked incomplete.
-
#initialize(config: Checkoff::Internal::ConfigLoader.load(:asana), client: Checkoff::Clients.new(config: config).client, workspaces: Checkoff::Workspaces.new(config: config, client: client), sections: Checkoff::Sections.new(config: config, client: client), portfolios: Checkoff::Portfolios.new(config: config, client: client), custom_fields: Checkoff::CustomFields.new(config: config, client: client), time_class: Time, date_class: Date, asana_task: Asana::Resources::Task) ⇒ Tasks
constructor
A new instance of Tasks.
-
#task(workspace_name, project_name, task_name, section_name: :unspecified, only_uncompleted: true, extra_fields: []) ⇒ Asana::Resources::Task?
Pull a specific task by name.
-
#task_by_gid(task_gid, extra_fields: [], only_uncompleted: true) ⇒ Asana::Resources::Task?
Pull a specific task by GID.
-
#task_ready?(task, period: :now_or_before, ignore_dependencies: false) ⇒ Boolean
Indicates a task is ready for a person to work on it.
-
#task_to_h(task) ⇒ Hash
Builds on the standard API representation of an Asana task with some convenience keys:.
-
#url_of_task(task) ⇒ String
Return user-accessible URL for a task.
Methods included from Logging
#debug, #error, #finer, #info, #logger, #warn
Constructor Details
#initialize(config: Checkoff::Internal::ConfigLoader.load(:asana), client: Checkoff::Clients.new(config: config).client, workspaces: Checkoff::Workspaces.new(config: config, client: client), sections: Checkoff::Sections.new(config: config, client: client), portfolios: Checkoff::Portfolios.new(config: config, client: client), custom_fields: Checkoff::CustomFields.new(config: config, client: client), time_class: Time, date_class: Date, asana_task: Asana::Resources::Task) ⇒ Tasks
Returns a new instance of Tasks.
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/checkoff/tasks.rb', line 39 def initialize(config: Checkoff::Internal::ConfigLoader.load(:asana), client: Checkoff::Clients.new(config: config).client, workspaces: Checkoff::Workspaces.new(config: config, client: client), sections: Checkoff::Sections.new(config: config, client: client), portfolios: Checkoff::Portfolios.new(config: config, client: client), custom_fields: Checkoff::CustomFields.new(config: config, client: client), time_class: Time, date_class: Date, asana_task: Asana::Resources::Task) @config = config @sections = sections @time_class = time_class @date_class = date_class @asana_task = asana_task @client = client @portfolios = portfolios @custom_fields = custom_fields @workspaces = workspaces @timing = Checkoff::Timing.new(today_getter: date_class, now_getter: time_class) end |
Instance Method Details
#add_task(name, workspace_gid: @workspaces.default_workspace_gid, assignee_gid: default_assignee_gid) ⇒ Asana::Resources::Task
Add a task
179 180 181 182 183 184 185 |
# File 'lib/checkoff/tasks.rb', line 179 def add_task(name, workspace_gid: @workspaces.default_workspace_gid, assignee_gid: default_assignee_gid) @asana_task.create(client, assignee: assignee_gid, workspace: workspace_gid, name: name) end |
#all_dependent_tasks(task, extra_task_fields: []) ⇒ Array<Hash>
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 |
# File 'lib/checkoff/tasks.rb', line 229 def all_dependent_tasks(task, extra_task_fields: []) dependent_tasks = [] # See note above - same applies as does in @dependencies # # @type [Array<Hash>] dependents = task.instance_variable_get(:@dependents) || [] dependents.each do |dependent_task_hash_or_obj| # seems like if we ever .inspect the task, it stashes the task # object instead of the hash. Try to avoid this - but maybe we # need to convert if it does happen. raise 'Found dependent task object!' if dependent_task_hash_or_obj.is_a?(Asana::Resources::Task) dependent_task_hash = dependent_task_hash_or_obj dependent_task = task_by_gid(dependent_task_hash.fetch('gid'), only_uncompleted: true, extra_fields: ['dependents'] + extra_task_fields) debug { "#{task.name} has dependent task #{dependent_task.name}" } next if dependent_task.nil? dependent_tasks << dependent_task dependent_tasks += all_dependent_tasks(dependent_task, extra_task_fields: extra_task_fields) end dependent_tasks end |
#as_cache_key ⇒ Hash
320 321 322 |
# File 'lib/checkoff/tasks.rb', line 320 def as_cache_key {} end |
#date_or_time_field_by_name(task, field_name) ⇒ Date, ...
102 103 104 |
# File 'lib/checkoff/tasks.rb', line 102 def date_or_time_field_by_name(task, field_name) task_timing.date_or_time_field_by_name(task, field_name) end |
#gid_for_task(workspace_name, project_name, section_name, task_name) ⇒ String?
@sg-ignore
138 139 140 141 142 143 144 145 146 |
# File 'lib/checkoff/tasks.rb', line 138 def gid_for_task(workspace_name, project_name, section_name, task_name) # @sg-ignore t = tasks(workspace_name, project_name, section_name: section_name, only_uncompleted: false) task_for_gid = t.find { |task| task.name == task_name } task_for_gid&.gid end |
#h_to_task(task_data) ⇒ Asana::Resources::Task
277 278 279 |
# File 'lib/checkoff/tasks.rb', line 277 def h_to_task(task_data) task_hashes.h_to_task(task_data, client: client) end |
#in_period?(task, field_name, period) ⇒ Boolean
86 87 88 89 90 91 |
# File 'lib/checkoff/tasks.rb', line 86 def in_period?(task, field_name, period) # @type [Date,Time,nil] task_date_or_time = task_timing.date_or_time_field_by_name(task, field_name) timing.in_period?(task_date_or_time, period) end |
#in_portfolio_more_than_once?(task, portfolio_name, workspace_name: @workspaces.default_workspace.name) ⇒ Boolean
True if the task is in a project which is in the given portfolio
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 |
# File 'lib/checkoff/tasks.rb', line 303 def in_portfolio_more_than_once?(task, portfolio_name, workspace_name: @workspaces.default_workspace.name) portfolio_projects = @portfolios.projects_in_portfolio(workspace_name, portfolio_name) portfolio_project_gids = portfolio_projects.map(&:gid) seen = false task.memberships.each do |membership| project_gid = membership.fetch('project').fetch('gid') next unless portfolio_project_gids.include?(project_gid) return true if seen seen = true end false end |
#in_portfolio_named?(task, portfolio_name, workspace_name: @workspaces.default_workspace.name) ⇒ Boolean
True if the task is in a project which is in the given portfolio
286 287 288 289 290 291 292 293 294 295 296 |
# File 'lib/checkoff/tasks.rb', line 286 def in_portfolio_named?(task, portfolio_name, workspace_name: @workspaces.default_workspace.name) portfolio_projects = @portfolios.projects_in_portfolio(workspace_name, portfolio_name) task.memberships.any? do |membership| project_gid = membership.fetch('project').fetch('gid') portfolio_projects.any? do |portfolio_project| portfolio_project.gid == project_gid end end end |
#incomplete_dependencies?(task) ⇒ Boolean
True if any of the task’s dependencies are marked incomplete
Include ‘dependencies.gid’ in extra_fields of task passed in.
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
# File 'lib/checkoff/tasks.rb', line 201 def incomplete_dependencies?(task) # Avoid a redundant fetch. Unfortunately, Ruby SDK allows # dependencies to be fetched along with other attributes--but # then doesn't use it and does another HTTP GET! At least this # way we can skip the extra HTTP GET in the common case when # there are no dependencies. # # https://github.com/Asana/ruby-asana/issues/125 # @sg-ignore # @type [Enumerable<Asana::Resources::Task>, nil] dependencies = task.instance_variable_get(:@dependencies) || [] dependencies.any? do |parent_task_info| # the real bummer though is that asana doesn't let you fetch # the completion status of dependencies, so we need to do this # regardless: parent_task_gid = parent_task_info.fetch('gid') parent_task = task_by_gid(parent_task_gid, only_uncompleted: false) parent_task.completed_at.nil? end end |
#task(workspace_name, project_name, task_name, section_name: :unspecified, only_uncompleted: true, extra_fields: []) ⇒ Asana::Resources::Task?
Pull a specific task by name
@sg-ignore
116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/checkoff/tasks.rb', line 116 def task(workspace_name, project_name, task_name, section_name: :unspecified, only_uncompleted: true, extra_fields: []) thread_local = Checkoff::Internal::ThreadLocal.new task_gid = thread_local.with_thread_local_variable(:suppress_asana_webhook_watch_creation, true) do gid_for_task(workspace_name, project_name, section_name, task_name) end return nil if task_gid.nil? task_by_gid(task_gid, only_uncompleted: only_uncompleted, extra_fields: extra_fields) end |
#task_by_gid(task_gid, extra_fields: [], only_uncompleted: true) ⇒ Asana::Resources::Task?
Pull a specific task by GID
156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/checkoff/tasks.rb', line 156 def task_by_gid(task_gid, extra_fields: [], only_uncompleted: true) # @type [Hash{Symbol => Object}] = projects.(extra_fields: extra_fields, only_uncompleted: only_uncompleted) # @type [Hash] = .fetch(:options, {}) [:completed_since] = [:completed_since] unless [:completed_since].nil? client.tasks.find_by_id(task_gid, options: ) rescue Asana::Errors::NotFound => e debug e nil end |
#task_ready?(task, period: :now_or_before, ignore_dependencies: false) ⇒ Boolean
Indicates a task is ready for a person to work on it. This is subtly different than what is used by Asana to mark a date as red/green! A task is ready if it is not dependent on an incomplete task and one of these is true:
-
start is null and due on is today
-
start is null and due at is before now
-
start on is today
-
start at is before now
77 78 79 80 81 |
# File 'lib/checkoff/tasks.rb', line 77 def task_ready?(task, period: :now_or_before, ignore_dependencies: false) return false if !ignore_dependencies && incomplete_dependencies?(task) in_period?(task, :ready, period) end |
#task_to_h(task) ⇒ Hash
Builds on the standard API representation of an Asana task with some convenience keys:
<regular keys from API response> + unwrapped:
membership_by_section_gid: Hash<String, Hash (membership)>
membership_by_project_gid: Hash<String, Hash (membership)>
membership_by_project_name: Hash<String, Hash (membership)>
task: String (name)
270 271 272 |
# File 'lib/checkoff/tasks.rb', line 270 def task_to_h(task) task_hashes.task_to_h(task) end |
#url_of_task(task) ⇒ String
Return user-accessible URL for a task
192 193 194 |
# File 'lib/checkoff/tasks.rb', line 192 def url_of_task(task) "https://app.asana.com/0/0/#{task.gid}/f" end |