@@ -50,7 +50,7 @@ public function __construct(string $filter = '')
5050
5151 $ this ->addAvailableFilters ([
5252 new TextFilter ('subject ' , 'wcf.global.title ' ),
53- new UserFilter ( ' participants ' , ' wcf.conversation.participants ' ),
53+ ... $ this -> getParticipantFilter ( $ filter ),
5454 $ this ->getLabelFilter (),
5555 ]);
5656
@@ -87,6 +87,69 @@ public function getParameters(): array
8787 return ['filter ' => $ this ->filter ];
8888 }
8989
90+ /**
91+ * @return AbstractFilter[]
92+ */
93+ private function getParticipantFilter (string $ filter ): array
94+ {
95+ // Participants in draft conversations are not yet stored in the `wcf1_conversation_to_user` table,
96+ // they are serialized in `draftData`.
97+ if ($ filter === 'draft ' ) {
98+ return [];
99+ }
100+
101+ return [
102+ new class (id: 'participants ' , languageItem: 'wcf.conversation.participants ' ) extends UserFilter {
103+ #[\Override]
104+ public function applyFilter (DatabaseObjectList $ list , string $ value ): void
105+ {
106+ // The condition is split into two branches in order to account for invisible participants.
107+ // Invisible participants are only visible to the conversation starter and remain invisible
108+ // until they write their first message.
109+ //
110+ // We need to protect these users from being exposed as participants by including them for
111+ // any conversation that the current user has started. For all other conversations, users
112+ // flagged with `isInvisible = 0` must be excluded.
113+ //
114+ // See https://github.com/WoltLab/com.woltlab.wcf.conversation/issues/131
115+
116+ $ list ->getConditionBuilder ()->add (
117+ "(
118+ (
119+ conversation.userID = ?
120+ AND conversation.conversationID IN (
121+ SELECT conversationID
122+ FROM wcf1_conversation_to_user
123+ WHERE participantID = ?
124+ )
125+ )
126+ OR
127+ (
128+ conversation.userID <> ?
129+ AND conversation.conversationID IN (
130+ SELECT conversationID
131+ FROM wcf1_conversation_to_user
132+ WHERE participantID = ?
133+ AND isInvisible = ?
134+ )
135+ )
136+ ) " ,
137+ [
138+ // Parameters for the first condition.
139+ WCF ::getUser ()->userID ,
140+ $ value ,
141+
142+ // Parameters for the second condition.
143+ WCF ::getUser ()->userID ,
144+ $ value ,
145+ 0 ,
146+ ]
147+ );
148+ }
149+ },
150+ ];
151+ }
152+
90153 private function getLabelFilter (): AbstractFilter
91154 {
92155 return new class extends AbstractFilter {
0 commit comments