Class: ActiveProject::Adapters::Base

Inherits:
Object
  • Object
show all
Includes:
ErrorMapper
Defined in:
lib/active_project/adapters/base.rb

Overview

Base abstract class defining the interface for all adapters. Concrete adapters should inherit from this class and implement its abstract methods.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config:) ⇒ Base

Returns a new instance of Base.



20
21
22
23
# File 'lib/active_project/adapters/base.rb', line 20

def initialize(config:)
  @config = config
  @status_mapper = StatusMapper.from_config(adapter_type, config)
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



18
19
20
# File 'lib/active_project/adapters/base.rb', line 18

def config
  @config
end

Class Method Details

.webhook_typeSymbol

Returns the webhook type identifier for this adapter class. This distinguishes between different adapter types for the same platform.

Returns:

  • (Symbol)

    The webhook type (e.g., :github_repo, :github_project, :jira, :basecamp)



174
175
176
177
178
179
# File 'lib/active_project/adapters/base.rb', line 174

def self.webhook_type
  # Default implementation extracts from class name
  # GithubRepoAdapter -> :github_repo, BasecampAdapter -> :basecamp
  class_name = name.split("::").last
  class_name.gsub(/Adapter$/, "").gsub(/([a-z])([A-Z])/, '\1_\2').downcase.to_sym
end

Instance Method Details

#add_comment(issue_id, comment_body, context = {}) ⇒ ActiveProject::Comment

Adds a comment to an issue.

Parameters:

  • issue_id (String, Integer)

    The ID or key of the issue.

  • comment_body (String)

    The text of the comment.

  • context (Hash) (defaults to: {})

    Optional context hash. Platform-specific requirements:

    • Basecamp: REQUIRES { project_id: ‘…’ }

    • Jira: Ignored

    • Trello: Ignored

    • GitHub: Optional { content_node_id: ‘…’ } for optimization

Returns:

  • (ActiveProject::Comment)

    The created comment object.

Raises:

  • (ArgumentError)

    if required context is missing (platform-specific).



132
133
134
# File 'lib/active_project/adapters/base.rb', line 132

def add_comment(issue_id, comment_body, context = {})
  raise NotImplementedError, "#{self.class.name} must implement #add_comment"
end

#connected?Boolean

Checks if the adapter can successfully authenticate and connect to the service. Typically calls #get_current_user internally and catches authentication errors.

Returns:

  • (Boolean)

    true if connection is successful, false otherwise.

Raises:



222
223
224
# File 'lib/active_project/adapters/base.rb', line 222

def connected?
  raise NotImplementedError, "#{self.class.name} must implement #connected?"
end

#create_issue(project_id, attributes) ⇒ ActiveProject::Issue

Creates a new issue.

Parameters:

  • project_id (String, Integer)

    The ID or key of the project to create the issue in.

  • attributes (Hash)

    Issue attributes (e.g., title, description).

Returns:

  • (ActiveProject::Issue)

    The created issue object.

Raises:



87
88
89
# File 'lib/active_project/adapters/base.rb', line 87

def create_issue(project_id, attributes)
  raise NotImplementedError, "#{self.class.name} must implement #create_issue"
end

#create_list(project_id, attributes) ⇒ Hash

Creates a new list/container within a project (e.g., Trello List, Basecamp Todolist). Not applicable to all platforms (e.g., Jira statuses are managed differently).

Parameters:

  • project_id (String, Integer)

    The ID or key of the parent project.

  • attributes (Hash)

    List attributes (platform-specific, e.g., :name).

Returns:

  • (Hash)

    A hash representing the created list (platform-specific structure).

Raises:



50
51
52
# File 'lib/active_project/adapters/base.rb', line 50

def create_list(project_id, attributes)
  raise NotImplementedError, "#{self.class.name} does not support #create_list or must implement #create_list"
end

#create_project(attributes) ⇒ ActiveProject::Project

Creates a new project.

Parameters:

  • attributes (Hash)

    Project attributes (platform-specific).

Returns:

  • (ActiveProject::Project)

    The created project object.

Raises:



41
42
43
# File 'lib/active_project/adapters/base.rb', line 41

def create_project(attributes)
  raise NotImplementedError, "#{self.class.name} must implement #create_project"
end

#delete_comment(comment_id, context = {}) ⇒ Boolean

Deletes a comment.

Parameters:

  • comment_id (String, Integer)

    The ID of the comment to delete.

  • context (Hash) (defaults to: {})

    Optional context hash. Platform-specific requirements:

    • Basecamp: REQUIRES { project_id: ‘…’ }

    • Jira: REQUIRES { issue_id: ‘…’ }

    • Trello: Ignored

    • GitHub: Ignored

Returns:

  • (Boolean)

    true if deletion was successful.

Raises:



159
160
161
# File 'lib/active_project/adapters/base.rb', line 159

def delete_comment(comment_id, context = {})
  raise NotImplementedError, "#{self.class.name} does not support #delete_comment"
end

#delete_issue(id, context = {}) ⇒ Boolean

Note:

GitHub adapter overrides this with delete_issue(project_id, item_id) due to GraphQL API requirements.

Deletes an issue from a project.

Parameters:

  • id (String, Integer)

    The ID or key of the issue to delete.

  • context (Hash) (defaults to: {})

    Optional context hash. Platform-specific requirements:

    • Basecamp: REQUIRES { project_id: ‘…’ }

    • Jira: Optional { delete_subtasks: true/false }

    • Trello: Ignored

    • GitHub: Uses different signature: delete_issue(project_id, item_id)

Returns:

  • (Boolean)

    true if deletion was successful.

Raises:

  • (ArgumentError)

    if required context is missing (platform-specific).



118
119
120
# File 'lib/active_project/adapters/base.rb', line 118

def delete_issue(id, context = {})
  raise NotImplementedError, "The #{self.class.name} adapter does not implement delete_issue"
end

#delete_project(project_id) ⇒ Boolean

Deletes a project. Use with caution.

Parameters:

  • project_id (String, Integer)

    The ID or key of the project to delete.

Returns:

  • (Boolean)

    true if deletion was successful (or accepted), false otherwise.

Raises:



58
59
60
# File 'lib/active_project/adapters/base.rb', line 58

def delete_project(project_id)
  raise NotImplementedError, "#{self.class.name} does not support #delete_project or must implement it"
end

#denormalize_status(normalized_status, project_id: nil) ⇒ String, Symbol

Converts a normalized status back to platform-specific format.

Parameters:

  • normalized_status (Symbol)

    Normalized status symbol

  • project_id (String, Integer) (defaults to: nil)

    Optional project context

Returns:

  • (String, Symbol)

    Platform-specific status



255
256
257
# File 'lib/active_project/adapters/base.rb', line 255

def denormalize_status(normalized_status, project_id: nil)
  @status_mapper.denormalize_status(normalized_status, project_id: project_id)
end

#find_issue(id, context = {}) ⇒ ActiveProject::Issue?

Finds a specific issue by its ID or key.

Parameters:

  • id (String, Integer)

    The ID or key of the issue.

  • context (Hash) (defaults to: {})

    Optional context hash. Platform-specific requirements:

    • Basecamp: REQUIRES { project_id: ‘…’ }

    • Jira: Optional { fields: ‘…’ }

    • Trello: Optional { fields: ‘…’ }

    • GitHub: Ignored

Returns:

  • (ActiveProject::Issue, nil)

    The issue object or nil if not found.

Raises:

  • (ArgumentError)

    if required context is missing (platform-specific).



79
80
81
# File 'lib/active_project/adapters/base.rb', line 79

def find_issue(id, context = {})
  raise NotImplementedError, "#{self.class.name} must implement #find_issue"
end

#find_project(id) ⇒ ActiveProject::Project?

Finds a specific project by its ID or key.

Parameters:

  • id (String, Integer)

    The ID or key of the project.

Returns:

  • (ActiveProject::Project, nil)

    The project object or nil if not found.

Raises:



34
35
36
# File 'lib/active_project/adapters/base.rb', line 34

def find_project(id)
  raise NotImplementedError, "#{self.class.name} must implement #find_project"
end

#get_current_userActiveProject::Resources::User

Retrieves details for the currently authenticated user.

Returns:

Raises:



215
216
217
# File 'lib/active_project/adapters/base.rb', line 215

def get_current_user
  raise NotImplementedError, "#{self.class.name} must implement #get_current_user"
end

#list_issues(project_id, options = {}) ⇒ Array<ActiveProject::Issue>

Lists issues within a specific project.

Parameters:

  • project_id (String, Integer)

    The ID or key of the project.

  • options (Hash) (defaults to: {})

    Optional filtering/pagination options.

Returns:

  • (Array<ActiveProject::Issue>)

Raises:



66
67
68
# File 'lib/active_project/adapters/base.rb', line 66

def list_issues(project_id, options = {})
  raise NotImplementedError, "#{self.class.name} must implement #list_issues"
end

#list_projectsArray<ActiveProject::Project>

Lists projects accessible by the configured credentials.

Returns:

  • (Array<ActiveProject::Project>)

Raises:



27
28
29
# File 'lib/active_project/adapters/base.rb', line 27

def list_projects
  raise NotImplementedError, "#{self.class.name} must implement #list_projects"
end

#normalize_status(platform_status, project_id: nil) ⇒ Symbol

Normalizes a platform-specific status to a standard symbol.

Parameters:

  • platform_status (String, Symbol)

    Platform-specific status

  • project_id (String, Integer) (defaults to: nil)

    Optional project context

Returns:

  • (Symbol)

    Normalized status symbol



247
248
249
# File 'lib/active_project/adapters/base.rb', line 247

def normalize_status(platform_status, project_id: nil)
  @status_mapper.normalize_status(platform_status, project_id: project_id)
end

#parse_webhook(request_body, headers = {}) ⇒ ActiveProject::WebhookEvent?

Parses an incoming webhook payload into a standardized WebhookEvent struct.

Parameters:

  • request_body (String)

    The raw request body.

  • headers (Hash) (defaults to: {})

    Optional hash of request headers (may be needed for event type detection).

Returns:

Raises:



205
206
207
208
209
# File 'lib/active_project/adapters/base.rb', line 205

def parse_webhook(request_body, headers = {})
  raise NotImplementedError,
        "#{self.class.name} does not support webhook parsing. " \
        "Webhook support is optional. Check #supports_webhooks? before calling this method."
end

#status_known?(project_id, status_sym) ⇒ Boolean

Adapters that do not support a custom “status” field can simply rely on this default implementation. Adapters that do care (e.g. the GitHub project adapter which knows its single-select options) already override it.

Returns:

  • (Boolean)

    true if the symbol is safe to pass through.



232
233
234
# File 'lib/active_project/adapters/base.rb', line 232

def status_known?(project_id, status_sym)
  @status_mapper.status_known?(status_sym, project_id: project_id)
end

#supports_webhooks?Boolean

Checks if the adapter supports webhook processing.

Returns:

  • (Boolean)

    true if the adapter can process webhooks



165
166
167
168
169
# File 'lib/active_project/adapters/base.rb', line 165

def supports_webhooks?
  respond_to?(:parse_webhook, true) &&
    !method(:parse_webhook).source_location.nil? &&
    method(:parse_webhook).source_location[0] != __FILE__
end

#update_comment(comment_id, body, context = {}) ⇒ ActiveProject::Comment

Updates an existing comment.

Parameters:

  • comment_id (String, Integer)

    The ID of the comment to update.

  • body (String)

    The new comment body text.

  • context (Hash) (defaults to: {})

    Optional context hash. Platform-specific requirements:

    • Basecamp: REQUIRES { project_id: ‘…’ }

    • Jira: REQUIRES { issue_id: ‘…’ }

    • Trello: Ignored

    • GitHub: Ignored

Returns:

  • (ActiveProject::Comment)

    The updated comment object.

Raises:



146
147
148
# File 'lib/active_project/adapters/base.rb', line 146

def update_comment(comment_id, body, context = {})
  raise NotImplementedError, "#{self.class.name} does not support #update_comment"
end

#update_issue(id, attributes, context = {}) ⇒ ActiveProject::Issue

Note:

GitHub adapter overrides this with update_issue(project_id, item_id, attrs) due to GraphQL API requirements for project-specific field operations.

Updates an existing issue.

Parameters:

  • id (String, Integer)

    The ID or key of the issue to update.

  • attributes (Hash)

    Issue attributes to update.

  • context (Hash) (defaults to: {})

    Optional context hash. Platform-specific requirements:

    • Basecamp: REQUIRES { project_id: ‘…’ }

    • Jira: Optional { fields: ‘…’ }

    • Trello: Optional { fields: ‘…’ }

    • GitHub: Uses different signature: update_issue(project_id, item_id, attrs)

Returns:

  • (ActiveProject::Issue)

    The updated issue object.

Raises:

  • (ArgumentError)

    if required context is missing (platform-specific).



103
104
105
# File 'lib/active_project/adapters/base.rb', line 103

def update_issue(id, attributes, context = {})
  raise NotImplementedError, "#{self.class.name} must implement #update_issue"
end

#valid_statuses(project_id = nil) ⇒ Array<Symbol>

Returns all valid statuses for the given project context.

Parameters:

  • project_id (String, Integer) (defaults to: nil)

    The project context

Returns:

  • (Array<Symbol>)

    Array of valid status symbols



239
240
241
# File 'lib/active_project/adapters/base.rb', line 239

def valid_statuses(project_id = nil)
  @status_mapper.valid_statuses(project_id: project_id)
end

#verify_webhook_signature(request_body, signature_header, webhook_secret: nil) ⇒ Boolean

Note:

Override this method in adapter subclasses to implement platform-specific verification.

Verifies the signature of an incoming webhook request, if supported by the platform.

Parameters:

  • request_body (String)

    The raw request body.

  • signature_header (String)

    The value of the platform-specific signature header.

  • webhook_secret (String) (defaults to: nil)

    Optional webhook secret for verification.

Returns:

  • (Boolean)

    true if the signature is valid or verification is not supported, false otherwise.



193
194
195
196
197
198
# File 'lib/active_project/adapters/base.rb', line 193

def verify_webhook_signature(request_body, signature_header, webhook_secret: nil)
  # Default implementation assumes no verification needed.
  # Adapters supporting verification should override this method.
  return true unless supports_webhooks? # Allow non-webhook flows by default
  false # Adapters must override this method to implement verification
end

#webhook_typeSymbol

Instance method that delegates to class method

Returns:

  • (Symbol)

    The webhook type



183
184
185
# File 'lib/active_project/adapters/base.rb', line 183

def webhook_type
  self.class.webhook_type
end