Class: BugReportsClient::BugReportsController

Inherits:
ApplicationController show all
Defined in:
app/controllers/bug_reports_client/bug_reports_controller.rb

Overview

Handles report submission, editing, listing and dismissal of resolved alerts. Reports are saved locally (screenshots via Active Storage), then submitted to the central bug-reports API which files a GitHub issue; the remote ID is stored so closure webhooks can find the local record.

Constant Summary collapse

PER_PAGE =
20

Instance Method Summary collapse

Instance Method Details

#allObject

GET /all (admins via config.admin_check) - every report from this app



23
24
25
26
27
28
# File 'app/controllers/bug_reports_client/bug_reports_controller.rb', line 23

def all
  @bug_reports = paginate(filtered(BugReport.includes(:user)).order(created_at: :desc))

  @counts = status_counts(BugReport)
  @type_counts = type_counts(BugReport)
end

#createObject

POST / Saves the report and screenshots locally, submits to the API, then stores the returned remote ID. A failed API call rolls the local record back so users can retry without creating orphans.



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
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
89
90
91
# File 'app/controllers/bug_reports_client/bug_reports_controller.rb', line 44

def create
  @bug_report = BugReport.new(bug_report_params)
  @bug_report.user = bug_reports_current_user
  apply_default_severity(@bug_report)
  link_related_error(@bug_report)
  @recent_error_events = recent_error_events

  # Screenshot files are validated server-side (type sniffed, size and
  # count checked) BEFORE anything is attached or saved.
  unless validate_screenshots(@bug_report, )
    render :new, status: :unprocessable_entity
    return
  end
  attach_screenshots(@bug_report)

  unless @bug_report.save
    render :new, status: :unprocessable_entity
    return
  end

  result = ApiClient.new.create_bug_report(
    title: @bug_report.title,
    description: DescriptionBuilder.new(@bug_report).build,
    severity: @bug_report.severity,
    report_type: @bug_report.report_type,
    reporter_email: BugReportsClient.config.reporter_email_for(bug_reports_current_user),
    reporter_name: BugReportsClient.config.reporter_name_for(bug_reports_current_user),
    reporter_external: BugReportsClient.config.external_reporter?(bug_reports_current_user)
  )

  if result.success?
    @bug_report.update!(remote_bug_report_id: result.data["id"])
    redirect_to bug_reports_path, notice: t("bug_reports_client.flashes.created", type_noun: @bug_report.type_noun.capitalize)
  else
    # Surface the failure in the form's error box (which scrolls itself
    # into view) rather than a top-of-page flash the user may never see.
    @bug_report.destroy
    @bug_report = BugReport.new
    @bug_report.errors.add(:base, result.message)
    render :new, status: :unprocessable_entity
  end
rescue ApiClient::ApiError => e
  @bug_report.destroy if @bug_report&.persisted?
  @bug_report = BugReport.new
  @bug_report.errors.add(:base, t("bug_reports_client.flashes.submit_failed"))
  Rails.logger.error "BugReportsClient: submission failed: #{e.message}"
  render :new, status: :unprocessable_entity
end

#editObject

GET /:id/edit - form for open (editable) and closed (read-only) reports



37
38
# File 'app/controllers/bug_reports_client/bug_reports_controller.rb', line 37

def edit
end

#indexObject

GET / (engine root) - the current user's reports



14
15
16
17
18
19
20
# File 'app/controllers/bug_reports_client/bug_reports_controller.rb', line 14

def index
  reports = BugReport.where(user: bug_reports_current_user)
  @bug_reports = paginate(filtered(reports).order(created_at: :desc))

  @counts = status_counts(reports)
  @type_counts = type_counts(reports)
end

#newObject

GET /new



31
32
33
34
# File 'app/controllers/bug_reports_client/bug_reports_controller.rb', line 31

def new
  @bug_report = BugReport.new
  @recent_error_events = recent_error_events
end

#updateObject

PATCH /:id Two cases: dismissing a resolved alert (no bug_report params), or editing an open report (re-syncs the remote issue).



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'app/controllers/bug_reports_client/bug_reports_controller.rb', line 96

def update
  return dismiss_bug_report if params[:bug_report].blank?

  unless @bug_report.open?
    redirect_to edit_bug_report_path(@bug_report), alert: t("bug_reports_client.flashes.only_open_editable", type_noun: @bug_report.type_noun)
    return
  end

  # The report type is locked once submitted - the remote issue and its
  # labels are already filed as that type.
  @bug_report.assign_attributes(bug_report_params.except(:report_type))
  apply_default_severity(@bug_report)

  # Attaching to a persisted record writes immediately (bypassing model
  # validations), so the new files must be validated before anything is
  # saved or purged.
  new_screenshots = 
  unless validate_screenshots(@bug_report, new_screenshots)
    render :edit, status: :unprocessable_entity
    return
  end

  if @bug_report.save
    # New uploads replace the existing set; editing without choosing any
    # files leaves the current screenshots alone.
    if new_screenshots.any?
      @bug_report.screenshots.purge
      @bug_report.screenshots.attach(new_screenshots)
    end

    if @bug_report.remote_bug_report_id.present?
      ApiClient.new.update_bug_report(
        @bug_report.remote_bug_report_id,
        title: @bug_report.title,
        description: DescriptionBuilder.new(@bug_report).build,
        severity: @bug_report.severity,
        report_type: @bug_report.report_type
      )
    end

    redirect_to edit_bug_report_path(@bug_report), notice: t("bug_reports_client.flashes.updated", type_noun: @bug_report.type_noun.capitalize)
  else
    render :edit, status: :unprocessable_entity
  end
end