Class: CamaleonCms::Admin::MediaController

Inherits:
CamaleonCms::AdminController show all
Defined in:
app/controllers/camaleon_cms/admin/media_controller.rb

Instance Method Summary collapse

Methods inherited from CamaleonCms::AdminController

#cama_get_i18n_frontend, #dashboard, #search

Instance Method Details

#actionsObject

do background actions in fog



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
# File 'app/controllers/camaleon_cms/admin/media_controller.rb', line 100

def actions
  params[:folder] = params[:folder].gsub('//', '/') if params[:folder].present?

  case params[:media_action]
  when 'new_folder'
    params[:folder] = slugify_folder(params[:folder])
    r = cama_uploader.add_folder(params[:folder])
    return render partial: 'render_file_item', locals: { files: [r] } if r[:error].blank?
  when 'del_folder'
    r = cama_uploader.delete_folder(params[:folder])
  when 'del_file'
    r = cama_uploader.delete_file(params[:folder].gsub('//', '/'))
  when 'crop_url'
    user_url = params[:url].to_s
    user_url = "#{current_site.the_url(locale: nil)}#{user_url}" unless user_url.start_with?('data:', 'http')
    url_error = cama_upload_url_error(user_url)
    r = if url_error
          { error: url_error }
        else
          cama_tmp_upload(user_url, formats: params[:formats], name: params[:name])
        end
    if r[:error].blank?
      params[:file_upload] = r[:file_path]
      sett = { remove_source: true }
      sett[:same_name] = true if params[:same_name].present?
      sett[:name] = params[:name] if params[:name].present?
      return upload(sett)
    end
  end

  return render plain: helpers.sanitize(r[:error]) if r[:error].present?

  render plain: ''
end

#ajaxObject

render media for modal content



86
87
88
89
90
91
92
93
94
95
96
97
# File 'app/controllers/camaleon_cms/admin/media_controller.rb', line 86

def ajax
  @show_file_actions = true if current_site.get_option('file_actions_in_modals') == 'yes'
  @tree = cama_uploader.search(params[:search]) if params[:search].present?
  @files = cama_uploader.cama_prepare_browser_page(@tree.paginate(page: params[:page], per_page: 100))
  @next_page = @files.current_page < @files.total_pages ? @files.current_page + 1 : nil
  if params[:partial].present?
    render json: { next_page: @next_page,
                   html: render_to_string(partial: 'render_file_item', locals: { files: @files }) }
  elsif params[:partial].blank?
    render 'index', layout: false
  end
end

#cropObject

crop a image to save as a new file

Unlike crop_url (which is URL-only and prefixes the site URL onto relative inputs), crop accepts three cp_img_path shapes: an http(s) URL, a data: URI, or a server filesystem path (see the cama_tmp_upload examples). Only http(s) URLs are validated here; data: URIs and filesystem paths pass through to cama_tmp_upload, whose cama_canonical_upload_path guard confines them to the public/tmp roots. A bare relative path is therefore treated as a filesystem path, not prefixed with the site URL — intentional divergence.



30
31
32
33
34
35
36
37
38
39
40
41
42
43
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
# File 'app/controllers/camaleon_cms/admin/media_controller.rb', line 30

def crop
  cp_img_path = params[:cp_img_path].to_s
  if (url_error = cama_upload_url_error(cp_img_path))
    return render(plain: helpers.sanitize(url_error))
  end

  # Security (object-level authorization): setting another user's avatar is a user-management
  # write, so gate a non-self saved_avatar target on :manage, :users -- the same capability
  # UsersController#update already requires. Decide from the parameter, before resolving the
  # target (so a denied caller cannot use the response as a same-site existence oracle) and
  # before the upload/crop (so no file work happens on a denied request). A caller may always
  # set their own avatar with the media permission the endpoint already requires.
  # (Mirrors UsersController#profile's self-vs-other gate. The .to_s compare and the blank-
  # saved_avatar skip -- a plain crop, not a user write -- are intentional and fail-closed; do
  # not "align" this to users_controller's .to_i, which coerces non-canonical ids.)
  if params[:saved_avatar].present? && params[:saved_avatar].to_s != cama_current_user.id.to_s
    authorize! :manage, :users
  end

  tmp = cama_tmp_upload(cp_img_path, formats: params[:formats], name: params[:name])
  return render(plain: helpers.sanitize(tmp[:error])) if tmp[:error].present?

  path_image = tmp[:file_path]
  crop_path = cama_crop_image(path_image, params[:ic_w], params[:ic_h], params[:ic_x], params[:ic_y])
  res = upload_file(crop_path, { remove_source: true })
  # A failed upload returns { error: ... } with no url. Surface it like the action's other
  # error paths instead of writing a nil avatar meta and rendering an empty 200 body (which
  # let the avatar flow store "").
  return render(plain: helpers.sanitize(res[:error])) if res[:error].present?

  # Security (audit Low): resolve the avatar target through the current site and nil-safely.
  # The object-level gate above (:manage, :users for a non-self target) is the primary control
  # that stops a media manager from writing another user's avatar; this site-scoping is defense
  # in depth -- for an authorized :manage,:users holder a foreign id is a no-op here, where an
  # unscoped User.find would reach across sites and 500 on a bad id.
  if params[:saved_avatar].present?
    current_site.users.find_by(id: params[:saved_avatar])&.set_meta('avatar', res['url'])
  end
  render plain: res['url'].to_s
end

#download_private_fileObject

download private files



72
73
74
75
76
77
78
79
80
81
82
83
# File 'app/controllers/camaleon_cms/admin/media_controller.rb', line 72

def download_private_file
  cama_uploader.enable_private_mode!

  sanitize_private_filename!
  return render(plain: 'Invalid file', status: :forbidden) unless @private_file_path

  fetched = cama_uploader.fetch_file(@private_file_path)

  return render plain: helpers.sanitize(fetched[:error]) if fetched.is_a?(Hash) && fetched[:error].present?

  send_file fetched, disposition: 'inline'
end

#indexObject

render media section



14
15
16
17
18
19
# File 'app/controllers/camaleon_cms/admin/media_controller.rb', line 14

def index
  @show_file_actions = true
  @files = cama_uploader.cama_prepare_browser_page(@tree.paginate(page: params[:page], per_page: 100))
  @next_page = @files.current_page < @files.total_pages ? @files.current_page + 1 : nil
  add_breadcrumb I18n.t('camaleon_cms.admin.sidebar.media')
end

#upload(settings = {}) ⇒ Object

upload files from media uploader



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'app/controllers/camaleon_cms/admin/media_controller.rb', line 136

def upload(settings = {})
  params[:dimension] = nil if params[:skip_auto_crop].present?
  f = { error: 'File not found.' }
  if params[:file_upload].present?
    if params[:file_upload].is_a?(String) && (url_error = cama_upload_url_error(params[:file_upload]))
      return render plain: helpers.sanitize(url_error)
    end

    f = upload_file(
      params[:file_upload],
      {
        folder: params[:folder], dimension: params['dimension'], formats: params[:formats],
        versions: params[:versions], thumb_size: params[:thumb_size]
      }.merge!(settings)
    )
  end

  if f[:error].present?
    render plain: helpers.sanitize(f[:error])
  else
    render partial: 'render_file_item', locals: { files: [f] }
  end
end