Class: PlanMyStuff::BaseProjectItem
- Inherits:
-
ApplicationRecord
- Object
- ApplicationRecord
- PlanMyStuff::BaseProjectItem
- Defined in:
- lib/plan_my_stuff/base_project_item.rb
Overview
Shared base for GitHub Projects V2 item wrappers. Holds attribute definitions, generic build/create/move/update/delete/assign machinery, and core instance helpers.
Not meant to be used directly. Concrete subclasses (ProjectItem, TestingProjectItem) add their own domain-specific methods.
Class methods:
BaseProjectItem.create!(issue) -- add existing issue
BaseProjectItem.create!(title, draft: true, body: "...") -- create draft item
BaseProjectItem.move_item(item_id:, status:)
BaseProjectItem.assign(item_id:, assignee:)
Instance methods:
item.move_to!("Done")
item.assign!("octocat")
Direct Known Subclasses
Instance Attribute Summary
Attributes inherited from ApplicationRecord
Class Method Summary collapse
-
.assign(number:, content_node_id:, assignees:, draft: false, repo: nil) ⇒ void
Assigns users to a project item.
-
.build(item_hash, project:) ⇒ PlanMyStuff::BaseProjectItem
Builds a persisted item from parsed item data.
-
.create!(issue_or_title, draft: false, body: nil, project_number: nil, user: nil) ⇒ PlanMyStuff::BaseProjectItem
Creates a project item by adding an existing issue or creating a draft.
-
.delete_item(item_id:, project_number: nil) ⇒ String
Deletes a project item from its parent project.
-
.move_item(item_id:, status:, project_number: nil) ⇒ Hash
Moves a project item to a new status column.
-
.update_date_field!(item_id:, field_name:, date:, project_number: nil) ⇒ Hash
Updates a date custom field on a project item.
-
.update_field!(item_id:, field_name:, value:, project_number: nil) ⇒ Hash
Updates a text custom field on a project item.
-
.update_single_select_field!(item_id:, field_name:, value:, project_number: nil) ⇒ Hash
Updates a single-select custom field on a project item.
Instance Method Summary collapse
-
#as_json(options = {}) ⇒ Hash
Serializes the project item to a JSON-safe hash, excluding the back-reference to the parent project to prevent recursive serialization cycles.
-
#assign!(assignees, user: nil) ⇒ void
Assigns users to this item on its parent project.
-
#body ⇒ String?
User-visible body (metadata comment stripped).
-
#content_node_id ⇒ String?
Node ID of the underlying content (Issue, PR, or DraftIssue).
-
#destroy!(user: nil) ⇒ String?
Deletes this item from its parent project.
- #draft? ⇒ Boolean
- #field_values ⇒ Hash
-
#id ⇒ String?
GitHub node ID (e.g. “PVTI_…”).
- #issue ⇒ PlanMyStuff::Issue?
- #issue=(val) ⇒ void
-
#metadata ⇒ PlanMyStuff::ProjectItemMetadata
Parsed metadata.
-
#move_to!(status, user: nil) ⇒ Hash
Moves this item to a new status column on its parent project.
- #number ⇒ Integer?
- #project ⇒ PlanMyStuff::BaseProject?
-
#raw_body ⇒ String?
Full body as stored on GitHub (draft items only).
- #repo ⇒ PlanMyStuff::Repo?
- #state ⇒ String?
- #status ⇒ String?
- #title ⇒ String?
-
#type ⇒ String?
GitHub item type (e.g. “DRAFT_ISSUE”, “ISSUE”, “PULL_REQUEST”).
-
#update_field!(field_name, value) ⇒ Hash
Updates a text custom field on this item.
- #url ⇒ String?
Methods inherited from ApplicationRecord
#destroyed?, #initialize, #new_record?, #persisted?, read_field
Constructor Details
This class inherits a constructor from PlanMyStuff::ApplicationRecord
Class Method Details
.assign(number:, content_node_id:, assignees:, draft: false, repo: nil) ⇒ void
This method returns an undefined value.
Assigns users to a project item. Issues/PRs use REST via Issue.update!, drafts use GraphQL.
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 |
# File 'lib/plan_my_stuff/base_project_item.rb', line 253 def assign(number:, content_node_id:, assignees:, draft: false, repo: nil) if draft client = PlanMyStuff.client user_ids = assignees.map do |assignee| user_data = client.graphql( PlanMyStuff::GraphQL::Queries::USER_NODE_ID, variables: { login: assignee }, ) user_id = user_data.dig(:user, :id) raise(APIError, "GitHub user not found: #{assignee}") if user_id.nil? user_id end client.graphql( PlanMyStuff::GraphQL::Queries::ASSIGN_DRAFT, variables: { draftIssueId: content_node_id, assigneeIds: user_ids }, ) else Issue.update!(number: number, repo: repo, assignees: assignees) end end |
.build(item_hash, project:) ⇒ PlanMyStuff::BaseProjectItem
Builds a persisted item from parsed item data.
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/plan_my_stuff/base_project_item.rb', line 61 def build(item_hash, project:) raw_body_val = item_hash[:body] item = new( id: item_hash[:id], type: item_hash[:type], content_node_id: item_hash[:content_node_id], title: item_hash[:title], raw_body: raw_body_val, number: item_hash[:number], url: item_hash[:url], repo: item_hash[:repo], state: item_hash[:state], status: item_hash[:status], field_values: item_hash[:field_values] || {}, project: project, ) if raw_body_val parsed = PlanMyStuff::MetadataParser.parse(raw_body_val) item. = PlanMyStuff::ProjectItemMetadata.from_hash(parsed[:metadata] || {}) item.body = parsed[:body] end item.instance_variable_set(:@github_response, item_hash[:github_response]) item.__send__(:persisted!) item end |
.create!(issue_or_title, draft: false, body: nil, project_number: nil, user: nil) ⇒ PlanMyStuff::BaseProjectItem
Creates a project item by adding an existing issue or creating a draft.
99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/plan_my_stuff/base_project_item.rb', line 99 def create!(issue_or_title, draft: false, body: nil, project_number: nil, user: nil) item = if draft add_draft_item(title: issue_or_title, body: body, project_number: project_number) else add_item(issue: issue_or_title, project_number: project_number) end PlanMyStuff::Notifications.instrument('project_item.added', item, user: user) item end |
.delete_item(item_id:, project_number: nil) ⇒ String
Deletes a project item from its parent project. Returns the deletedItemId from the GraphQL response on success.
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 |
# File 'lib/plan_my_stuff/base_project_item.rb', line 226 def delete_item(item_id:, project_number: nil) project_number = resolve_default_project_number(project_number) org = PlanMyStuff.configuration.organization project_id = resolve_project_id(org, project_number) data = PlanMyStuff.client.graphql( PlanMyStuff::GraphQL::Queries::DELETE_PROJECT_ITEM, variables: { projectId: project_id, itemId: item_id }, ) deleted_id = data.dig(:deleteProjectV2Item, :deletedItemId) raise(PlanMyStuff::APIError, "Failed to delete project item #{item_id}") if deleted_id.nil? deleted_id end |
.move_item(item_id:, status:, project_number: nil) ⇒ Hash
Moves a project item to a new status column.
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/plan_my_stuff/base_project_item.rb', line 119 def move_item(item_id:, status:, project_number: nil) project_number = resolve_default_project_number(project_number) project = BaseProject.find(project_number) status_field = project.status_field option_id = resolve_status_option_id(status_field, status) PlanMyStuff.client.graphql( PlanMyStuff::GraphQL::Queries::UPDATE_SINGLE_SELECT_FIELD, variables: { projectId: project.id, itemId: item_id, fieldId: status_field[:id], optionId: option_id, }, ) end |
.update_date_field!(item_id:, field_name:, date:, project_number: nil) ⇒ Hash
Updates a date custom field on a project item.
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
# File 'lib/plan_my_stuff/base_project_item.rb', line 199 def update_date_field!(item_id:, field_name:, date:, project_number: nil) project_number = resolve_default_project_number(project_number) project = BaseProject.find(project_number) field = resolve_text_field(project, field_name) PlanMyStuff.client.graphql( PlanMyStuff::GraphQL::Queries::UPDATE_DATE_FIELD, variables: { projectId: project.id, itemId: item_id, fieldId: field[:id], date: date.to_s, }, ) end |
.update_field!(item_id:, field_name:, value:, project_number: nil) ⇒ Hash
Updates a text custom field on a project item.
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/plan_my_stuff/base_project_item.rb', line 173 def update_field!(item_id:, field_name:, value:, project_number: nil) project_number = resolve_default_project_number(project_number) project = BaseProject.find(project_number) field = resolve_text_field(project, field_name) PlanMyStuff.client.graphql( PlanMyStuff::GraphQL::Queries::UPDATE_TEXT_FIELD, variables: { projectId: project.id, itemId: item_id, fieldId: field[:id], value: value, }, ) end |
.update_single_select_field!(item_id:, field_name:, value:, project_number: nil) ⇒ Hash
Updates a single-select custom field on a project item.
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/plan_my_stuff/base_project_item.rb', line 146 def update_single_select_field!(item_id:, field_name:, value:, project_number: nil) project_number = resolve_default_project_number(project_number) project = BaseProject.find(project_number) field = resolve_single_select_field(project, field_name) option_id = resolve_status_option_id(field, value) PlanMyStuff.client.graphql( PlanMyStuff::GraphQL::Queries::UPDATE_SINGLE_SELECT_FIELD, variables: { projectId: project.id, itemId: item_id, fieldId: field[:id], optionId: option_id, }, ) end |
Instance Method Details
#as_json(options = {}) ⇒ Hash
Serializes the project item to a JSON-safe hash, excluding the back-reference to the parent project to prevent recursive serialization cycles.
533 534 535 536 537 538 539 540 |
# File 'lib/plan_my_stuff/base_project_item.rb', line 533 def as_json( = {}) merged_except = Array.wrap([:except]) + ['project'] merged_methods = Array.wrap([:methods]) + [:draft?] super(.merge(except: merged_except, methods: merged_methods)).merge( 'project_id' => project&.id, 'project_number' => project&.number, ) end |
#assign!(assignees, user: nil) ⇒ void
This method returns an undefined value.
Assigns users to this item on its parent project.
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 |
# File 'lib/plan_my_stuff/base_project_item.rb', line 509 def assign!(assignees, user: nil) assignee_list = Array.wrap(assignees) self.class.assign( number: number, content_node_id: content_node_id, assignees: assignee_list, draft: draft?, repo: repo, ) PlanMyStuff::Notifications.instrument( 'project_item.assigned', self, user: user, assignees: assignee_list, ) end |
#body ⇒ String?
Returns user-visible body (metadata comment stripped).
33 |
# File 'lib/plan_my_stuff/base_project_item.rb', line 33 attribute :body, :string |
#content_node_id ⇒ String?
Returns node ID of the underlying content (Issue, PR, or DraftIssue).
25 |
# File 'lib/plan_my_stuff/base_project_item.rb', line 25 attribute :content_node_id, :string |
#destroy!(user: nil) ⇒ String?
Deletes this item from its parent project. Marks the in-memory instance as destroyed so destroyed? returns true and persisted? returns false.
No-op if the instance is already destroyed.
490 491 492 493 494 495 496 497 498 499 500 501 |
# File 'lib/plan_my_stuff/base_project_item.rb', line 490 def destroy!(user: nil) return if destroyed? deleted_id = self.class.delete_item( project_number: project.number, item_id: id, ) PlanMyStuff::Notifications.instrument('project_item.removed', self, user: user) destroyed! deleted_id end |
#draft? ⇒ Boolean
543 544 545 |
# File 'lib/plan_my_stuff/base_project_item.rb', line 543 def draft? type == 'DRAFT_ISSUE' end |
#field_values ⇒ Hash
47 |
# File 'lib/plan_my_stuff/base_project_item.rb', line 47 attribute :field_values, default: -> { {} } |
#id ⇒ String?
Returns GitHub node ID (e.g. “PVTI_…”).
23 |
# File 'lib/plan_my_stuff/base_project_item.rb', line 23 attribute :id, :string |
#issue ⇒ PlanMyStuff::Issue?
51 |
# File 'lib/plan_my_stuff/base_project_item.rb', line 51 attribute :issue |
#issue=(val) ⇒ void
This method returns an undefined value.
548 549 550 551 |
# File 'lib/plan_my_stuff/base_project_item.rb', line 548 def issue=(val) @issue_assigned = true super end |
#metadata ⇒ PlanMyStuff::ProjectItemMetadata
Returns parsed metadata.
35 |
# File 'lib/plan_my_stuff/base_project_item.rb', line 35 attribute :metadata, default: -> { PlanMyStuff::ProjectItemMetadata.new } |
#move_to!(status, user: nil) ⇒ Hash
Moves this item to a new status column on its parent project.
445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 |
# File 'lib/plan_my_stuff/base_project_item.rb', line 445 def move_to!(status, user: nil) previous_status = self.status result = self.class.move_item( project_number: project.number, item_id: id, status: status, ) PlanMyStuff::Notifications.instrument( 'project_item.status_changed', self, user: user, status: status, previous_status: previous_status, ) result end |
#number ⇒ Integer?
37 |
# File 'lib/plan_my_stuff/base_project_item.rb', line 37 attribute :number, :integer |
#project ⇒ PlanMyStuff::BaseProject?
49 |
# File 'lib/plan_my_stuff/base_project_item.rb', line 49 attribute :project |
#raw_body ⇒ String?
Returns full body as stored on GitHub (draft items only).
31 |
# File 'lib/plan_my_stuff/base_project_item.rb', line 31 attribute :raw_body, :string |
#repo ⇒ PlanMyStuff::Repo?
41 |
# File 'lib/plan_my_stuff/base_project_item.rb', line 41 attribute :repo |
#state ⇒ String?
43 |
# File 'lib/plan_my_stuff/base_project_item.rb', line 43 attribute :state, :string |
#status ⇒ String?
45 |
# File 'lib/plan_my_stuff/base_project_item.rb', line 45 attribute :status, :string |
#title ⇒ String?
29 |
# File 'lib/plan_my_stuff/base_project_item.rb', line 29 attribute :title, :string |
#type ⇒ String?
Returns GitHub item type (e.g. “DRAFT_ISSUE”, “ISSUE”, “PULL_REQUEST”).
27 |
# File 'lib/plan_my_stuff/base_project_item.rb', line 27 attribute :type, :string |
#update_field!(field_name, value) ⇒ Hash
Updates a text custom field on this item.
471 472 473 474 475 476 477 478 |
# File 'lib/plan_my_stuff/base_project_item.rb', line 471 def update_field!(field_name, value) self.class.update_field!( project_number: project.number, item_id: id, field_name: field_name, value: value, ) end |
#url ⇒ String?
39 |
# File 'lib/plan_my_stuff/base_project_item.rb', line 39 attribute :url, :string |