仅向同一组的用户显示全名的插件

大家好,

我已经为自己的问题搜索了好几个星期,现在几乎要放弃了。

背景:
我正在开发并维护一个面向体育俱乐部的多租户管理面板。
我的自托管 Discourse 论坛目前仅对俱乐部成员开放,但我希望将其改为公开访问。我自己的 SSO 集成会在用户登录后,自动将数据库中用户的完整姓名同步到 Discourse 用户中。

问题:
目前我无法将论坛设为公开,因为用户的完整姓名应当仅对同一俱乐部的用户可见。

作为一名 Ruby 开发者,我的经验为零(我是一名 JS 开发者),但到目前为止,我已经弄懂了以下代码部分:

# plugin.rb

after_initialize {
  require_dependency 'basic_user_serializer'
  require_dependency 'current_user'

  class ::BasicUserSerializer
    attributes :name

    def name
      # 表示属于某个俱乐部的固定组名集合
      clubGroups = Array['foo', 'bar', 'baz']
      
      # 我无法弄明白的部分:
      # 仅当目标用户与当前登录用户共享同一个 clubGroups 时,才显示该用户的姓名,
      # 例如:我作为属于 'bar' 组的用户登录,意味着我属于 Bar 俱乐部。我应该只能看到同样属于 'bar' 组的用户的姓名
      ???

    end
  end
}

我无法弄明白以下两点:

  1. 如何获取当前用户的所属组
  2. 如何获取目标用户的所属组

一旦我有了上述信息,我就可以将这两个数组与 clubGroups 进行比较,从而决定是否显示该用户的姓名。

另一个对我来说具有挑战性的任务是关闭用户编辑自己姓名的功能,但那是另一回事了。

GroupUser 模型包含用户所属的群组关系。

您可以使用类似 GroupUser.where(user_id: current_user.id) 的查询来获取当前用户所属的群组 ID。

这将返回一个 Active Record 关联对象。

然后,您可以将其 map 为数组:

GroupUser.where(user_id: myuser.id).map {|gu| gu.group_id}

对您的精选用户采用相同的处理方式。

完美!谢谢 :slight_smile:

我目前还不知道如何将其转化为可行的解决方案,但这已经是一个重要的提示。

永不放弃。继续前行。:rocket:

另一个障碍:

在尝试获取当前用户的 ID 以传递给查询时,我不太清楚该如何获取。
当我导航到代码中的 CurrentUser 模型时,唯一看起来与我的需求相关的方法是 current_user,但当我执行以下操作时:

pp CurrentUser.current_user

它会报错:

undefined method `current_user' for CurrentUser:Module

我想我肯定缺少一些关于 Ruby 的基础知识,但也许你能轻松帮我解决这个问题?

您可能想查看此插件的代码。它能为同一群组中的成员添加头像标识,以便他们能够识别彼此为群组成员。这虽然有所不同,但其中确实包含了检查查看用户是否与发帖用户属于同一群组的代码。

这里的线索是这个方法:

  def user_is_current_user
    object.id == scope.user&.id
  end

被序列化的用户是 object

当前用户实际上在 scope.user 中,因此:

GroupUser.where(user_id: scope.user&.id).map {|gu| gu.group_id}

可能对当前用户有效。

等等。

一些有用的提示:

  1. 阅读 Discourse 源代码
  2. 按照 @RGJ 的建议,查看一些开源插件,看看它们是如何实现功能的
  3. 在 Rails 控制台中进行原型设计 rails c --sandbox

太棒了!有很多有用的知识。谢谢大家 :heart_eyes:

我要开始深入研究了 :dealwithit:

为了将来访问此主题的访客,以下是我最终得出的解决方案。

它并不完美,也没有经过优化,但能正常工作!这是第一步,也是最重要的一步 :wink:

after_initialize {
  require_dependency 'basic_user_serializer'

  class ::BasicUserSerializer
    attributes :name

    def name
      if user_is_current_user
        return _old_name_method
      else
        # TODO: 使此列表可编辑
        clubGroups = Array['...']

        if scope.user
          ownGroups = GroupUser.where(user_id: scope.user.id)
                               .map { |gu| gu.group_id }
                               .map { |group_id| Group.find_by(id: group_id) }
                               .filter { |group| clubGroups.include? group.name }

          if ownGroups.length > 0
            ownGroupsIds = ownGroups.map { |g| g.id }

            if GroupUser.exists?(user_id: user.id, group_id: ownGroupsIds)
              return _old_name_method
            end
          end
        end
      end

      return ''
    end

    private def _old_name_method
      return Hash === user ? user[:name] : user.try(:name)
    end
  end
}