Find Orphaned Folders using CTE - sql-server

I am trying to create an SQL Syntax to search my database for folders on the network that users can't access.
Let me explain:
My Database has 5 tables:
Table: Folders
FUID - INT - Unique ID
Path - Varchar - Example: E:\shared
STATUS - INT - 1 = good, 0 = stale
Table: Groups
GRUID - INT - Unique ID
Class - varchar - User or Admin Group (admin group being a sysadmin group)
Name - Example HR_Users
STATUS - INT - 1 = good, 0 = stale
Table: Users:
URUID - INT - Unique ID
Class - varchar - Standard User or Admin User (admin user being a sysadmin)
Name - Varchar - Example: Smith, John
STATUS - INT - 1 = good, 0 = stale
Table: UG_JOIN:
UID: Unique ID
GRUID - INT - Relationship to Groups
URUID - INT - Relationship to Users
STATUS - INT - 1 = good, 0 = stale
Table: ACLS:
UID - INT - Unique ID
FUID - INT - Relationship to Folders FUID
GRUID - INT - Relationship to Group GRUID
URUID - INT - Relationship to User URUID
ACCESS - VARCHAR - Type of Access, list, read, modify, full control
STATUS - INT - 1 = good, 0 = stale
The reason I have to have both the users and groups in the ACL table is because some users are directly assigned permissions at the folder, not by group.
Anyway, What I am trying to find out is:
What folders don't have any permissions for standard users
Including the above, I want to be able to filter out by ACCESS, so search for folders where Standard Users don't have Modify Access).
Also want to filter out stale groups, users, UG_Join, folders and acls using the STATUS Column
I'm NOT trying to find what certain users have access to. I don't care about that, what I want is what folders standard users cant access (list, read, modify, full control). I don't expect to see usernames or group names in my result, just paths.
Logically all I can come up with is get all the paths that Admins have access to (which is 100% of the paths) then skip paths that end-users have access two, leaving only paths that only Admins have access to. Any idea on how I would go about this? Thanks!

Please try the query below. It gets all the folders, and then uses all standard users and any standard groups of that user before applying to filter to only show the folders without a standard user or a standard user in a standard group assigned.
SELECT DISTINCT
F.Path
FROM Folders F
INNER JOIN ACLS A
ON A.FUID = F.FUID
LEFT OUTER JOIN (
SELECT
U.URUID,
G.GRUID
FROM Users U
LEFT OUTER JOIN UG_JOIN UG
ON UG.URUID = U.URUID
LEFT OUTER JOIN Groups G
ON G.GRUID = UG.GRUID
AND G.Class = 'User' -- Whatever class needs to be user group
WHERE U.Class = 'Standard User' -- Whatever class neeed to be standard group
-- AND U.STATUS = 1 -- If you only care about active users
) UG
ON (A.URUID = UG.URUID OR A.GRUID = UG.URUID)
WHERE UG.URUID IS NULL

not sure how to combine first and second requirement, so i use Or operator at below, lets me know if i misunderstand u :)
DECLARE #Class NVARCHAR(100) = 'STANDARD USER'
DECLARE #Access NVARCHAR(100) = 'Modify'
SELECT F.[PATH]
FROM Folders F
INNER JOIN ACLS A
ON A.FUID = F.FUID
INNER JOIN Users U
ON U.URUID = A.URUID
INNER JOIN Groups G
ON G.GRUID = A.GRUID
INNER JOIN UG_JOIN UG
ON UG.URUID = U.URUID
INNER JOIN UG_JOIN UG2
ON UG2.GRUID = G.GRUID
WHERE (U.Class != #Class --First requirement : What Folders dont have any permission for standard user
-- means i will filter out standuser
OR (A.Access Not LIKE '%' + #Access + '%'
AND U.Class = #Class)-- second requirement: search for folders where standard users dont have modify access
)
AND F.Status != 0 --Third reqirement : also want to filter out stale group for all the table
AND A.Status != 0
AND U.Status != 0
AND G.Status != 0
AND UG.Status != 0
AND UG2.Status != 0

Related

Teacher representation in Moodle database

I wonder how the instructor is represented in the vast Moodle DB. Where is the specific table with attribute columns to store data for every teacher?
Although there is something relevant like the diagram above, i need something to describe the teacher table.
Any ideas?
picture taken from : http://www.examulator.com/er/
Moodle has the following default archetypes for what you refer to as an instructor;
manager
coursecreator
editingteacher
teacher
A user can be assigned one of these roles in a particular context, a context such as a course or perhaps course category.
The database stores the teacher data across a number of tables. Looking at the database schema diagram you have shown, the tables you are looking for are in the roles grouping. Specifically role and role_assignments. By linking these tables with the user, context and course tables, you can find the staff associated with courses.
An example function to get the staff associated with a particular course would be
function get_course_staff($courseid) {
global $DB;
$sql = "SELECT u.firstname,
u.lastname
FROM {role_assignments} ra
WHERE c.contextlevel = 50 // Numeric value of the course context
AND c.instanceid = ?
AND r.id < 5
JOIN {role} r ON ra.roleid = r.id
JOIN {user} u ON ra.userid = u.id
JOIN {context} c ON ra.contextid = c.id
JOIN {course} co ON c.instanceid = co.id
ORDER BY r.sortorder ASC";
return $DB->get_records_sql($sql, array($courseid));
}
A role can be assigned to many users.
A user can have many roles.
A user is assigned a role in a particular context.

Updating column based on three tables

I know it's very unprofessional, but it's our business system so I can't change it.
I have three tables: t_posList, t_url, t_type. The table t_posList has a column named URL which is also stored in the table t_url (the ID of the table t_url is not saved in t_posList so I have to find it like posList.Url = t_url.Url).
The column t_posList.status of every data row should be updated to 'non-customer' (it will be a status id but lets keep it simple) if: the ID of t_url can NOT be found in t_type.url_id.
So the query has like two steps: first I have to get all of the data rows where t_posList.Url = t_url.Url. After this I have to check which ID's of the found t_url rows can NOT be found in t_type.url_id.
I really hope you know what I mean. Because our system is very unprofessional and my SQL knowledge is not that good I'm not able to make this query.
EDIT: I tried this:
UPDATE t_poslist SET status = (
SELECT 'non-customer'
FROM t_url, t_type
WHERE url in
(select url from t_url
LEFT JOIN t_type ON t_url.ID = t_type.url_id
WHERE t_type.url_id is null)
)
What about this?
UPDATE p
SET status = 'non-customer'
FROM t_poslist p
INNER JOIN t_url u ON u.url = p.url
WHERE NOT EXISTS
(
SELECT * FROM t_type t WHERE t.url_id = u.ID
)

SQL Server: transforming query for materialized path traversing in a view

I would like to transform this query in a view that I can call passing the UserId as a parameter to select all groups (including subtrees of those groups) related to that user.
In fact I have 2 tables:
"EVA_Roles" which contains the roles tree, defined through a materialized path in the RoleHid field as varchar(8000)
"EVA_UsersInRoles" which related users to roles through the field UserId
Problem here is that only some roles may be related to the user in the EVA_UsersInRoles table, but maybe those roles are parents to other roles in the tree hierarchy so I have to retrieve multiple subtrees for each user.
Finally I came up with this query which seems to work fine, but I would like to transform it in a View. The problem I'm facing of course is that the UserId parameter, which is the one I would use to filter the view results, is inside the subquery.
Any hint to refactor this into a view?
SELECT A.RoleId, E.EndDate FROM EVA_Roles A INNER JOIN EVA_Roles B ON
A.RoleHid LIKE B.RoleHid + '%' AND B.RoleHid IN (SELECT RoleHid FROM EVA_Roles C
LEFT JOIN EVA_UsersInRoles D ON C.RoleId = D.RoleId WHERE
(D.Userid = #0 OR C.RoleId = #1) AND C.ApplicationId = #2)
LEFT JOIN EVA_UsersInRoles E ON A.RoleId = E.RoleId AND E.UserId = #0 WHERE
A.ApplicationId = #2 ORDER BY A.RoleId
I left parameters where I should pass values to the view. I think it may be impossible to refactor in a view. It was just to exploit my micro-ORM (PetaPoco) in a more friendly way, otherwise I have to use the SQL in my code but it's ok, don't loose your mind on this.
About the tables definition:
EVA_Roles
RoleId INT - Primary Key
RoleHid VARCHAR(800) - Here I store the materialized path of the tree using nodes
ids... An example on this later.
RoleLevel INT - Security level of the role
RoleName INT - Name of the role (admin, guest, ...)
ApplicationID INT - Id of the application (in a multi app scenario)
EVA_UsersInRoles
RoleId - INT
UserId - INT
The materialized path in RoleHid follows this logic. Consider this data where RoleId 2 is child of RoleId 1:
RoleId 1
RoleHid "1."
RoleId 2
RoleHid "1.2."
With the query above I'm able to retrieve all subtrees tied to a specific user and application.

SQL Server : Storing Hierarchical ACL Data

I would like implement a database containing hierarchical acl data
My tables
USERS: idUser,username,...
GROUPS: idGroups,name...
GROUPSENTITIES: idGroup, idChild, childType (1 for users, 2 from groups)
ROLES : idRole,name...
ROLESENTITIES: idRole, IsDeny, idChild, childType (1 for users, 2 from groups)
Every user can belong to 0 or more groups
Every group can belong to 0 or more groups
Every user and every group can belong to 0 or more roles and roles can be allowed or denied
If an explicit deny is found, role is denied
How can I store this kind of data? Is my design correct?
Is it possible retrieve a list of users with all allowed roles?
Can you please write me a query (T-SQL based) for extract this information from db
thanks in advance
You can write the tables as you would expect. For instance, to get all the users in a group, when there are hierarchical groups, you would use a recursive CTE. Assume the group table is set up as:
create table groups (
groupid int,
member_userId int,
member_groupid int,
check (member_userId is NULL or member_groupid is null)
);
with usergroups as (
select groupid, member_userid, 1 as level
from groups
union all
select g.groupid, users.member_userid, 1+level
from users u join
groups g
on u.member_groupid = g.groupid
)
select *
from usergroups;

Sphinx Search Engine using with an access rights table

I want to check while searching through sphinx index the read-permission of user who is looking for some documents.
For examle i have an documents table with doc_id, doc_title and doc_is_global. On other side i have an accessprivileges table with an structure like:
user_id, user_group_id, doc_id, doc_category_id
users can grouped in an "user_group" with identifier user_group_id, and documents equivalent into document_categories.
The Access Table could look like:
user_id, user_group_id, doc_id, doc_category_id
1 , NULL, 1, NULL
NULL, 12, NULL, 32
1, NULL, NULL, 31
NULL, 10, 1, NULL
A user should only find documents where is_global flag is set to 1 or he has access by his user_id, or by a group_id he is member of.
In plain MySQL I get the right result by some JOINs Like:
SELECT * from documents d
LEFT JOIN document_category dc ON dc.doc_id = d.doc_id
LEFT JOIN access a ON a.user_id = {$user} and a.doc_id = d.doc_id
LEFT JOIN access a ON a.category_id = dc.category_id and dc.group_id IN ({$groups})
[...]
In Sphinx, I know, I can put multiple attributes to an indexed document but that are not what i want. In my productive envirenment i have also to check which user has given the read access and only if he can do that, the user becomes the access to read.
Made that situation with multiple attributes using sphinx it returns something like:
access_user_id = (1,4,6,2) accessed_by_user = (1,5,3)
so there aren't possibilities to check who gave read permission to who. Next problem is that Sphinx only supports max. 4gb attributes per index.
I need some hint for an idea to build the index to filter out the results the user isn't allowed to see (maybe with multiple indexes?)
Well you can index this with
sql_query =
SELECT d.doc_id, ...
GROUP_CONCAT(a.user_id) AS access_user_id,
GROUP_CONCAT(a.user_group_id) AS access_user_group_id
FROM documents d
LEFT JOIN document_category dc ON (dc.doc_id = d.doc_id)
LEFT JOIN access a ON (a.doc_id = d.doc_id OR a.doc_category_id = dc.category_id)
GROUP BY doc_id
Then can filter on that
$cl->setSelect("*, IF(IN({$user},access_user_id),1,0)+IF(IN({$group},access_user_group_id),1,0) AS myint");
$cl->setFilter('myint',array(1,2));
Next problem is that Sphinx only supports max. 4gb attributes per index.
Sphinx only supports 4gb of string attributes per index. Are you sure there is such a limit on MVA attributes?
In anycase, if too many attributes - the limit is per index. So shard the index to parts :)
As running into issues with max-length in GROUP CONCAT, easiest would probabyl be to use a MVA query.
See the docs for it http://sphinxsearch.com/docs/current.html#conf-sql-attr-multi
In there can define a query to fetch the data for the MVA directly, avoids the use of GROUP_CONCAT/GROUP_BY
sql_query = SELECT d.doc_id, ... FROM documents d
sql_attr_multi = uint access_user_id from query; SELECT DISTINCT doc_id, a.user_id FROM documents d
LEFT JOIN document_category dc ON (dc.doc_id = d.doc_id)
LEFT JOIN access a ON (a.doc_id = d.doc_id OR a.doc_category_id = dc.category_id)
sql_attr_multi = uint access_user_group_id from query; SELECT DISTINCT doc_id, a.user_group_id FROM documents d
LEFT JOIN document_category dc ON (dc.doc_id = d.doc_id)
LEFT JOIN access a ON (a.doc_id = d.doc_id OR a.doc_category_id = dc.category_id)
(can probably optimise those queries a bit, but at least should show how enough to get started)

Resources