Skip to content

SAK-51713 Tests & Quizzes Instructors should see all student submissions when a assessment is published to the entire site#278

Open
st-manu wants to merge 1 commit intosakaiproject:masterfrom
st-manu:SAK-51713
Open

SAK-51713 Tests & Quizzes Instructors should see all student submissions when a assessment is published to the entire site#278
st-manu wants to merge 1 commit intosakaiproject:masterfrom
st-manu:SAK-51713

Conversation

@st-manu
Copy link
Contributor

@st-manu st-manu commented Dec 10, 2025

https://sakaiproject.atlassian.net/browse/SAK-51713

Summary by CodeRabbit

  • Chores
    • Updated database migration scripts for version 25.1 to 25.2 compatibility, including configuration of assessment permissions across supported database systems.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 10, 2025

Walkthrough

Adds database migration scripts for Sakai 25.1 to 25.2 supporting MySQL and Oracle. Introduces 'assessment.all.groups' permission and uses temporary tables to map roles to functions, applying permissions across realms while preventing duplicates via NOT EXISTS clauses.

Changes

Cohort / File(s) Change Summary
Sakai 25.1–25.2 Database Migrations
docs/conversion/sakai_25_1-25_2_mysql_conversion.sql, docs/conversion/sakai_25_1-25_2_oracle_conversion.sql
Adds migration logic (SAK-51713) to define the 'assessment.all.groups' function and grant it across Sakai realms. Uses temporary tables (PERMISSIONS_SRC_TEMP, PERMISSIONS_TEMP) to map roles to the function, populates mappings, and inserts into SAKAI_REALM_RL_FN with deduplication logic. Excludes helper and template realms, then cleans up temporary artifacts.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly reflects the main change: adding the assessment.all.groups permission to enable instructors to see all student submissions when assessments are published site-wide.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 50294e1 and 2022b6f.

📒 Files selected for processing (2)
  • docs/conversion/sakai_26_mysql_conversion.sql (1 hunks)
  • docs/conversion/sakai_26_oracle_conversion.sql (1 hunks)

…ons when a assessment is published to the entire site
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
docs/conversion/sakai_25_1-25_2_mysql_conversion.sql (1)

8-8: Temporary table operations lack defensive guards.

CREATE TABLE will fail if tables already exist from a partial previous run, and DROP TABLE will fail if tables were never created. Adding defensive guards improves script resilience.

🔎 Suggested fix:
 -- Add this to populate existing sites with the permission
+DROP TABLE IF EXISTS PERMISSIONS_SRC_TEMP;
 CREATE TABLE PERMISSIONS_SRC_TEMP (ROLE_NAME VARCHAR(99), FUNCTION_NAME VARCHAR(99));
+DROP TABLE IF EXISTS PERMISSIONS_TEMP;
 CREATE TABLE PERMISSIONS_TEMP (ROLE_KEY INTEGER, FUNCTION_KEY INTEGER);
-DROP TABLE PERMISSIONS_TEMP;
-DROP TABLE PERMISSIONS_SRC_TEMP;
+DROP TABLE IF EXISTS PERMISSIONS_TEMP;
+DROP TABLE IF EXISTS PERMISSIONS_SRC_TEMP;

Also applies to: 12-12, 32-33

docs/conversion/sakai_25_1-25_2_oracle_conversion.sql (1)

16-16: Temporary table operations may fail on partial re-runs.

Oracle's CREATE TABLE fails if the table exists, and DROP TABLE fails if it doesn't. For robustness, consider dropping before creating. In Oracle 12.2+, you can use the PRIVATE TEMPORARY TABLE feature, or for older versions, add a preceding drop with exception handling.

🔎 Simpler approach - drop before create:
 -- Add this to populate existing sites with the permission
+BEGIN EXECUTE IMMEDIATE 'DROP TABLE PERMISSIONS_SRC_TEMP'; EXCEPTION WHEN OTHERS THEN NULL; END;
+/
 CREATE TABLE PERMISSIONS_SRC_TEMP (ROLE_NAME VARCHAR(99), FUNCTION_NAME VARCHAR(99));
+BEGIN EXECUTE IMMEDIATE 'DROP TABLE PERMISSIONS_TEMP'; EXCEPTION WHEN OTHERS THEN NULL; END;
+/
 CREATE TABLE PERMISSIONS_TEMP (ROLE_KEY INTEGER, FUNCTION_KEY INTEGER);

Or at the end:

-DROP TABLE PERMISSIONS_TEMP;
-DROP TABLE PERMISSIONS_SRC_TEMP;
+BEGIN EXECUTE IMMEDIATE 'DROP TABLE PERMISSIONS_TEMP'; EXCEPTION WHEN OTHERS THEN NULL; END;
+/
+BEGIN EXECUTE IMMEDIATE 'DROP TABLE PERMISSIONS_SRC_TEMP'; EXCEPTION WHEN OTHERS THEN NULL; END;
+/

Also applies to: 20-20, 41-42

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2022b6f and 50f0d20.

📒 Files selected for processing (2)
  • docs/conversion/sakai_25_1-25_2_mysql_conversion.sql (1 hunks)
  • docs/conversion/sakai_25_1-25_2_oracle_conversion.sql (1 hunks)
🔇 Additional comments (3)
docs/conversion/sakai_25_1-25_2_mysql_conversion.sql (1)

19-30: LGTM!

The bulk insert logic correctly uses NOT EXISTS for idempotency and appropriately excludes helper and user template realms. The join strategy to propagate permissions to existing realms is sound.

docs/conversion/sakai_25_1-25_2_oracle_conversion.sql (2)

3-11: LGTM!

The MERGE statement properly handles idempotent insertion of the function, avoiding errors on re-run. This is the correct Oracle pattern for "insert if not exists".


27-39: LGTM!

The bulk insert logic is correct and idempotent. The NOT EXISTS clause prevents duplicates, and the realm exclusions are appropriate.

Comment on lines +5 to +6
INSERT INTO SAKAI_REALM_RL_FN VALUES((select REALM_KEY from SAKAI_REALM where REALM_ID = '!site.template'), (select ROLE_KEY from SAKAI_REALM_ROLE where ROLE_NAME = 'maintain'), (select FUNCTION_KEY from SAKAI_REALM_FUNCTION where FUNCTION_NAME = 'assessment.all.groups'));
INSERT INTO SAKAI_REALM_RL_FN VALUES((select REALM_KEY from SAKAI_REALM where REALM_ID = '!site.template.course'), (select ROLE_KEY from SAKAI_REALM_ROLE where ROLE_NAME = 'Instructor'), (select FUNCTION_KEY from SAKAI_REALM_FUNCTION where FUNCTION_NAME = 'assessment.all.groups'));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Template inserts lack idempotency and may fail on re-run.

These direct INSERT statements will fail with a duplicate key error if the script runs a second time (or if the permission already exists). Additionally, if any subquery returns NULL (e.g., role or realm not found), the insert will either fail or insert invalid data.

Consider using INSERT IGNORE or wrapping with a NOT EXISTS check to match the idempotent pattern used in the bulk insert below.

🔎 Suggested fix using INSERT IGNORE:
 -- Add this for every role able to create and manage conditions on a site, you'll need to add the tool too
-INSERT INTO SAKAI_REALM_RL_FN VALUES((select REALM_KEY from SAKAI_REALM where REALM_ID = '!site.template'), (select ROLE_KEY from SAKAI_REALM_ROLE where ROLE_NAME = 'maintain'), (select FUNCTION_KEY from SAKAI_REALM_FUNCTION where FUNCTION_NAME = 'assessment.all.groups'));
-INSERT INTO SAKAI_REALM_RL_FN VALUES((select REALM_KEY from SAKAI_REALM where REALM_ID = '!site.template.course'), (select ROLE_KEY from SAKAI_REALM_ROLE where ROLE_NAME = 'Instructor'), (select FUNCTION_KEY from SAKAI_REALM_FUNCTION where FUNCTION_NAME = 'assessment.all.groups'));
+INSERT IGNORE INTO SAKAI_REALM_RL_FN VALUES((select REALM_KEY from SAKAI_REALM where REALM_ID = '!site.template'), (select ROLE_KEY from SAKAI_REALM_ROLE where ROLE_NAME = 'maintain'), (select FUNCTION_KEY from SAKAI_REALM_FUNCTION where FUNCTION_NAME = 'assessment.all.groups'));
+INSERT IGNORE INTO SAKAI_REALM_RL_FN VALUES((select REALM_KEY from SAKAI_REALM where REALM_ID = '!site.template.course'), (select ROLE_KEY from SAKAI_REALM_ROLE where ROLE_NAME = 'Instructor'), (select FUNCTION_KEY from SAKAI_REALM_FUNCTION where FUNCTION_NAME = 'assessment.all.groups'));
🤖 Prompt for AI Agents
In docs/conversion/sakai_25_1-25_2_mysql_conversion.sql around lines 5 to 6, the
two direct INSERT statements are not idempotent and will error on duplicate keys
or insert NULLs if the subqueries return no rows; change them to perform
conditional inserts (e.g., INSERT IGNORE ... SELECT ... or INSERT ... SELECT ...
WHERE NOT EXISTS (...) ) and ensure the SELECTs only run when the subquery
values are non-NULL (add WHERE clauses checking existence of the realm, role and
function keys or join to those tables instead of scalar subqueries) so
re-running the script is safe and no invalid rows are inserted.

Comment on lines +13 to +14
INSERT INTO SAKAI_REALM_RL_FN VALUES((select REALM_KEY from SAKAI_REALM where REALM_ID = '!site.template'), (select ROLE_KEY from SAKAI_REALM_ROLE where ROLE_NAME = 'maintain'), (select FUNCTION_KEY from SAKAI_REALM_FUNCTION where FUNCTION_NAME = 'assessment.all.groups'));
INSERT INTO SAKAI_REALM_RL_FN VALUES((select REALM_KEY from SAKAI_REALM where REALM_ID = '!site.template.course'), (select ROLE_KEY from SAKAI_REALM_ROLE where ROLE_NAME = 'Instructor'), (select FUNCTION_KEY from SAKAI_REALM_FUNCTION where FUNCTION_NAME = 'assessment.all.groups'));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Template inserts lack idempotency and may fail on re-run.

Same issue as the MySQL version: these will fail with a constraint violation if run twice. Oracle doesn't have INSERT IGNORE, so consider using MERGE or wrapping each insert with a NOT EXISTS check.

🔎 Suggested fix using MERGE:
 -- Add this for every role able to create and manage conditions on a site, you'll need to add the tool too
-INSERT INTO SAKAI_REALM_RL_FN VALUES((select REALM_KEY from SAKAI_REALM where REALM_ID = '!site.template'), (select ROLE_KEY from SAKAI_REALM_ROLE where ROLE_NAME = 'maintain'), (select FUNCTION_KEY from SAKAI_REALM_FUNCTION where FUNCTION_NAME = 'assessment.all.groups'));
-INSERT INTO SAKAI_REALM_RL_FN VALUES((select REALM_KEY from SAKAI_REALM where REALM_ID = '!site.template.course'), (select ROLE_KEY from SAKAI_REALM_ROLE where ROLE_NAME = 'Instructor'), (select FUNCTION_KEY from SAKAI_REALM_FUNCTION where FUNCTION_NAME = 'assessment.all.groups'));
+MERGE INTO SAKAI_REALM_RL_FN t
+USING (
+    SELECT 
+        (SELECT REALM_KEY FROM SAKAI_REALM WHERE REALM_ID = '!site.template') AS REALM_KEY,
+        (SELECT ROLE_KEY FROM SAKAI_REALM_ROLE WHERE ROLE_NAME = 'maintain') AS ROLE_KEY,
+        (SELECT FUNCTION_KEY FROM SAKAI_REALM_FUNCTION WHERE FUNCTION_NAME = 'assessment.all.groups') AS FUNCTION_KEY
+    FROM dual
+) s ON (t.REALM_KEY = s.REALM_KEY AND t.ROLE_KEY = s.ROLE_KEY AND t.FUNCTION_KEY = s.FUNCTION_KEY)
+WHEN NOT MATCHED THEN INSERT (REALM_KEY, ROLE_KEY, FUNCTION_KEY) VALUES (s.REALM_KEY, s.ROLE_KEY, s.FUNCTION_KEY);
+
+MERGE INTO SAKAI_REALM_RL_FN t
+USING (
+    SELECT 
+        (SELECT REALM_KEY FROM SAKAI_REALM WHERE REALM_ID = '!site.template.course') AS REALM_KEY,
+        (SELECT ROLE_KEY FROM SAKAI_REALM_ROLE WHERE ROLE_NAME = 'Instructor') AS ROLE_KEY,
+        (SELECT FUNCTION_KEY FROM SAKAI_REALM_FUNCTION WHERE FUNCTION_NAME = 'assessment.all.groups') AS FUNCTION_KEY
+    FROM dual
+) s ON (t.REALM_KEY = s.REALM_KEY AND t.ROLE_KEY = s.ROLE_KEY AND t.FUNCTION_KEY = s.FUNCTION_KEY)
+WHEN NOT MATCHED THEN INSERT (REALM_KEY, ROLE_KEY, FUNCTION_KEY) VALUES (s.REALM_KEY, s.ROLE_KEY, s.FUNCTION_KEY);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
INSERT INTO SAKAI_REALM_RL_FN VALUES((select REALM_KEY from SAKAI_REALM where REALM_ID = '!site.template'), (select ROLE_KEY from SAKAI_REALM_ROLE where ROLE_NAME = 'maintain'), (select FUNCTION_KEY from SAKAI_REALM_FUNCTION where FUNCTION_NAME = 'assessment.all.groups'));
INSERT INTO SAKAI_REALM_RL_FN VALUES((select REALM_KEY from SAKAI_REALM where REALM_ID = '!site.template.course'), (select ROLE_KEY from SAKAI_REALM_ROLE where ROLE_NAME = 'Instructor'), (select FUNCTION_KEY from SAKAI_REALM_FUNCTION where FUNCTION_NAME = 'assessment.all.groups'));
MERGE INTO SAKAI_REALM_RL_FN t
USING (
SELECT
(SELECT REALM_KEY FROM SAKAI_REALM WHERE REALM_ID = '!site.template') AS REALM_KEY,
(SELECT ROLE_KEY FROM SAKAI_REALM_ROLE WHERE ROLE_NAME = 'maintain') AS ROLE_KEY,
(SELECT FUNCTION_KEY FROM SAKAI_REALM_FUNCTION WHERE FUNCTION_NAME = 'assessment.all.groups') AS FUNCTION_KEY
FROM dual
) s ON (t.REALM_KEY = s.REALM_KEY AND t.ROLE_KEY = s.ROLE_KEY AND t.FUNCTION_KEY = s.FUNCTION_KEY)
WHEN NOT MATCHED THEN INSERT (REALM_KEY, ROLE_KEY, FUNCTION_KEY) VALUES (s.REALM_KEY, s.ROLE_KEY, s.FUNCTION_KEY);
MERGE INTO SAKAI_REALM_RL_FN t
USING (
SELECT
(SELECT REALM_KEY FROM SAKAI_REALM WHERE REALM_ID = '!site.template.course') AS REALM_KEY,
(SELECT ROLE_KEY FROM SAKAI_REALM_ROLE WHERE ROLE_NAME = 'Instructor') AS ROLE_KEY,
(SELECT FUNCTION_KEY FROM SAKAI_REALM_FUNCTION WHERE FUNCTION_NAME = 'assessment.all.groups') AS FUNCTION_KEY
FROM dual
) s ON (t.REALM_KEY = s.REALM_KEY AND t.ROLE_KEY = s.ROLE_KEY AND t.FUNCTION_KEY = s.FUNCTION_KEY)
WHEN NOT MATCHED THEN INSERT (REALM_KEY, ROLE_KEY, FUNCTION_KEY) VALUES (s.REALM_KEY, s.ROLE_KEY, s.FUNCTION_KEY);
🤖 Prompt for AI Agents
In docs/conversion/sakai_25_1-25_2_oracle_conversion.sql around lines 13 to 14,
the two INSERT statements for SAKAI_REALM_RL_FN are not idempotent and will fail
on duplicate key constraint on re-run; replace each INSERT with an
Oracle-friendly idempotent operation (e.g., use a MERGE that matches on the
composite key columns or wrap the insert in a conditional INSERT ... SELECT that
only inserts when a corresponding row does not exist using NOT EXISTS), ensuring
you compute the same subselect values for realm/role/function and use them as
the MERGE key predicates or in the NOT EXISTS check so repeated runs do nothing
if the mapping already exists.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant