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

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

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

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

Это особенно ограничительно, когда требуется, чтобы пользователи могли добавлять теги к своим собственным личным сообщениям, при этом вы не хотите, чтобы они могли добавлять теги к публичным темам (например, как в этом случае: Private template permissions to override allowed PM tagging groups), то есть когда pm_tags_allowed_for_groups не является подмножеством tag_topic_allowed_groups.

Анализ

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

  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?. Настройки различны.

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

    topic.private_message? ? can_tag_pms? : can_tag_topics?
  end

ListController также удовлетворяется только проверкой can_tag_pms?.

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

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

  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.

  @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.

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

Однако модальное окно Move to Topic не имеет такого ограничения:

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

и ChatToTopicSelector также:

@alias("site.can_tag_pms") canTagMessages;

и UserPrivateMessagesController тоже:

@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 использует tc.guardian.can_tag_topics? вместо tc.guardian.can_tag?(tc.topic).

А в DiscourseTagging

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

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

но tags_for_saving — нет:


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

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

6 лайков