diff --git a/app/models/attachment.rb b/app/models/attachment.rb index 2dbce28730ef..91e20598b22d 100644 --- a/app/models/attachment.rb +++ b/app/models/attachment.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require 'digest/md5' +require "digest/md5" class Attachment < ApplicationRecord enum status: { @@ -38,7 +38,7 @@ class Attachment < ApplicationRecord }.freeze, _prefix: true belongs_to :container, polymorphic: true - belongs_to :author, class_name: 'User' + belongs_to :author, class_name: "User" validates :author, :content_type, :filesize, :status, presence: true validates :description, length: { maximum: 255 } @@ -65,7 +65,7 @@ class Attachment < ApplicationRecord acts_as_journalized acts_as_event title: -> { file.name }, url: (Proc.new do |o| - { controller: '/attachments', action: 'download', id: o.id, filename: o.filename } + { controller: "/attachments", action: "download", id: o.id, filename: o.filename } end) mount_uploader :file, OpenProject::Configuration.file_uploader @@ -108,7 +108,7 @@ def project end def content_disposition(include_filename: true) - disposition = inlineable? ? 'inline' : 'attachment' + disposition = inlineable? ? "inline" : "attachment" if include_filename "#{disposition}; filename=#{filename}" @@ -159,7 +159,7 @@ def is_movie? alias :image? :is_image? def is_pdf? - content_type == 'application/pdf' + content_type == "application/pdf" end def is_text? @@ -193,7 +193,7 @@ def local_path end def filename - attributes['file'] || super + attributes["file"] || super end ## diff --git a/docker/dev/object_storage/docker-compose.yml b/docker/dev/object_storage/docker-compose.yml new file mode 100644 index 000000000000..e48cf5ca5a68 --- /dev/null +++ b/docker/dev/object_storage/docker-compose.yml @@ -0,0 +1,32 @@ +version: "3.9" + +services: + minio: + restart: always + image: minio/minio:latest + volumes: + - minio:/data + entrypoint: minio server /data + networks: + - external + ports: + - "9000:9000" + environment: + - MINIO_ROOT_USER=openproject + - MINIO_ROOT_PASSWORD=openproject + - MINIO_DEFAULT_BUCKETS=application + extra_hosts: + - "openproject.local:host-gateway" + labels: + - "traefik.enable=true" + - "traefik.http.routers.minio.rule=Host(`minio.local`)" + - "traefik.http.routers.minio.entrypoints=websecure" + - "traefik.http.services.minio.loadbalancer.server.port=80" + +volumes: + minio: + +networks: + external: + name: gateway + external: true diff --git a/docker/dev/tls/docker-compose.override.example.yml b/docker/dev/tls/docker-compose.override.example.yml index 5fb18ee2c47c..726573ff93a4 100644 --- a/docker/dev/tls/docker-compose.override.example.yml +++ b/docker/dev/tls/docker-compose.override.example.yml @@ -10,3 +10,4 @@ services: - openproject.local - nextcloud.local - gitlab.local + - minio.local diff --git a/modules/bim/app/controllers/bim/ifc_models/ifc_models_controller.rb b/modules/bim/app/controllers/bim/ifc_models/ifc_models_controller.rb index 6c64972e7752..a9c3718d0565 100644 --- a/modules/bim/app/controllers/bim/ifc_models/ifc_models_controller.rb +++ b/modules/bim/app/controllers/bim/ifc_models/ifc_models_controller.rb @@ -65,6 +65,12 @@ def defaults end def set_direct_upload_file_name + if params[:filesize].to_i > Setting.attachment_max_size.to_i.kilobytes + render json: { error: I18n.t("activerecord.errors.messages.file_too_large", count: Setting.attachment_max_size) }, + status: :unprocessable_entity + return + end + session[:pending_ifc_model_title] = params[:title] session[:pending_ifc_model_is_default] = params[:isDefault] end diff --git a/modules/bim/app/views/bim/ifc_models/ifc_models/_form.html.erb b/modules/bim/app/views/bim/ifc_models/ifc_models/_form.html.erb index 62d8e3464db2..de1608b687c0 100644 --- a/modules/bim/app/views/bim/ifc_models/ifc_models/_form.html.erb +++ b/modules/bim/app/views/bim/ifc_models/ifc_models/_form.html.erb @@ -62,6 +62,10 @@ See COPYRIGHT and LICENSE files for more details. fileName = fileNameField[0].files[0].name; } + <%# Reset the form validity %> + <%# See: https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/setCustomValidity %> + fileNameField[0].setCustomValidity(''); + var titleField = jQuery("#bim_ifc_models_ifc_model_title"); <%# When creating a new model, there is no titleField. %> @@ -86,12 +90,20 @@ See COPYRIGHT and LICENSE files for more details. }, data: { title: title, - isDefault: jQuery("#bim_ifc_models_ifc_model_is_default").is(":checked") ? 1 : 0 + isDefault: jQuery("#bim_ifc_models_ifc_model_is_default").is(":checked") ? 1 : 0, + filesize: fileNameField[0].files[0].size }, statusCode: { 401: function(resp, status, error) { document.location.reload(); // reload to make user login again } + }, + error: function(jqXHR, ajaxOptions, errorThrown) { + if (jqXHR.status == 422) { + var errorMessage = jqXHR.responseJSON.error; + fileNameField[0].setCustomValidity(errorMessage); + fileNameField[0].reportValidity(); + } } }); }; @@ -132,7 +144,11 @@ See COPYRIGHT and LICENSE files for more details. if (submitted) { return }; e.preventDefault(); - setDirectUploadFileName().always(() => form.submit()); + setDirectUploadFileName() + .done(() => form.submit()) + .fail((jqXHR, textStatus, errorThrown) => { + alert("Error: " + errorThrown); + }); submitted = true; }); <% end %>