我们在使用微型博客(简称微博)时,时常会需要带图片发起投票。就比如给小姐姐打分投票时没有图片,就很难把问题描述清楚。这种情况就需要进行长毛象轻度魔改

那么废话不多说,直接进入正题

问题分析

不想看过程的(跟我想的一样的)可以跳过这一章节。

这个灵感直接来源于这个glitch版长毛象的提交https://github.com/BakaAC/mastodon/commit/e797b43a328679c879bd7ddadfafc701daccefc8 (这里不方便嵌入网页,就直接分析一下思路得了)

原版长毛象故意 禁了投票的功能。我在魔改完成后,提交了Pull Request,尽管这个呼声在长毛象用户当中非常强烈,但作者方面仍然拒绝了本次合并。理由很简单:

Thank you for your contribution, however, I’ve discussed this with our designer and our position remains that we don’t want to encourage media + poll posts (even though we are aware they are possible in other fediverse software) for two main reasons:

  1. Height of individual items in the feed (a single post shouldn’t be able to hog too much scroll space)
  2. Box-in-a-box-over-box problem (polls are boxes, media is boxes, they’re in a post, with quote posts they’re in another box, etc)
    纯粹是担心影响用户体验罢了。

让我们来看看作者是如何禁止的:

  1. “发送”代码被写死:禁止带图和投票的嘟文被发送
  2. “插入图片”和“插入投票”的代码分别被写死:禁止在有图片或投票时,处于可用状态,只能处于禁用(disabled)状态
  3. 后端可能被写死:所有同时包含投票和图片的嘟文,禁止以发送(post)和编辑(update)方式发布
    可谓是严防死守。

代码实现

歪个题,以后所有魔改,我都直接git diff两个提交,粘贴输出的代码到这里来,家人们自己抄

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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
70
71
72
73
74
75
76
diff --git a/app/javascript/mastodon/actions/compose.js b/app/javascript/mastodon/actions/compose.js
index aa1c6de20e..7525be454e 100644
--- a/app/javascript/mastodon/actions/compose.js
+++ b/app/javascript/mastodon/actions/compose.js
@@ -83,7 +83,6 @@ export const COMPOSE_FOCUS = 'COMPOSE_FOCUS';

const messages = defineMessages({
uploadErrorLimit: { id: 'upload_error.limit', defaultMessage: 'File upload limit exceeded.' },
- uploadErrorPoll: { id: 'upload_error.poll', defaultMessage: 'File upload not allowed with polls.' },
open: { id: 'compose.published.open', defaultMessage: 'Open' },
published: { id: 'compose.published.body', defaultMessage: 'Post published.' },
saved: { id: 'compose.saved.body', defaultMessage: 'Post saved.' },
@@ -310,11 +309,6 @@ export function uploadCompose(files) {
return;
}

- if (getState().getIn(['compose', 'poll'])) {
- dispatch(showAlert({ message: messages.uploadErrorPoll }));
- return;
- }
-
dispatch(uploadComposeRequest());

for (const [i, file] of Array.from(files).entries()) {
diff --git a/app/javascript/mastodon/features/compose/containers/poll_button_container.js b/app/javascript/mastodon/features/compose/containers/poll_button_container.js
index 9de388f64a..f037c253a8 100644
--- a/app/javascript/mastodon/features/compose/containers/poll_button_container.js
+++ b/app/javascript/mastodon/features/compose/containers/poll_button_container.js
@@ -4,7 +4,7 @@ import { addPoll, removePoll } from '../../../actions/compose';
import PollButton from '../components/poll_button';

const mapStateToProps = state => ({
- disabled: state.getIn(['compose', 'is_uploading']) || (state.getIn(['compose', 'media_attachments']).size > 0),
+ disabled: state.getIn(['compose', 'is_uploading']) ,
active: state.getIn(['compose', 'poll']) !== null,
});

diff --git a/app/javascript/mastodon/features/compose/containers/upload_button_container.js b/app/javascript/mastodon/features/compose/containers/upload_button_container.js
index 7cdc12663d..53528ca3f8 100644
--- a/app/javascript/mastodon/features/compose/containers/upload_button_container.js
+++ b/app/javascript/mastodon/features/compose/containers/upload_button_container.js
@@ -13,7 +13,7 @@ const mapStateToProps = state => {
const hasVideoOrAudio = state.getIn(['compose', 'media_attachments']).some(m => ['video', 'audio'].includes(m.get('type')));

return {
- disabled: isPoll || isUploading || isOverLimit || hasVideoOrAudio,
+ disabled: isUploading || isOverLimit || hasVideoOrAudio,
resetFileKey: state.getIn(['compose', 'resetFileKey']),
};
};
diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb
index 98fd95f025..4cb2b399ff 100644
--- a/app/services/post_status_service.rb
+++ b/app/services/post_status_service.rb
@@ -130,7 +130,7 @@ class PostStatusService < BaseService
return
end

- raise Mastodon::ValidationError, I18n.t('media_attachments.validations.too_many') if @options[:media_ids].size > Status::MEDIA_ATTACHMENTS_LIMIT || @options[:poll].present?
+ raise Mastodon::ValidationError, I18n.t('media_attachments.validations.too_many') if @options[:media_ids].size > Status::MEDIA_ATTACHMENTS_LIMIT

@media = @account.media_attachments.where(status_id: nil).where(id: @options[:media_ids].take(Status::MEDIA_ATTACHMENTS_LIMIT).map(&:to_i))

diff --git a/app/services/update_status_service.rb b/app/services/update_status_service.rb
index 7837d37c95..a2f50e901a 100644
--- a/app/services/update_status_service.rb
+++ b/app/services/update_status_service.rb
@@ -69,7 +69,7 @@ class UpdateStatusService < BaseService
def validate_media!
return [] if @options[:media_ids].blank? || !@options[:media_ids].is_a?(Enumerable)

- raise Mastodon::ValidationError, I18n.t('media_attachments.validations.too_many') if @options[:media_ids].size > Status::MEDIA_ATTACHMENTS_LIMIT || @options[:poll].present?
+ raise Mastodon::ValidationError, I18n.t('media_attachments.validations.too_many') if @options[:media_ids].size > Status::MEDIA_ATTACHMENTS_LIMIT

media_attachments = @status.account.media_attachments.where(status_id: [nil, @status.id]).where(scheduled_status_id: nil).where(id: @options[:media_ids].take(Status::MEDIA_ATTACHMENTS_LIMIT).map(&:to_i)).to_a