• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pulibrary / tigerdata-app / 2fb4025f-2f8f-4e95-8823-3f9744ab33a6

12 Feb 2026 02:48PM UTC coverage: 90.265% (-0.7%) from 90.952%
2fb4025f-2f8f-4e95-8823-3f9744ab33a6

Pull #2384

circleci

web-flow
Merge branch 'main' into file-explorer-poc
Pull Request #2384: File Explorer Proof of Concept

3 of 29 new or added lines in 2 files covered. (10.34%)

2 existing lines in 1 file now uncovered.

3069 of 3400 relevant lines covered (90.26%)

585.69 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.45
/app/controllers/projects_controller.rb
1
# frozen_string_literal: true
2
class ProjectsController < ApplicationController
2✔
3

4
  before_action :set_breadcrumbs
2✔
5
  before_action :authenticate_user!
2✔
6

7
  def details
2✔
8
    return if project.blank?
22✔
9

10
    add_breadcrumb(@presenter.title, project_path)
20✔
11
    add_breadcrumb("Details")
20✔
12

13
    project_metadata = @project.metadata
20✔
14
    storage_capacity = project_metadata[:storage_capacity]
20✔
15
    size = storage_capacity[:size]
20✔
16
    unit = storage_capacity[:unit]
20✔
17

18
    @requested_size = size[:requested]
20✔
19
    @requested_unit = unit[:requested]
20✔
20

21
    @approved_size = size[:approved]
20✔
22
    @approved_unit = unit[:approved]
20✔
23

24
    @project_session = "details"
20✔
25
    @show_quota_breakdown = params["quota"] == "true"
20✔
26

27
    respond_to do |format|
20✔
28
      format.html do
20✔
29
        render
17✔
30
      end
31
      format.json do
20✔
32
        render json: project.to_json
2✔
33
      end
34
      format.xml do
20✔
35
        render xml: @presenter.to_xml
1✔
36
      end
37
    end
38
  end
39

40
  def index
2✔
41
    if current_user.eligible_sysadmin?
10✔
42
      search_projects
6✔
43
    else
44
      flash[:alert] = I18n.t(:access_denied)
4✔
45
      redirect_to dashboard_path
4✔
46
    end
47
  end
48

49
  def show
2✔
50
    return if project.blank?
38✔
51

52
    add_breadcrumb(@presenter.title, project_path)
29✔
53
    add_breadcrumb("Contents")
29✔
54

55
    @latest_completed_download = current_user.inventory_requests.where(project_id: @project.id, state: "completed").order(:completion_time).last
29✔
56
    @storage_usage = project.storage_usage(session_id: current_user.mediaflux_session)
29✔
57
    @storage_capacity = project.storage_capacity(session_id: current_user.mediaflux_session)
29✔
58

59
    @num_files = project.asset_count(session_id: current_user.mediaflux_session)
29✔
60

61
    @file_list = project.file_list(session_id: current_user.mediaflux_session, size: 100)
29✔
62
    @files = @file_list[:files]
29✔
63
    @files.sort_by!(&:path)
29✔
64

65
    @project_session = "content"
29✔
66
    respond_to do |format|
29✔
67
      format.html { render }
52✔
68
      format.xml { render xml: ProjectShowPresenter.new(project, current_user).to_xml
35✔
69
    }
70
    end
71
  end
72

73
  # GET "projects/:id/file-explorer"
74
  # Used via an AJAX call to retrieve the list of files for a given path within a project
75
  def file_explorer
2✔
NEW
76
    project # force the presenter to be set
×
77

NEW
78
    if params["pathId"].to_i == 0
×
NEW
79
      path = @presenter.project_directory
×
NEW
80
      path_id = project.mediaflux_id
×
81
    else
NEW
82
      path = params["path"]
×
NEW
83
      path_id = params["pathId"].to_i
×
84
    end
85

NEW
86
    iterator_id = if params["iteratorId"].to_i == 0
×
87
      # setup a new iterator
NEW
88
      project.file_explorer_setup(session_id: current_user.mediaflux_session, path_id: path_id)
×
89
    else
90
      # use the existing iterator
NEW
91
      params["iteratorId"].to_i
×
92
    end
93

NEW
94
    mediaflux_data = project.file_explorer_iterate(session_id: current_user.mediaflux_session, iterator_id: iterator_id)
×
NEW
95
    if mediaflux_data[:error]
×
NEW
96
      render json: {}, status: 500
×
97
    else
98
      data = {
NEW
99
        fileListUrl: project_file_explorer_url,
×
100
        currentPath: path,
101
        currentPathId: path_id,
102
        iteratorId: iterator_id,
103
        files: mediaflux_data[:files],
104
        complete: mediaflux_data[:complete]
105
      }
NEW
106
      render json: data
×
107
    end
108
  end
109

110
  # GET "projects/:id/:id-mf"
111
  #
112
  # This action is used to render the mediaflux metadata for a project.
113
  def show_mediaflux
2✔
114
    project_id = params[:id]
4✔
115
    project = Project.find(project_id)
4✔
116
    respond_to do |format|
3✔
117
      format.xml do
3✔
118
        render xml: project.mediaflux_meta_xml(user: current_user)
3✔
119
      end
120
    end
121
  rescue => ex
122
    Rails.logger.error "Error getting MediaFlux XML for project #{project_id}, user #{current_user.uid}: #{ex.message}"
1✔
123
    flash[:alert] = "Error fetching Mediaflux XML for this project"
1✔
124
    redirect_to project_path(project_id)
1✔
125
  end
126

127
  def list_contents
2✔
128
    return if project.blank?
4✔
129

130
    project_job_service.list_contents_job(user: current_user)
3✔
131

132
    json_response = {
133
      message: "File list for \"#{project.title}\" is being generated in the background. A link to the downloadable file list will be available in the \"Recent Activity\" section of your dashboard when it is available. You may safely navigate away from this page or close this tab."
3✔
134
    }
135
    render json: json_response
3✔
136
  rescue => ex
137
    message = "Error producing document list (project id: #{project&.id}): #{ex.message}"
×
138
    Rails.logger.error(message)
×
139
    Honeybadger.notify(message)
×
140
    render json: { message: "Document list could not be generated." }
×
141
  end
142

143
  def file_list_download
2✔
144
    job_id = params[:job_id]
×
145
    file_inventory_request = FileInventoryRequest.where(job_id:job_id).first
×
146
    if file_inventory_request.nil?
×
147
      # TODO: handle error
148
      redirect_to "/"
×
149
    else
150
      filename = file_inventory_request.output_file
×
151
      send_data File.read(filename), type: "text/plain", filename: "filelist.csv", disposition: "attachment"
×
152
    end
153
  end
154

155
  private
2✔
156

157
    def project_job_service
2✔
158
      @project_job_service ||= ProjectJobService.new(project:)
3✔
159
    end
160

161
    def project
2✔
162
      @project ||= begin
194✔
163
        project = Project.find(params[:id])
64✔
164
        @presenter = ProjectShowPresenter.new(project, current_user)
64✔
165
        if project&.mediaflux_id != nil && @presenter.user_has_access?(user: current_user)
60✔
166
          project
52✔
167
        else
168
          flash[:alert] = I18n.t(:access_denied)
8✔
169
          redirect_to dashboard_path
8✔
170
          nil
8✔
171
        end
172
      end
173
    end
174

175
    def eligible_editor?
2✔
176
      return true if current_user.eligible_sponsor? or current_user.eligible_manager?
×
177
    end
178

179
    def set_breadcrumbs
2✔
180
      add_breadcrumb("Dashboard",dashboard_path)
84✔
181
    end
182

183
    def search_projects
2✔
184
      @title_query = if params[:title_query].present?
6✔
185
        params[:title_query]
4✔
186
      else
187
        "*" # default to all projects
2✔
188
      end
189
      result =  ProjectSearch.new.call(search_string: @title_query, requestor: current_user)
6✔
190
      if result.success?
6✔
191
        flash[:notice] = "Successful search in Mediaflux for #{@title_query}"
6✔
192
        @project_presenters = result.value!
6✔
193
      else
194
        flash[:notice] = "Error searching projects for #{@title_query}.  Error: #{result.failure}"
×
195
        @project_presenters = []
×
196
      end
197
    end
198
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc