# Несогласованный код/требования для PM-тегов

**URL:** https://meta.discourse.org/t/inconsistent-code-requirements-for-pm-tagging/362931
**Category:** Bug
**Tags:** tags, personal-messages
**Created:** [22.Апрель.2025 08:14:18 UTC](https://meta.discourse.org/t/inconsistent-code-requirements-for-pm-tagging/362931 "2025-04-22T08:14:18Z")
**Posts on this page:** 1
**Showing post:** 1

<div class="post-metadata">

### Author: ![RGJ](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/rgj/32/523185_2.png) [@RGJ](https://meta.discourse.org/u/RGJ)
#### Post date: [22.Апрель.2025 08:14:18 UTC](https://meta.discourse.org/t/inconsistent-code-requirements-for-pm-tagging/362931/1 "2025-04-22T08:14:18Z")

</div>

### Код обработки тегов для личных сообщений непоследователен.

В некоторых частях кодовой базы достаточно быть в группе `pm_tags_allowed_for_groups`, чтобы иметь возможность добавить тег к личному сообщению.

В других частях кодовой базы необходимо быть одновременно и в `pm_tags_allowed_for_groups`, и в `tag_topic_allowed_groups`.

Это особенно ограничительно, когда требуется, чтобы пользователи могли добавлять теги к своим собственным личным сообщениям, при этом вы не хотите, чтобы они могли добавлять теги к публичным темам (например, как в этом случае: [Private template permissions to override allowed PM tagging groups](https://meta.discourse.org/t/private-template-permissions-to-override-allowed-pm-tagging-groups/277513)), то есть когда `pm_tags_allowed_for_groups` не является подмножеством `tag_topic_allowed_groups`.

### Анализ

В [`TagGuardian`](https://github.com/discourse/discourse/blob/b0ab1b23214ec8377dbac5defa118e6a2427edf4/lib/guardian/tag_guardian.rb#L22) эти настройки различны. Для возможности добавления тега к личному сообщению достаточно быть в группе `pm_tags_allowed_for_groups`.

```rb
  def can_tag_topics?
    SiteSetting.tagging_enabled && @user.in_any_groups?(SiteSetting.tag_topic_allowed_groups_map)
  end
  
  def can_tag_pms?
    return false if !SiteSetting.tagging_enabled
    return false if @user.blank?
    return true if @user == Discourse.system_user

    group_ids = SiteSetting.pm_tags_allowed_for_groups_map
    group_ids.include?(Group::AUTO_GROUPS[:everyone]) ||
      @user.group_users.exists?(group_id: group_ids)
  end

```

То же самое касается и [`Guardian.can_tag?`](https://github.com/discourse/discourse/blob/b2ce3746508b0fec369a42b0525699afe56596f7/lib/guardian.rb#L231). Настройки различны.

```rb
  def can_tag?(topic)
    return false if topic.blank?

    topic.private_message? ? can_tag_pms? : can_tag_topics?
  end

```

[`ListController`](https://github.com/discourse/discourse/blob/b2ce3746508b0fec369a42b0525699afe56596f7/app/controllers/list_controller.rb#L205) также удовлетворяется только проверкой `can_tag_pms?`.

```rb
    when :private_messages_tag
      raise Discourse::NotFound if target_user.id != current_user.id
      raise Discourse::NotFound if !guardian.can_tag_pms? 

```

Однако [`TopicGuardian`](https://github.com/discourse/discourse/blob/b2ce3746508b0fec369a42b0525699afe56596f7/lib/guardian/topic_guardian.rb#L331) требует, чтобы пользователь состоял одновременно и в `tag_topic_allowed_groups`, и в `pm_tags_allowed_for_groups`, если он хочет иметь возможность добавить тег к личному сообщению.

```rb
  def can_edit_tags?(topic)
    return false unless can_tag_topics?
    return false if topic.private_message? && !can_tag_pms?
    return true if can_edit_topic?(topic)

    if topic&.first_post&.wiki &&
         @user.in_any_groups?(SiteSetting.edit_wiki_post_allowed_groups_map)
      return can_create_post?(topic)
    end

    false
  end

```

На стороне клиента такое же ограничение действует в [`Composer`](https://github.com/discourse/discourse/blob/b2ce3746508b0fec369a42b0525699afe56596f7/app/assets/javascripts/discourse/app/services/composer.js#L305).

```js
  @discourseComputed("model.canEditTitle", "model.creatingPrivateMessage")
  canEditTags(canEditTitle, creatingPrivateMessage) {
    const isPrivateMessage =
      creatingPrivateMessage || this.get("model.topic.isPrivateMessage");
    return (
      canEditTitle &&
      this.site.can_tag_topics &&
      (!isPrivateMessage || this.site.can_tag_pms)
    );
  }

```

и в [`TopicController`](https://github.com/discourse/discourse/blob/b2ce3746508b0fec369a42b0525699afe56596f7/app/assets/javascripts/discourse/app/controllers/topic.js#L235).

```js
  @discourseComputed("model.isPrivateMessage")
  canEditTags(isPrivateMessage) {
    return (
      this.site.get("can_tag_topics") &&
      (!isPrivateMessage || this.site.get("can_tag_pms"))
    );
  }

```

Однако модальное окно [`Move to Topic`](https://github.com/discourse/discourse/blob/b2ce3746508b0fec369a42b0525699afe56596f7/app/assets/javascripts/discourse/app/components/modal/move-to-topic.gjs#L101) не имеет такого ограничения:

```js
  get canTagMessages() {
    return this.site.can_tag_pms;
  }

```

и [`ChatToTopicSelector`](https://github.com/discourse/discourse/blob/8367819b1b52e5b141ea8ced73216d798f7b243a/plugins/chat/assets/javascripts/discourse/components/chat-to-topic-selector.gjs#L28) также:

```js
@alias("site.can_tag_pms") canTagMessages;

```

и [`UserPrivateMessagesController`](https://github.com/discourse/discourse/blob/b2ce3746508b0fec369a42b0525699afe56596f7/app/assets/javascripts/discourse/app/controllers/user-private-messages.js#L90) тоже:

```js
@readOnly("site.can_tag_pms") pmTaggingEnabled;

    if (this.pmTaggingEnabled) {
      content.push({
        id: this.router.urlFor("userPrivateMessages.tags", usernameLower),
        name: i18n("user.messages.tags"),
        icon: "tags",
      });
    }

```

### Итог

| Класс | Сторона | Поведение |
| --- | --- | --- |
| TagGuardian | сервер | только pm\_tags\_allowed\_for\_groups |
| Guardian | сервер | только pm\_tags\_allowed\_for\_groups |
| ListController | сервер | только pm\_tags\_allowed\_for\_groups |
| TopicGuardian | сервер | и pm\_tags\_allowed\_for\_groups, и tag\_topic\_allowed\_groups |
| Composer | клиент | и pm\_tags\_allowed\_for\_groups, и tag\_topic\_allowed\_groups |
| TopicController | клиент | и pm\_tags\_allowed\_for\_groups, и tag\_topic\_allowed\_groups |
| Модальное окно Move to Topic | клиент | только pm\_tags\_allowed\_for\_groups |
| ChatToTopicSelector | клиент | только pm\_tags\_allowed\_for\_groups |
| | | |

### Дополнительные проблемы

Я обнаружил ещё два дополнительных препятствия:

[`PostRevisor`](https://github.com/discourse/discourse/blob/main/lib/post_revisor.rb#L109C1-L110C35) использует `tc.guardian.can_tag_topics?` вместо `tc.guardian.can_tag?(tc.topic)`.

А в `DiscourseTagging`

`tag_topic_by_names` работает правильно:

```rb
  def self.tag_topic_by_names(topic, guardian, tag_names_arg, append: false)
    if guardian.can_tag?(topic)    

```

но [`tags_for_saving`](https://github.com/discourse/discourse/blob/main/lib/discourse_tagging.rb#L733) — нет:

```rb

   def self.tags_for_saving(tags_arg, guardian, opts = {})
    return [] unless guardian.can_tag_topics? && tags_arg.present?

```

Последняя проблема особенно неприятна, так как функция не знает, работает ли она с личным сообщением.

---

_[View the full topic](https://meta.discourse.org/t/inconsistent-code-requirements-for-pm-tagging/362931)._
