Hallo Werner,
Gegeben sind mir die Gruppen-Ids der Untergruppen von den Gruppen, die Zugriff auf das Modul haben.
Habe ich noch etwas übersehen?
Deine vorgestellte Lösung konnte ich wegen fehlender Parameterwerte nicht nachvollziehen. Im weiteren zeige ich meinen Lösungsvorschlag, der auf meinem Verständnis Deiner Beschreibung basiert.
Ich gehe im folgenden davon aus, dass es genau einen Parameter gibt: die userId des Benutzers, für den wir die Liste der Benutzer sehen wollen, die er administrieren darf (diese ist leer, wenn der Benutzer nicht in einer Gruppe ist, die Zugriff auf die Benutzerverwaltung haben).
a) Liste der echten Untergruppen der Gruppen, in denen sich der Benutzer befindet:
-- Echte Untergruppen haben einen lKey, der größer ist als der lKey
-- der Elterngruppe und kleiner ust als der rKey.
-- Dass Gruppen mehrfach aufgeführt werden, soll uns nicht stören.
-- Erst die Benutzer wollen wir nur noch einfach sehen
SELECT
child.groupId
FROM
groups node
INNER JOIN
groups child
ON
child.lKey > node.lKey AND child.lKey < node.rKey
WHERE
-- wir benötigen die Untergruppen aller Gruppen,
-- in denen sich der Benutzer befindet
node.groupId IN (
SELECT
groupId
FROM
group_user
WHERE
userId = ?
)
Liefert für den userId-Wert 1 (Uwe) als Ergebnis
groupId
-------
2
3
4
5
/*
Komplizierter ist das Ausschlussverfahren:
Hier dürfen nicht einfach alle Vorfahren aller Gruppen
ausgeschlossen werden, in denen sich der Benutzer befindet,
eingeschlossen der Gruppe selbst - sondern nur die Vorfahren
inklusive der Gruppe selbst, die nicht in der Liste der echten
Untergruppen enthalten sind.
Im Beispiel ist Uwe in den Gruppen 1 und 3 enthalten
Vorfahren von 1 ist 1,
Vorfahren von 3 sind 1, 2, 3
Die Vereinigungsmenge aller Vorfahren enthält somit 1, 2, 3
Echte Untergruppen von 1 sind 2, 3, 4, 5
Echte Untergruppen von 3 gibt es nicht
Da 2 und 3 in den echten Untergruppen enthalten sind, entfallen sie
aus der Ausschlussliste:
Ausgeschlossen werden nur die Mitglieder der Gruppe 1
*/
-- Die Vorfahren aller Gruppen (inklusive der Gruppen selbst)
-- eines Benutzers erhält man über
SELECT
ancestor.groupId
FROM
groups node
INNER JOIN
groups ancestor
ON
node.lKey BETWEEN ancestor.lKey AND ancestor.rKey
WHERE
node.groupId IN (
SELECT
groupId
FROM
group_user gu2
WHERE
gu2.userId = ?
)
Liefert für den userId-Wert 1 folgendes Ergebnis
groupId
-------
1
1
2
3
-- Die Vorfahren aller Gruppen ohne die echten Untergruppen ergibt sich somit
-- aus der Kombination:
SELECT
ancestor.groupID
FROM
groups node
INNER JOIN
groups ancestor
ON
node.lKey BETWEEN ancestor.lKey AND ancestor.rKey
WHERE
node.groupId IN (
SELECT
groupId
FROM
group_user gu2
WHERE
gu2.userId = ?
)
AND
node.groupId NOT IN (
SELECT
child.groupID
FROM
groups node
INNER JOIN
groups child
ON
child.lKey > node.lKey AND child.lKey < node.rKey
WHERE
node.groupID IN (
SELECT
groupId
FROM
group_user gu2
WHERE
gu2.userId = ?
)
)
Liefert für Uwe (userId 1) folgendes Ergebnis
groupId
-------
1
Setzen wir es zusammen:
SELECT DISTINCT -- damit jeder Benutzer nur einmal ausgegeben wird
u.userId,
u.name
FROM
user u
INNER JOIN
group_user gu
USING
(userId)
WHERE
-- Benutzer ist in echten Untergrupen enthalten
gu.groupId IN (
SELECT
child.groupId
FROM
groups node
INNER JOIN
groups child
ON
child.lKey > node.lKey AND child.lKey < node.rKey
WHERE
node.groupId IN (
SELECT
groupId
FROM
group_user
WHERE
userId = ?
)
)
AND
-- aber nicht in übergeordneten Gruppen (inklusive dieser selbst)
u.userId NOT IN (
SELECT
gu2.userId
FROM
group_user gu2
WHERE
gu2.groupId IN (
SELECT
ancestor.groupId
FROM
groups node
INNER JOIN
groups ancestor
ON
node.lKey BETWEEN ancestor.lKey AND ancestor.rKey
WHERE
node.groupId IN (
SELECT
groupId
FROM
group_user gu2
WHERE
gu2.userId = ?
)
AND
node.groupId NOT IN (
SELECT
child.groupId
FROM
groups node
INNER JOIN
groups child
ON
child.lKey > node.lKey AND child.lKey < node.rKey
WHERE
node.groupId IN (
SELECT
groupId
FROM
group_user gu2
WHERE
gu2.userId = ?
)
)
)
)
Ergänzen wir noch die Prüfung auf die Mitgliedschaft in einer Gruppe, die für die Benutzerverwaltung berechtigt ist:
AND (
SELECT
(COUNT(groupId) > 0) Admin
FROM
group_user
WHERE
userId = ?
AND
groupId IN (
SELECT
groupId
FROM
module_group
WHERE
moduleId = 1
)
)
-- und sortieren nach Gruppe
ORDER BY
gu.groupId
Ergebisse für die userId-Wert 1 und 2 jeweils:
userId name
-----------
3 Gabi
4 Inge
5 Gerd
6 Sepp
für den userId-Wert 3:
userId name
-----------
4 Inge
und für alle anderen ein leeres Ergebnis - wie gewünscht.
Die Idee mit implizitem Verbot bei gleichzeitigem "Verbot geht über Erlaubnis" kann zu überraschenden Ergebnissen führen: Hinzufügen zu einer weiteren Gruppe in einem anderen Ast kann effektiv zum Verlust von Berechtigungen führen, d.h. zu geringeren Rechten als vorher. Ist das so gewollt oder habe ich das System falsch verstanden?
Bitte beachte: meine Verknüpfungstabellen haben etwas andere Namen als Deine.
Freundliche Grüße
Vinzenz