How to remove programmatically all participation of a student in a Moodle 2.5 group? - moodle

I need to remove an user programmatically from everything he is related with a group, like notes and everything. I removed the user from the table mdl_user_enrollments but he's still enrolled and when he logs in all data of the group is still being displayed. I want to remove everything this user has related with the group, so i can enroll he again and he'll start all over.

Don't know if this is exactly what you are looking for but the procedure bellow removes users data from course. Not from all installed moodle modules that will vary for each Moodle configuration) but you can add a few querys for your extra modules as well.
CREATE DEFINER = `your_user`#`%` PROCEDURE `RemoveUserDataFromCourse`(IN `c_id` int,IN `u_id` int)
BEGIN
# ENROLLMENT
DELETE FROM mdl_user_enrolments WHERE userid = u_id AND enrolid IN (SELECT id FROM mdl_enrol WHERE courseid = c_id);
# LOG, EVENT, POSTS
DELETE FROM mdl_log WHERE course = c_id AND userid = u_id;
DELETE FROM mdl_event WHERE courseid = c_id AND userid = u_id;
DELETE FROM mdl_post WHERE courseid = c_id AND userid = u_id;
# Course completion
DELETE FROM mdl_course_modules_completion WHERE coursemoduleid IN (SELECT id FROM mdl_course_modules WHERE course= c_id and userid=u_id);
DELETE FROM mdl_course_completions WHERE course = c_id AND userid = u_id;
DELETE FROM mdl_course_completion_crit_compl WHERE course = c_id AND userid = u_id;
# Grades from all modules
DELETE FROM mdl_grade_grades WHERE userid = u_id and itemid IN (SELECT id FROM mdl_grade_items WHERE courseid = c_id);
# MODULES
# ASSIGNMENTS
DELETE FROM mdl_assign_grades WHERE userid = u_id AND assignment IN (SELECT id FROM mdl_assign WHERE course = c_id);
# QUIZ
DELETE FROM mdl_quiz_attempts WHERE userid = u_id AND quiz IN (SELECT id FROM mdl_quiz WHERE course = c_id);
DELETE FROM mdl_quiz_grades WHERE userid = u_id AND quiz IN (SELECT id FROM mdl_quiz WHERE course = c_id);
# SCORM
DELETE FROM mdl_scorm_scoes_track WHERE userid = u_id AND scormid IN (SELECT id FROM mdl_scorm WHERE course = c_id);
# CHECK LIST
DELETE FROM mdl_checklist_check WHERE userid = u_id AND item IN ( SELECT mci.id FROM mdl_checklist mc INNER JOIN mdl_checklist_item mci ON mci.checklist = mc.id WHERE course = c_id );
DELETE FROM mdl_checklist_comment WHERE userid = u_id AND itemid IN ( SELECT mci.id FROM mdl_checklist mc INNER JOIN mdl_checklist_item mci ON mci.checklist = mc.id WHERE course = c_id );
# CHOICE
DELETE FROM mdl_choice_answers WHERE userid = u_id AND choiceid IN (SELECT id FROM mdl_choice WHERE course = c_id);
END;
This procedure is based on the operations made by course/reset.php it receives two parameters: the course id and the user id. Add/remove the modules related querys depending on you Moodle configuration.

Related

Row-level-security dual join

I have three tables
journeys
id
user_id
...
sections
id
journey_id
...
stops
id
section_id
...
I want to use row level security to make sure that a user can only insert a stop if the uid() matches the user_id on the journey that is referenced by the stop via stops.section_id->sections.journey_id->journeys.user_id.
In other words, the user should only be able to set stops.section_id to a section and thus to a journey that belongs to him.
How can I achieve this in Supabase with row level security joins?
You can use an EXISTS condition:
CREATE POLICY may_insert_stop ON stops
FOR INSERT TO PUBLIC
WITH CHECK (EXISTS (SELECT 1
FROM journeys AS j
JOIN sections AS s ON s.journey_id = j.id
WHERE s.id = stops.section_id
AND j.user_id = uid()
)
);

Join two postgresql queries

I have the following query
SELECT role_uuid FROM users WHERE email = 'email#domain.com'
I also have a roles table the following fields:
uuid
name
created_at
I'm hoping to have 1 query that gives lets me select the role by email and get the name and created_at field from the roles table.
I've tried things like this but I can't quite figure it out.
SELECT *
FROM ( SELECT * FROM users WHERE email = 'email#domain.com') AS A
JOIN ( SELECT * FROM roles WHERE uuid = A.role_uuid) AS B
WHERE A.role_uuid = B.uuid
You JOIN the two tables which gives you a table with all the fields from both source tables. Then you use WHERE to filter and SELECT to specify the fields that you want to be returned.
SELECT r.name, r.created_at
FROM users u JOIN roles r ON (u.role_uuid = r.uuid)
WHERE u.email = 'email#domain.com'
If you run into naming conflicts because of fields from both tables sharing the same name you can use AS to define fieldnames for the output columns:
SELECT r.name AS rolename, u.name AS username, r.created_at
FROM users u JOIN roles r ON (u.role_uuid = r.uuid)
WHERE u.email = 'email#domain.com'

Find Missing Values Between 3 Tables

I have 3 tables: Permissions, Roles, and RolePermissions. I would like to have a way to select Roles that are missing new rows in the Permissions table based on the RolePermissions table relationship to insert those values once new permissions are added.
I have had no luck finding how this can be done so that is why I'm asking here.
Table structure
Permissions | Roles | RolePermissions
------------------------------------------
Id | Id | Id
Name | Name | RoleId
| | PermissionId
Idea of sql but I know it's not correct:
-- Looking to be able to do something like
INSERT INTO RolePermissions (RoleId, PermissionId)
SELECT missingpermissions.PermissionId, missingpermissions.RoleId
FROM Permissions as p
INNER JOIN(
Select r.Id as RoleId, p.Id as PermissionId
FROM Role as r
LEFT JOIN RolePermissions as rp
ON r.Id = rp.RoleId
WHERE rp.PermissionId = p.Id
) as missingpermissions
ON p.id = missingpermissions.permissionid
Edited to format
You need to get your new permission and cross join all roles (to get all combinations of roles and new permissions).
INSERT INTO RolePermissions(RoleId, PermissionId)
SELECT r.ID AS RoleId,p.ID AS PermissionId
FROM Role r
CROSS JOIN (
--get all permissions currently not assigned to a role (presumably "new")
select p.*
from Permissions p
left join RolePermissions rp on p.id=rp.PermissionId
where rp.PermissionId is null
) p

Join four tables using Entity Framework

I have 4 tables:
User:
User_id
List item
User_Name
Company_id
Depart_id
Group_id
Company:
Company_id
Company_Name
Depart:
Depart_id
Depart_Name
Group:
Group_id
Group_Name
I use Entity Framework, how can I get User information:
User_id
User_Name
Company_Name
Depart_Name
Group_Name
Like this:
var va = from vx in dbContex.User
join vy in dbContext.Company
on vx.CompanyId equals vy.Company_id
into a
from b in a
select new {
vx.User_id,
vx.User_Name,
CompanyName = b.Company_Name
};
One solution could be:
var detailedUserInformations = (from u in dbContext.User
join c in dbContext.Company on u.Company_id equals c.Company_id
join d in dbContext.Depart on u.Depart_id equals d.Depart_id
join g in dbContext.Group on u.Group_id equals d.Group_id
select new
{
UserId = u.User_id,
UserName = u.User_Name
CompanyName = c.Company_id,
DepartName = d.Depart_Name,
GroupName = g.Group_Name
}).ToArray();
You have to check if a .Distinct() makes sense before you will project (.ToArray()) your selection.

PostgreSQL join to most recent record between tables

I have two tables pertaining to this question: conversations has many messages. The basic structure (with just the relevant columns) is as follows:
conversations (
int id (PK)
)
create table conversation_participants (
int id (PK),
int conversation_id (FK conversations),
int user_id (FK users),
unique key on [conversation_id, profile_id]
)
create table messages (
int id (PK),
int conversation_id (FK conversations),
int sender_id (FK users),
int recipient_id (FK users),
text body
)
For each conversations entry, given a user_id I want to receive:
all conversations that user participated in (i.e.: conversations.*)
joined to the most recent matching message (i.e.: order by messages.id desc limit 1)
conversations ordered by their most recent message id (i.e.: order by messages.id desc)
Unfortunately, all the query help I can seem to find on anything like this pertains to MySQL, and that doesn't work in PostgreSQL. The closest thing I found is this answer on StackOverflow that gives an example of the select distinct on (...) syntax. However, unless I'm just doing it wrong, I can't seem to get the results ordered in the correct way given the grouping constraints I need with that method.
All information is in the table "messages", you don't need the other tables:
SELECT
id,
body,
c.* -- content from conversations
FROM messages
JOIN
(SELECT MAX(id) AS id, conversation_id
FROM messages
WHERE 1 IN(sender_id, recipient_id) -- the number is the userid, should be dynamic
GROUP BY conversation_id) sub
USING(id, conversation_id)
JOIN conversations c ON c.id = messages.conversation_id
ORDER BY
id DESC;
Edit: Just JOIN on "conversations" to get the data needed from this table.
Try this:
select
*
from
conversation_participants cp
join conversations c on
c.id = cp.conversation_id
-- assuming you only want the conversations where a
-- message has been left. otherwise use left join
join messages m on
m.conversation_id = cp.conversation_id
and m.id = (
select
id
from
messages _m
where
_m.conversation_id = m.conversation_id
and sender_id = 1
order by
id desc
limit 1
)
where
cp.user_id = 1
order by
m.id desc;