같은 그룹 사용자만 전체 이름을 볼 수 있는 플러그인

여러분 안녕하세요,

몇 주째 구글링을 하고 있는데 포기할 지경에 이르렀습니다.

배경:
스포츠 클럽을 위한 멀티 테넌트 관리 패널을 개발 및 유지보수하고 있습니다.
셀프 호스팅한 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 모델은 사용자별 그룹 멤버십을 포함합니다.

현재 사용자의 그룹 ID를 반환하는 GroupUser.where(user_id: current_user.id)와 같은 쿼리를 실행하고 싶을 것입니다.

이렇게 하면 Active Record Relation이 반환됩니다.

이후 이를 배열로 변환하기 위해 map을 사용할 수 있습니다:

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

추천 사용자(Featured user)에 대해서도 동일한 접근 방식을 적용하세요.

완벽해요! 감사합니다 :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 c --sandbox를 사용하여 rails 콘솔에서 프로토타입을 만들어보세요.

대단해요! 정말 유익한 정보들이 많네요. 여러분 감사합니다 :heart_eyes:

지금 바로 파고들겠습니다 :dealwithit:

이 주제를 나중에 방문할 분들을 위해, 제가 최종적으로 찾아낸 해결책을 공유합니다.

완벽하지는 않고 최적화도 되지 않았지만 동작합니다! 그리고 그것이 가장 중요한 첫 번째 단계죠 :slight_smile:

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
}