Plugin pour afficher le nom complet uniquement aux utilisateurs du même groupe

Bonjour à tous,

Je cherche une solution à mon problème sur Google depuis quelques semaines et je suis presque prêt à abandonner.

Contexte :
Je développe et maintiens un panneau d’administration multi-locataires pour des clubs sportifs.
Mon forum Discourse auto-hébergé n’est actuellement accessible qu’aux membres de ces clubs. Je souhaiterais le rendre accessible au public. Ma propre intégration SSO attribue automatiquement le nom complet des utilisateurs depuis ma base de données à l’utilisateur Discourse dès la connexion.

Problème :
Actuellement, je ne peux pas rendre mon forum public car le nom complet d’un utilisateur ne doit être visible que par les utilisateurs du même club.

Je n’ai aucune expérience en Ruby (je suis développeur JS), mais j’ai jusqu’ici identifié cette partie du code :

# plugin.rb

after_initialize {
  require_dependency 'basic_user_serializer'
  require_dependency 'current_user'

  class ::BasicUserSerializer
    attributes :name

    def name
      # ensemble fixe de noms de groupes indiquant l'appartenance à un club
      clubGroups = Array['foo', 'bar', 'baz']
      
      # PARTIE QUE JE N'ARRIVE PAS À DÉCRYPTER :
      # Afficher le nom de l'utilisateur UNIQUEMENT s'il partage l'un des mêmes `clubGroups` que l'utilisateur actuellement connecté,
      # par exemple : je suis connecté en tant qu'utilisateur appartenant au groupe 'bar', ce qui signifie que j'appartiens au club Bar. Je ne devrais pouvoir voir les noms que des utilisateurs appartenant également au groupe 'bar'.
      ???

    end
  end
}

Je n’arrive pas à comprendre les points suivants :

  1. Comment récupérer les groupes de l’utilisateur actuel ?
  2. Comment récupérer les groupes de l’utilisateur concerné ?

Une fois ces informations obtenues, je pourrais comparer les deux tableaux avec clubGroups et décider d’afficher ou non le nom de l’utilisateur.

Un autre défi pour moi sera de désactiver la possibilité de modifier son propre nom, mais c’est une autre histoire.

1 « J'aime »

Le modèle GroupUser contient l’appartenance au groupe par utilisateur.

Vous souhaitez quelque chose comme : GroupUser.where(user_id: current_user.id) pour retourner les identifiants de groupe de l’utilisateur actuel.

Cela vous donnera une relation Active Record.

Ensuite, vous voudrez peut-être la map en un tableau :

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

Suivez la même approche pour votre utilisateur en vedette.

1 « J'aime »

Parfait ! Merci :slight_smile:

Je ne sais pas encore comment transformer cela en une solution fonctionnelle, mais c’est déjà un indice majeur.

1 « J'aime »

Ne lâchez jamais. Continuez simplement d’avancer. :rocket:

1 « J'aime »

Un autre obstacle :

Lorsque j’essaie de récupérer l’ID de l’utilisateur actuel pour le passer à la requête, je ne sais pas vraiment comment faire.
Lorsque je navigue vers le modèle CurrentUser dans le code, la seule méthode qui semble correspondre à mes besoins est current_user, mais quand j’exécute ceci :

pp CurrentUser.current_user

j’obtiens l’erreur suivante :

undefined method `current_user' for CurrentUser:Module

Je pense que je manque clairement de connaissances de base en Ruby ici, mais peut-être pouvez-vous facilement résoudre ce problème pour moi ?

Vous voudrez peut-être examiner le code de ce plugin. Il ajoute un insigne d’avatar pour les personnes appartenant aux mêmes groupes, afin qu’elles puissent se reconnaître en tant que membres du groupe. C’est une fonctionnalité différente, mais le code contient bien la vérification pour déterminer si l’utilisateur qui consulte le message appartient au même groupe que l’utilisateur qui a publié.

1 « J'aime »

L’indice ici est cette méthode :

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

L’utilisateur en cours de sérialisation est object.

L’utilisateur actuel se trouve en réalité dans scope.user, donc :

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

fonctionne probablement pour l’utilisateur actuel.

etc. etc.

Conseils utiles :

  1. Lisez le code source de Discourse
  2. Comme l’a indiqué @RGJ, examinez plusieurs plugins open source pour voir comment ils procèdent
  3. Testez des prototypes dans la console Rails avec rails c --sandbox

Incroyable ! Plein de superbes connaissances. Merci les gars :heart_eyes:

Je me lance dedans :dealwithit:

1 « J'aime »

Pour le bénéfice des futurs visiteurs de ce sujet, voici la solution finale à laquelle je suis parvenu.

Ce n’est pas parfait, ni optimisé, mais cela fonctionne ! Et c’est la première et la plus importante étape :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: rendre cette liste modifiable
        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 « J'aime »