Plugin para mostrar el nombre completo solo a usuarios del mismo grupo

Hola a todos,

Llevo varias semanas buscando mi problema en Google y estoy muy cerca de rendirme.

El contexto:
Desarrollo y mantengo un panel de administración multiinquilino para clubes deportivos.
Mi foro de Discourse autoalojado solo está disponible para los miembros de esos clubes. Me gustaría que estuviera abierto al público. Mi propia integración SSO asigna automáticamente el nombre completo de los usuarios desde mi base de datos al usuario de Discourse una vez que han iniciado sesión.

El problema:
Actualmente no puedo hacer que mi foro sea público porque el nombre completo de un usuario solo debe ser visible para los usuarios del mismo club.

Mi experiencia como desarrollador Ruby es nula (soy desarrollador JS), pero hasta ahora he logrado identificar esta parte del código:

# plugin.rb

after_initialize {
  require_dependency 'basic_user_serializer'
  require_dependency 'current_user'

  class ::BasicUserSerializer
    attributes :name

    def name
      # conjunto fijo de nombres de grupos que indican pertenencia a un club
      clubGroups = Array['foo', 'bar', 'baz']
      
      # PARTE QUE NO PUEDO RESOLVER:
      # Mostrar el nombre del usuario SOLO si comparten uno de los mismos `clubGroups` del usuario actualmente conectado,
      # por ejemplo, estoy conectado como un usuario que pertenece al grupo 'bar', lo que significa que pertenezco al club Bar. Debería poder ver los nombres solo de aquellos usuarios que también pertenecen al grupo 'bar'
      ???

    end
  end
}

No logro resolver lo siguiente:

  1. cómo obtener los grupos del usuario actual
  2. cómo obtener los grupos del usuario destacado

Una vez que tenga lo anterior, podría comparar los dos arrays con clubGroups y decidir si mostrar o no el nombre del usuario.

Otro desafío para mí será desactivar la posibilidad de editar el propio nombre, pero esa es otra historia.

1 me gusta

El modelo GroupUser contiene la membresía de grupo por usuario.

Deseas algo como: GroupUser.where(user_id: current_user.id) para obtener los IDs de grupo del usuario actual.

Esto te devolverá una relación de Active Record.

Luego, podrías querer mapearla en un array:

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

Sigue el mismo enfoque para tu usuario destacado.

1 me gusta

¡Perfecto! Gracias :slight_smile:

Aún no sé cómo convertirlo en una solución funcional, pero eso ya es una pista importante.

1 me gusta

Nunca te rindas. Sigue adelante. :rocket:

1 me gusta

Otro obstáculo:

Al intentar obtener el ID del usuario actual para pasarlo a la consulta, no tengo muy claro cómo hacerlo.
Cuando navego al modelo CurrentUser en el código, el único método que parece relevante para mis necesidades es current_user, pero al ejecutar esto:

pp CurrentUser.current_user

recibo el siguiente error:

undefined method `current_user' for CurrentUser:Module

Creo que me falta algún conocimiento básico sobre Ruby, pero quizás puedas ayudarme a resolverlo fácilmente.

Quizás quieras revisar el código de este plugin. Agrega un distintivo de avatar para personas en los mismos grupos, de modo que puedan reconocerse como miembros del grupo. Es algo diferente, pero sí contiene el código que verifica si el usuario que ve la publicación está en el mismo grupo que el usuario que la publicó.

1 me gusta

La pista aquí es este método:

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

El usuario que se está serializando es object.

El usuario actual en realidad está en scope.user, por lo que:

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

probablemente funcione para el usuario actual.

etc., etc.

Consejos útiles:

  1. Lee el código fuente de Discourse.
  2. Como mencionó @RGJ, revisa algunos plugins de código abierto para ver cómo lo hacen.
  3. Prototipa cosas en la consola de Rails: rails c --sandbox.

¡Increíble! Mucho conocimiento genial. Gracias, chicos :heart_eyes:

Me estoy zambullendo en ello :dealwithit:

1 me gusta

Por el bien de los futuros visitantes de este tema, aquí está la solución final a la que llegué.

No es perfecta ni optimizada, ¡pero funciona! Y ese es el primer y más importante paso :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: hacer esta lista editable
        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
}
2 Me gusta