Plugin para mostrar nome completo apenas para usuários do mesmo grupo

Olá a todos,

Estou pesquisando meu problema no Google há algumas semanas e estou quase desistindo.

O contexto:
Eu desenvolvo e mantenho um painel administrativo multi-tenant para clubes esportivos.
Meu fórum Discourse auto-hospedado está disponível apenas para membros desses clubes. Gostaria que ele estivesse aberto ao público. Minha própria integração SSO atribui automaticamente o nome completo dos usuários do meu banco de dados ao usuário do Discourse assim que eles fazem login.

O problema:
No momento, não consigo tornar meu fórum público porque o nome completo de um usuário deve ser visível apenas para usuários do mesmo clube.

Minha experiência como desenvolvedor Ruby é zero (sou desenvolvedor JS), mas até agora consegui entender esta parte do código:

# plugin.rb

after_initialize {
  require_dependency 'basic_user_serializer'
  require_dependency 'current_user'

  class ::BasicUserSerializer
    attributes :name

    def name
      # conjunto fixo de nomes de grupos que indicam pertencimento a um clube
      clubGroups = Array['foo', 'bar', 'baz']
      
      # PARTE QUE NÃO CONSIGO ENTENDER:
      # Mostrar o nome do usuário APENAS se eles compartilharem um dos mesmos `clubGroups` do usuário atualmente logado,
      # ex: estou logado como um usuário que pertence ao grupo 'bar', o que significa que pertenço ao clube Bar. Deveria ser capaz de ver os nomes apenas daqueles usuários que também pertencem ao grupo 'bar'
      ???

    end
  end
}

Não consigo entender as seguintes coisas:

  1. como buscar os grupos do usuário atual
  2. como buscar os grupos do usuário em destaque

Uma vez que eu tenha o acima, poderia comparar os 2 arrays com o clubGroups e decidir se deve mostrar ou não o nome do usuário.

Outro desafio para mim será desativar a possibilidade de editar o próprio nome, mas essa é outra história.

O modelo GroupUser contém a associação de grupos por usuário.

Você deseja algo como: GroupUser.where(user_id: current_user.id) para retornar os IDs dos grupos do usuário atual.

Isso resultará em uma relação Active Record.

Em seguida, você pode querer mapear isso em um array:

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

Siga a mesma abordagem para o seu usuário em destaque.

Perfeito! Obrigado :slight_smile:

Ainda não sei como transformá-lo em uma solução funcional, mas isso já é uma grande dica.

Nunca desista. Apenas continue. :rocket:

Outro obstáculo:

Ao tentar buscar o ID do usuário atual para passar na consulta, não sei muito bem como obtê-lo.
Quando navego até o modelo CurrentUser no código, o único método que parece relevante para meus requisitos é current_user, mas ao fazer isso:

pp CurrentUser.current_user

ele retorna:

undefined method `current_user' for CurrentUser:Module

Acho que estou com certeza perdendo algum conhecimento básico sobre Ruby, mas talvez você possa resolver isso facilmente para mim?

Talvez você queira examinar o código deste plugin. Ele adiciona um distintivo de avatar para pessoas nos mesmos grupos, permitindo que se reconheçam como membros do grupo. Isso é algo diferente, mas contém o código que verifica se o usuário que está visualizando pertence ao mesmo grupo que o usuário que fez a postagem.

A dica aqui é este método:

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

O usuário sendo serializado é o object.

O usuário atual está realmente em scope.user, então:

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

provavelmente funciona para o usuário atual.

etc. etc.

Dicas úteis:

  1. Leia o código-fonte do Discourse
  2. Como sugerido por @RGJ, examine alguns plugins de código aberto para ver como eles fazem as coisas
  3. Prototipe coisas no console do Rails rails c --sandbox

Incrível! Muitas ótimas informações. Obrigado, pessoal :heart_eyes:

Vou mergulhar nisso :dealwithit:

Pelo bem dos futuros visitantes deste tópico, aqui está a solução final que eu encontrei.

Não é perfeita, nem otimizada, mas funciona! E esse é o primeiro e mais importante passo :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: tornar esta lista editável
        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
}