I've been trying to find this answer by myself, but i'm just too bad for that, so i come here hoping you can help me.
I have the following database tables :
user(
int unsigned id,
varchar login
)
group(
int unsigned id,
varchar label
)
right(
int unsigned id,
varchar label
)
user_group(
int unsigned userId,
int unsigned groupId
)
user_right(
int unsigned userId,
int unsigned rightId,
boolean granted
)
group_right(
int unsigned groupId,
int unsigned rightId,
boolean granted
)
And 3 configuration parameters (PHP defines) :
GRANTED_BY_DEFAULT
that can be TRUE
or FALSE
.
It indicates, when a right is not specified for a group or a user (i.e not in the association table), if the right is granted or not.
RESULTING_RIGHTS
that can be MIN_RIGHTS
or MAX_RIGHTS
.
It indicates whether to use "AND" or "OR" operator when determining resulting rights. For exemple, if for right "r1", the group "g1" has TRUE and the groups "g2" and "g3" have FALSE, with "MIN_RIGHTS" you get FALSE, and with "MAX_RIGHTS" you get TRUE.
RIGHTS_PRIORITY
that can be USER_OVER_GROUP
or GROUP_OVER_USER
.
It indicates if the user's own rights override his groups's rights or if the groups's rights override the user's own rights.
I would like to come out with a single query that would find the rights a user effectivly has, considering these 3 parameters and his groups, but i really have no idea about how to do it. I could also make multiple queries and do a part of the work on PHP side, but i would like to avoid having to many queries as i want my app to be fast enough for things like AJAX auto completions and other stuff like that.
I'd understand if no one wants or has the time to help me :p Thanks for reading.
EDIT : Some sample datas :
user (id, login) :
1 "Admin"
group (id, label) :
1 "g1"
2 "g2"
3 "g3"
right (id, label) :
1 "r1"
2 "r2"
3 "r3"
user_group (userId, groupId) :
1 1
1 2
user_right (userId, rightId) :
1 1 true
1 2 false
group_rights (groupId, rightId) :
1 1 true
1 2 false
2 1 false
2 3 true
And the output would be a list of (right_id, right_label) rows depending on the parameters and the rows of other tables.
The user ID and / or login is considered as known when retrieving the rights.
DECLARE @USERID INT = 1,
@GRANTED_BY_DEFAULT INT = 0,
@RESULTING_RIGHTS VARCHAR(20) = 'MIN_RIGHTS',
@RIGHTS_PRIORITY VARCHAR(20) = 'USER_OVER_GROUP'
SELECT
R.ID,
R.NAME,
CASE
WHEN MAX(UR.Value) IS NULL AND MAX(GR.Value) IS NULL THEN
@GRANTED_BY_DEFAULT
WHEN MAX(UR.Value) IS NOT NULL AND MAX(GR.Value) IS NOT NULL THEN
CASE
WHEN @RIGHTS_PRIORITY = 'USER_OVER_GROUP' THEN
MAX(UR.Value)
ELSE
CASE
WHEN @RESULTING_RIGHTS = 'MIN_RIGHTS' THEN
MIN(GR.Value)
ELSE
MAX(GR.Value)
END
END
WHEN MAX(GR.Value) IS NULL THEN
MAX(UR.Value)
ELSE
CASE
WHEN @RESULTING_RIGHTS = 'MIN_RIGHTS' THEN
MIN(GR.Value)
ELSE
MAX(GR.Value)
END
END VALUE
FROM
[Right] R
CROSS JOIN [User] U
LEFT JOIN [User_Right] UR
ON R.ID = UR.RightID
AND UR.UserID = U.ID
LEFT JOIN [User_Group] UG
ON UG.UserID = U.ID
LEFT JOIN [Group_Right] GR
ON UG.GroupID = GR.GroupID
AND GR.RightID = R.ID
WHERE
U.ID = @USERID
GROUP BY
R.ID,
R.NAME
Here is a SQL fiddle example SQL Fiddle