Skip to content

Commit 5626e6d

Browse files
committed
[Feature - Max Attachment Size] - UI check and notice implemented. BE validation added. ENV added. Tests added. Readme updated.
1 parent 59b322e commit 5626e6d

8 files changed

Lines changed: 75 additions & 5 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ To configure additional features, you can set the following environment variable
2828
`/script/admin/create-vapid-key`
2929
- `SENTRY_DSN` - to enable error reporting to sentry in production, supply your
3030
DSN here
31+
- `MAX_ATTACHMENT_SIZE_IN_BYTES` - sets maximum size in bytes, per attachment, if not defined there is no limit in size
3132

3233
For example:
3334

app/assets/stylesheets/composer.css

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,24 @@
44
padding: var(--block-space-half) calc(var(--inline-space) + 1vw);
55
}
66

7+
.composer-notice {
8+
text-align: right;
9+
color: red;
10+
font-size: 12px;
11+
opacity: 0;
12+
}
13+
14+
.composer-notice-show {
15+
animation: flashMaxAttachmentNotice 2s ease-in
16+
}
17+
18+
@keyframes flashMaxAttachmentNotice
19+
{
20+
0% { opacity: 1; }
21+
95% { opacity: 1; }
22+
100% { opacity: 0; }
23+
}
24+
725
.composer__input-hint,
826
.composer__context-btn {
927
.composer:has(.composer__input:focus-within) & {

app/helpers/application_helper.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,22 @@ def body_classes
2222
[ @body_class, admin_body_class, account_logo_body_class ].compact.join(" ")
2323
end
2424

25+
def is_attachment_size_valid(attachment_size_in_bytes)
26+
return true unless max_attachment_size_enabled?
27+
28+
attachment_size_in_bytes <= max_attachment_size_in_bytes
29+
end
30+
31+
def max_attachment_size_enabled?
32+
ENV.fetch("MAX_ATTACHMENT_SIZE_IN_BYTES", nil).present? && Integer(ENV.fetch("MAX_ATTACHMENT_SIZE_IN_BYTES", nil)).positive?
33+
end
34+
35+
def max_attachment_size_in_bytes
36+
return nil unless max_attachment_size_enabled?
37+
38+
Integer(ENV["MAX_ATTACHMENT_SIZE_IN_BYTES"])
39+
end
40+
2541
def link_back
2642
back_url = request.referrer
2743
back_url = root_path if back_url.nil? || back_url == request.url

app/helpers/rooms_helper.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ def composer_data_options(room)
6666
controller: "composer drop-target",
6767
action: composer_data_actions,
6868
composer_messages_outlet: "#message-area",
69-
composer_toolbar_class: "composer--rich-text", composer_room_id_value: room.id
69+
composer_toolbar_class: "composer--rich-text",
70+
composer_room_id_value: room.id,
71+
composer_max_attachment_size_in_bytes_value: max_attachment_size_in_bytes
7072
}
7173
end
7274

app/javascript/controllers/composer_controller.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { escapeHTML } from "helpers/dom_helpers"
55

66
export default class extends Controller {
77
static classes = ["toolbar"]
8-
static targets = [ "clientid", "fields", "fileList", "text" ]
9-
static values = { roomId: Number }
8+
static targets = [ "clientid", "fields", "fileList", "text", "attachmentNotice" ]
9+
static values = { roomId: Number, maxAttachmentSizeInBytes: Number }
1010
static outlets = [ "messages" ]
1111

1212
#files = []
@@ -65,7 +65,14 @@ export default class extends Controller {
6565

6666
filePicked(event) {
6767
for (const file of event.target.files) {
68-
this.#files.push(file)
68+
if(this.maxAttachmentSizeInBytesValue === null || file.size <= this.maxAttachmentSizeInBytesValue) {
69+
this.#files.push(file)
70+
} else {
71+
this.attachmentNoticeTarget.addEventListener("animationend", () => {
72+
this.attachmentNoticeTarget.classList.remove("composer-notice-show")
73+
});
74+
this.attachmentNoticeTarget.classList.add("composer-notice-show")
75+
}
6976
}
7077
event.target.value = null
7178
this.#updateFileList()

app/models/message.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
class Message < ApplicationRecord
22
include Attachment, Broadcasts, Mentionee, Pagination, Searchable
33

4+
validate :attachment_size
5+
46
belongs_to :room, touch: true
57
belongs_to :creator, class_name: "User", default: -> { Current.user }
68

@@ -41,4 +43,11 @@ def sound
4143
Sound.find_by_name match[:name]
4244
end
4345
end
46+
47+
private
48+
def attachment_size
49+
if attachment? && !ApplicationController.helpers.is_attachment_size_valid(attachment.blob.byte_size)
50+
errors.add(:attachment, "Attachment exceeds max size: #{ApplicationController.helpers.max_attachment_size_in_bytes}")
51+
end
52+
end
4453
end

app/views/rooms/show/_composer.html.erb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
</div>
5151
</div>
5252
</fieldset>
53-
53+
<div class="composer-notice" data-composer-target="attachmentNotice">File exceeds max attachment size (<%= max_attachment_size_in_bytes %> bytes)</div>
5454
<div class="typing-indicator gap txt-small align-center flex-inline" data-typing-notifications-target="indicator">
5555
<div class="typing-indicator__author spinner" data-typing-notifications-target="author"></div>
5656
</div>

test/models/message/attachment_test.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,23 @@ class Message::AttachmentTest < ActiveSupport::TestCase
1919
assert_equal message.plain_text_body, "moon.jpg"
2020
end
2121

22+
test "creating a blank message with attachment that exceeds max attachment limit" do
23+
ApplicationController.helpers.expects(:is_attachment_size_valid).returns(false)
24+
25+
assert_raises(ActiveRecord::RecordInvalid) do
26+
create_attachment_message("moon.jpg", "image/jpeg")
27+
end
28+
end
29+
30+
test "creating a blank message with attachment that doesn't exceed max attachment limit" do
31+
ApplicationController.helpers.expects(:is_attachment_size_valid).returns(true)
32+
33+
assert_nothing_raised do
34+
create_attachment_message("moon.jpg", "image/jpeg")
35+
end
36+
end
37+
38+
2239

2340
private
2441
def create_attachment_message(file, content_type)

0 commit comments

Comments
 (0)