feat: Implement LTI deep linking, live sessions, predictive analytics, and portfolios with associated UI and database migrations.

This commit is contained in:
2026-02-24 09:37:16 -03:00
parent 7f7ea3d70c
commit 04dbe05704
81 changed files with 4119 additions and 249 deletions
@@ -0,0 +1,86 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE library_blocks \n SET name = COALESCE($1, name),\n description = COALESCE($2, description),\n tags = COALESCE($3, tags),\n updated_at = NOW()\n WHERE id = $4 AND organization_id = $5\n RETURNING id, organization_id, created_by, name, description, block_type, block_data, tags, usage_count as \"usage_count!\", created_at, updated_at\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "organization_id",
"type_info": "Uuid"
},
{
"ordinal": 2,
"name": "created_by",
"type_info": "Uuid"
},
{
"ordinal": 3,
"name": "name",
"type_info": "Text"
},
{
"ordinal": 4,
"name": "description",
"type_info": "Text"
},
{
"ordinal": 5,
"name": "block_type",
"type_info": "Text"
},
{
"ordinal": 6,
"name": "block_data",
"type_info": "Jsonb"
},
{
"ordinal": 7,
"name": "tags",
"type_info": "TextArray"
},
{
"ordinal": 8,
"name": "usage_count!",
"type_info": "Int4"
},
{
"ordinal": 9,
"name": "created_at",
"type_info": "Timestamptz"
},
{
"ordinal": 10,
"name": "updated_at",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"TextArray",
"Uuid",
"Uuid"
]
},
"nullable": [
false,
false,
false,
false,
true,
false,
false,
true,
true,
false,
false
]
},
"hash": "00e1fd1111ece41c0c1494cf92dacaa1127f01bf97ddf71342cf129c3a3275e1"
}
@@ -0,0 +1,22 @@
{
"db_name": "PostgreSQL",
"query": "SELECT rubric_id FROM rubric_criteria WHERE id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "rubric_id",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": [
false
]
},
"hash": "13d9a1d22c6a77705cd74ed6d05916d9f84c28b87cb357178400ee7421cbe0bc"
}
@@ -0,0 +1,63 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE rubric_levels\n SET name = COALESCE($1, name),\n description = COALESCE($2, description),\n points = COALESCE($3, points),\n position = COALESCE($4, position)\n WHERE id = $5\n AND criterion_id IN (\n SELECT id FROM rubric_criteria\n WHERE rubric_id IN (SELECT id FROM rubrics WHERE organization_id = $6)\n )\n RETURNING id, criterion_id, name, description, points, position, created_at\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "criterion_id",
"type_info": "Uuid"
},
{
"ordinal": 2,
"name": "name",
"type_info": "Varchar"
},
{
"ordinal": 3,
"name": "description",
"type_info": "Text"
},
{
"ordinal": 4,
"name": "points",
"type_info": "Int4"
},
{
"ordinal": 5,
"name": "position",
"type_info": "Int4"
},
{
"ordinal": 6,
"name": "created_at",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Varchar",
"Text",
"Int4",
"Int4",
"Uuid",
"Uuid"
]
},
"nullable": [
false,
false,
false,
true,
false,
false,
false
]
},
"hash": "17b6ee6e225ecf0573f41c8017f7509bf38d345a697b9b885ec276061baa1cba"
}
@@ -0,0 +1,21 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO assets (id, organization_id, uploaded_by, course_id, filename, storage_path, mimetype, size_bytes)\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8)\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Uuid",
"Uuid",
"Uuid",
"Uuid",
"Text",
"Text",
"Text",
"Int8"
]
},
"nullable": []
},
"hash": "255e2331ed0f3148bd14e1cc2e791c7c91067eea455146923e463036d61e92c7"
}
@@ -0,0 +1,58 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT id, criterion_id, name, description, points, position, created_at\n FROM rubric_levels\n WHERE criterion_id = $1\n ORDER BY position ASC\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "criterion_id",
"type_info": "Uuid"
},
{
"ordinal": 2,
"name": "name",
"type_info": "Varchar"
},
{
"ordinal": 3,
"name": "description",
"type_info": "Text"
},
{
"ordinal": 4,
"name": "points",
"type_info": "Int4"
},
{
"ordinal": 5,
"name": "position",
"type_info": "Int4"
},
{
"ordinal": 6,
"name": "created_at",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": [
false,
false,
false,
true,
false,
false,
false
]
},
"hash": "2893eec86b904d90f69b96766029f17c80aa86fd3a10d12bef9879b9f25ae23a"
}
@@ -0,0 +1,14 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE rubrics\n SET total_points = (SELECT COALESCE(SUM(max_points), 0) FROM rubric_criteria WHERE rubric_id = $1),\n updated_at = NOW()\n WHERE id = $1\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": []
},
"hash": "2abb997f1ef644429883fbd0bd72408bddaa1cea968319f28d5e87011e2bf0b7"
}
@@ -0,0 +1,15 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM lesson_rubrics WHERE lesson_id = $1 AND rubric_id = $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Uuid",
"Uuid"
]
},
"nullable": []
},
"hash": "3747c2088f23d32d110971afcdf8271678069e981fa98749ff7ec26c358a139f"
}
@@ -0,0 +1,14 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE rubrics\n SET total_points = (SELECT COALESCE(SUM(max_points), 0) FROM rubric_criteria WHERE rubric_id = $1),\n updated_at = NOW()\n WHERE id = $1\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": []
},
"hash": "42dfabb9428c4d090242fc98e43eb3a8236333ca2305b6ab852dcc90d232ac89"
}
@@ -0,0 +1,47 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO lesson_rubrics (lesson_id, rubric_id, is_active)\n VALUES ($1, $2, true)\n ON CONFLICT (lesson_id, rubric_id) DO UPDATE SET is_active = true\n RETURNING id, lesson_id, rubric_id, is_active, assigned_at\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "lesson_id",
"type_info": "Uuid"
},
{
"ordinal": 2,
"name": "rubric_id",
"type_info": "Uuid"
},
{
"ordinal": 3,
"name": "is_active",
"type_info": "Bool"
},
{
"ordinal": 4,
"name": "assigned_at",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Uuid",
"Uuid"
]
},
"nullable": [
false,
false,
false,
false,
false
]
},
"hash": "45c3ae8b43e4fe46aa4126986b7607996f77213b859e4f47e0a1d16cf4913fd0"
}
@@ -0,0 +1,71 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT r.id, r.organization_id, r.course_id, r.created_by, r.name, r.description, r.total_points, r.created_at, r.updated_at\n FROM rubrics r\n INNER JOIN lesson_rubrics lr ON lr.rubric_id = r.id\n WHERE lr.lesson_id = $1 AND lr.is_active = true AND r.organization_id = $2\n ORDER BY lr.assigned_at DESC\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "organization_id",
"type_info": "Uuid"
},
{
"ordinal": 2,
"name": "course_id",
"type_info": "Uuid"
},
{
"ordinal": 3,
"name": "created_by",
"type_info": "Uuid"
},
{
"ordinal": 4,
"name": "name",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "description",
"type_info": "Text"
},
{
"ordinal": 6,
"name": "total_points",
"type_info": "Int4"
},
{
"ordinal": 7,
"name": "created_at",
"type_info": "Timestamptz"
},
{
"ordinal": 8,
"name": "updated_at",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Uuid",
"Uuid"
]
},
"nullable": [
false,
false,
true,
false,
false,
true,
false,
false,
false
]
},
"hash": "4687bb156a947f156e401c0d610756e7bb3a1abb0f706d3be347659f485e71de"
}
@@ -0,0 +1,55 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO lesson_dependencies (organization_id, lesson_id, prerequisite_lesson_id, min_score_percentage)\n VALUES ($1, $2, $3, $4)\n ON CONFLICT (lesson_id, prerequisite_lesson_id) \n DO UPDATE SET min_score_percentage = EXCLUDED.min_score_percentage\n RETURNING id, organization_id, lesson_id, prerequisite_lesson_id, min_score_percentage, created_at\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "organization_id",
"type_info": "Uuid"
},
{
"ordinal": 2,
"name": "lesson_id",
"type_info": "Uuid"
},
{
"ordinal": 3,
"name": "prerequisite_lesson_id",
"type_info": "Uuid"
},
{
"ordinal": 4,
"name": "min_score_percentage",
"type_info": "Float8"
},
{
"ordinal": 5,
"name": "created_at",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Uuid",
"Uuid",
"Uuid",
"Float8"
]
},
"nullable": [
false,
false,
false,
false,
true,
false
]
},
"hash": "4e61a89bc2207eba7452c77aea850919ec09dfabd2b8e5b5dd84aca3853669eb"
}
@@ -0,0 +1,71 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT id, organization_id, course_id, created_by, name, description, total_points, created_at, updated_at\n FROM rubrics\n WHERE id = $1 AND organization_id = $2\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "organization_id",
"type_info": "Uuid"
},
{
"ordinal": 2,
"name": "course_id",
"type_info": "Uuid"
},
{
"ordinal": 3,
"name": "created_by",
"type_info": "Uuid"
},
{
"ordinal": 4,
"name": "name",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "description",
"type_info": "Text"
},
{
"ordinal": 6,
"name": "total_points",
"type_info": "Int4"
},
{
"ordinal": 7,
"name": "created_at",
"type_info": "Timestamptz"
},
{
"ordinal": 8,
"name": "updated_at",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Uuid",
"Uuid"
]
},
"nullable": [
false,
false,
true,
false,
false,
true,
false,
false,
false
]
},
"hash": "521e61afe4ab4bf06305447d012ee4bc236f2b3ebce7c788335cf0ca2daf8823"
}
@@ -0,0 +1,71 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT id, organization_id, course_id, created_by, name, description, total_points, created_at, updated_at\n FROM rubrics\n WHERE organization_id = $1 AND (course_id = $2 OR course_id IS NULL)\n ORDER BY created_at DESC\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "organization_id",
"type_info": "Uuid"
},
{
"ordinal": 2,
"name": "course_id",
"type_info": "Uuid"
},
{
"ordinal": 3,
"name": "created_by",
"type_info": "Uuid"
},
{
"ordinal": 4,
"name": "name",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "description",
"type_info": "Text"
},
{
"ordinal": 6,
"name": "total_points",
"type_info": "Int4"
},
{
"ordinal": 7,
"name": "created_at",
"type_info": "Timestamptz"
},
{
"ordinal": 8,
"name": "updated_at",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Uuid",
"Uuid"
]
},
"nullable": [
false,
false,
true,
false,
false,
true,
false,
false,
false
]
},
"hash": "62c035c29d3b3c5a2fff84713668f6d8a2f6e2cbabf55a6795b218338239d8ab"
}
@@ -0,0 +1,71 @@
{
"db_name": "PostgreSQL",
"query": "SELECT * FROM assets WHERE id = $1 AND organization_id = $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "filename",
"type_info": "Text"
},
{
"ordinal": 2,
"name": "storage_path",
"type_info": "Text"
},
{
"ordinal": 3,
"name": "mimetype",
"type_info": "Text"
},
{
"ordinal": 4,
"name": "size_bytes",
"type_info": "Int8"
},
{
"ordinal": 5,
"name": "created_at",
"type_info": "Timestamptz"
},
{
"ordinal": 6,
"name": "organization_id",
"type_info": "Uuid"
},
{
"ordinal": 7,
"name": "course_id",
"type_info": "Uuid"
},
{
"ordinal": 8,
"name": "uploaded_by",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"Uuid",
"Uuid"
]
},
"nullable": [
false,
false,
false,
false,
false,
false,
false,
true,
true
]
},
"hash": "71a9bb3c9b3ba2c851c2dad049291bb46855eca27523952bbf655250039a7468"
}
@@ -0,0 +1,88 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO library_blocks (organization_id, created_by, name, description, block_type, block_data, tags)\n VALUES ($1, $2, $3, $4, $5, $6, $7)\n RETURNING id, organization_id, created_by, name, description, block_type, block_data, tags, usage_count as \"usage_count!\", created_at, updated_at\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "organization_id",
"type_info": "Uuid"
},
{
"ordinal": 2,
"name": "created_by",
"type_info": "Uuid"
},
{
"ordinal": 3,
"name": "name",
"type_info": "Text"
},
{
"ordinal": 4,
"name": "description",
"type_info": "Text"
},
{
"ordinal": 5,
"name": "block_type",
"type_info": "Text"
},
{
"ordinal": 6,
"name": "block_data",
"type_info": "Jsonb"
},
{
"ordinal": 7,
"name": "tags",
"type_info": "TextArray"
},
{
"ordinal": 8,
"name": "usage_count!",
"type_info": "Int4"
},
{
"ordinal": 9,
"name": "created_at",
"type_info": "Timestamptz"
},
{
"ordinal": 10,
"name": "updated_at",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Uuid",
"Uuid",
"Text",
"Text",
"Text",
"Jsonb",
"TextArray"
]
},
"nullable": [
false,
false,
false,
false,
true,
false,
false,
true,
true,
false,
false
]
},
"hash": "7b3e62330c2b8c283aff253e568b65655efd76d54a5e6ac57093a05718af9882"
}
@@ -0,0 +1,15 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE library_blocks SET usage_count = usage_count + 1 WHERE id = $1 AND organization_id = $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Uuid",
"Uuid"
]
},
"nullable": []
},
"hash": "82e4c85bf3aaa45506e3245c3d7b9e8ab224a8e10f2666e69ef212fb0c000ac0"
}
@@ -0,0 +1,14 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM assets WHERE id = $1",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": []
},
"hash": "834a48554bc7989975b42afbc40d0128865826a7cc6130441c42e75b46c54dc9"
}
@@ -0,0 +1,23 @@
{
"db_name": "PostgreSQL",
"query": "SELECT id FROM rubric_criteria WHERE id = $1 AND rubric_id IN (SELECT id FROM rubrics WHERE organization_id = $2)",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"Uuid",
"Uuid"
]
},
"nullable": [
false
]
},
"hash": "85fbeda23c72b58439fdedac4c6dbf23b9054354f737f60c23d0b416944b6095"
}
@@ -0,0 +1,73 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE rubrics\n SET name = COALESCE($1, name),\n description = COALESCE($2, description),\n updated_at = NOW()\n WHERE id = $3 AND organization_id = $4\n RETURNING id, organization_id, course_id, created_by, name, description, total_points, created_at, updated_at\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "organization_id",
"type_info": "Uuid"
},
{
"ordinal": 2,
"name": "course_id",
"type_info": "Uuid"
},
{
"ordinal": 3,
"name": "created_by",
"type_info": "Uuid"
},
{
"ordinal": 4,
"name": "name",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "description",
"type_info": "Text"
},
{
"ordinal": 6,
"name": "total_points",
"type_info": "Int4"
},
{
"ordinal": 7,
"name": "created_at",
"type_info": "Timestamptz"
},
{
"ordinal": 8,
"name": "updated_at",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Varchar",
"Text",
"Uuid",
"Uuid"
]
},
"nullable": [
false,
false,
true,
false,
false,
true,
false,
false,
false
]
},
"hash": "8ce98992129f77432d24a5a8a458c52d3a252c10f41d6be67d8696b046e4c18f"
}
@@ -0,0 +1,62 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO rubric_criteria (rubric_id, name, description, max_points, position)\n VALUES ($1, $2, $3, $4, $5)\n RETURNING id, rubric_id, name, description, max_points, position, created_at\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "rubric_id",
"type_info": "Uuid"
},
{
"ordinal": 2,
"name": "name",
"type_info": "Varchar"
},
{
"ordinal": 3,
"name": "description",
"type_info": "Text"
},
{
"ordinal": 4,
"name": "max_points",
"type_info": "Int4"
},
{
"ordinal": 5,
"name": "position",
"type_info": "Int4"
},
{
"ordinal": 6,
"name": "created_at",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Uuid",
"Varchar",
"Text",
"Int4",
"Int4"
]
},
"nullable": [
false,
false,
false,
true,
false,
false,
false
]
},
"hash": "914bcec73c3c1399f4e743d3e89289e783b7479592d1c7e11dd677c99d9bb2d3"
}
@@ -0,0 +1,16 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM lesson_dependencies WHERE lesson_id = $1 AND prerequisite_lesson_id = $2 AND organization_id = $3",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Uuid",
"Uuid",
"Uuid"
]
},
"nullable": []
},
"hash": "95ddcf80ff28b2680ebdd9d8ba92aefa34fd99209e228238d86e7d135f6b41e2"
}
@@ -0,0 +1,15 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM library_blocks WHERE id = $1 AND organization_id = $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Uuid",
"Uuid"
]
},
"nullable": []
},
"hash": "b42eb00367a1991125ff01fab2a51a3582512a9265d02c2bcb05ddb80e7c6038"
}
@@ -0,0 +1,23 @@
{
"db_name": "PostgreSQL",
"query": "SELECT id FROM rubrics WHERE id = $1 AND organization_id = $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"Uuid",
"Uuid"
]
},
"nullable": [
false
]
},
"hash": "c2a37e2b0139c053b4c4eb88a2cf4b658fbf419795901d565eaaa1e169d881e9"
}
@@ -0,0 +1,85 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE library_blocks \n SET description = COALESCE($1, description),\n tags = COALESCE($2, tags),\n updated_at = NOW()\n WHERE id = $3 AND organization_id = $4\n RETURNING id, organization_id, created_by, name, description, block_type, block_data, tags, usage_count as \"usage_count!\", created_at, updated_at\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "organization_id",
"type_info": "Uuid"
},
{
"ordinal": 2,
"name": "created_by",
"type_info": "Uuid"
},
{
"ordinal": 3,
"name": "name",
"type_info": "Text"
},
{
"ordinal": 4,
"name": "description",
"type_info": "Text"
},
{
"ordinal": 5,
"name": "block_type",
"type_info": "Text"
},
{
"ordinal": 6,
"name": "block_data",
"type_info": "Jsonb"
},
{
"ordinal": 7,
"name": "tags",
"type_info": "TextArray"
},
{
"ordinal": 8,
"name": "usage_count!",
"type_info": "Int4"
},
{
"ordinal": 9,
"name": "created_at",
"type_info": "Timestamptz"
},
{
"ordinal": 10,
"name": "updated_at",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Text",
"TextArray",
"Uuid",
"Uuid"
]
},
"nullable": [
false,
false,
false,
false,
true,
false,
false,
true,
true,
false,
false
]
},
"hash": "cc7467f5734e57f581fab98e7e37a934a7852474ed2eb3ea7b26e4d14b8a4df0"
}
@@ -0,0 +1,15 @@
{
"db_name": "PostgreSQL",
"query": "\n DELETE FROM rubric_criteria\n WHERE id = $1\n AND rubric_id IN (SELECT id FROM rubrics WHERE organization_id = $2)\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Uuid",
"Uuid"
]
},
"nullable": []
},
"hash": "d06f83e2b566ac9a49c63bdfcce03912f6ae1ef00a96fd345d89f22f218aaf1c"
}
@@ -0,0 +1,74 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO rubrics (organization_id, course_id, created_by, name, description)\n VALUES ($1, $2, $3, $4, $5)\n RETURNING id, organization_id, course_id, created_by, name, description, total_points, created_at, updated_at\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "organization_id",
"type_info": "Uuid"
},
{
"ordinal": 2,
"name": "course_id",
"type_info": "Uuid"
},
{
"ordinal": 3,
"name": "created_by",
"type_info": "Uuid"
},
{
"ordinal": 4,
"name": "name",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "description",
"type_info": "Text"
},
{
"ordinal": 6,
"name": "total_points",
"type_info": "Int4"
},
{
"ordinal": 7,
"name": "created_at",
"type_info": "Timestamptz"
},
{
"ordinal": 8,
"name": "updated_at",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Uuid",
"Uuid",
"Uuid",
"Varchar",
"Text"
]
},
"nullable": [
false,
false,
true,
false,
false,
true,
false,
false,
false
]
},
"hash": "ddc1f59ea8f744d2357944e68cf49e4176f7dbee191bbdff8876fc88a0e26436"
}
@@ -0,0 +1,63 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE rubric_criteria\n SET name = COALESCE($1, name),\n description = COALESCE($2, description),\n max_points = COALESCE($3, max_points),\n position = COALESCE($4, position)\n WHERE id = $5\n AND rubric_id IN (SELECT id FROM rubrics WHERE organization_id = $6)\n RETURNING id, rubric_id, name, description, max_points, position, created_at\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "rubric_id",
"type_info": "Uuid"
},
{
"ordinal": 2,
"name": "name",
"type_info": "Varchar"
},
{
"ordinal": 3,
"name": "description",
"type_info": "Text"
},
{
"ordinal": 4,
"name": "max_points",
"type_info": "Int4"
},
{
"ordinal": 5,
"name": "position",
"type_info": "Int4"
},
{
"ordinal": 6,
"name": "created_at",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Varchar",
"Text",
"Int4",
"Int4",
"Uuid",
"Uuid"
]
},
"nullable": [
false,
false,
false,
true,
false,
false,
false
]
},
"hash": "e26e27402806a7fa4d85433ed18f25c84a2cc2f5eb6b9c2db7562f75755ddc13"
}
@@ -0,0 +1,83 @@
{
"db_name": "PostgreSQL",
"query": "SELECT id, organization_id, created_by, name, description, block_type, block_data, tags, usage_count as \"usage_count!\", created_at, updated_at FROM library_blocks WHERE id = $1 AND organization_id = $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "organization_id",
"type_info": "Uuid"
},
{
"ordinal": 2,
"name": "created_by",
"type_info": "Uuid"
},
{
"ordinal": 3,
"name": "name",
"type_info": "Text"
},
{
"ordinal": 4,
"name": "description",
"type_info": "Text"
},
{
"ordinal": 5,
"name": "block_type",
"type_info": "Text"
},
{
"ordinal": 6,
"name": "block_data",
"type_info": "Jsonb"
},
{
"ordinal": 7,
"name": "tags",
"type_info": "TextArray"
},
{
"ordinal": 8,
"name": "usage_count!",
"type_info": "Int4"
},
{
"ordinal": 9,
"name": "created_at",
"type_info": "Timestamptz"
},
{
"ordinal": 10,
"name": "updated_at",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Uuid",
"Uuid"
]
},
"nullable": [
false,
false,
false,
false,
true,
false,
false,
true,
true,
false,
false
]
},
"hash": "e3065bc94b895c8ced3d16c97bd6a11909ee9d29a2dc30a70123d07b28d12c11"
}
@@ -0,0 +1,15 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM rubrics WHERE id = $1 AND organization_id = $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Uuid",
"Uuid"
]
},
"nullable": []
},
"hash": "e3b659588c9e818f6c89d030ae929280aaee5c922c1f01420dc061336cb1c159"
}
@@ -0,0 +1,15 @@
{
"db_name": "PostgreSQL",
"query": "\n DELETE FROM rubric_levels\n WHERE id = $1\n AND criterion_id IN (\n SELECT id FROM rubric_criteria\n WHERE rubric_id IN (SELECT id FROM rubrics WHERE organization_id = $2)\n )\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Uuid",
"Uuid"
]
},
"nullable": []
},
"hash": "e57d5797051a54d5ad707edeabfad84a6da8d8d7020f049d67c98687e6961194"
}
@@ -0,0 +1,62 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO rubric_levels (criterion_id, name, description, points, position)\n VALUES ($1, $2, $3, $4, $5)\n RETURNING id, criterion_id, name, description, points, position, created_at\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "criterion_id",
"type_info": "Uuid"
},
{
"ordinal": 2,
"name": "name",
"type_info": "Varchar"
},
{
"ordinal": 3,
"name": "description",
"type_info": "Text"
},
{
"ordinal": 4,
"name": "points",
"type_info": "Int4"
},
{
"ordinal": 5,
"name": "position",
"type_info": "Int4"
},
{
"ordinal": 6,
"name": "created_at",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Uuid",
"Varchar",
"Text",
"Int4",
"Int4"
]
},
"nullable": [
false,
false,
false,
true,
false,
false,
false
]
},
"hash": "e5ede144c8250e31ce63979c3f1a835eb7e8377cf75c8dc0679ec5c2f9504e98"
}
@@ -0,0 +1,23 @@
{
"db_name": "PostgreSQL",
"query": "SELECT id FROM library_blocks WHERE id = $1 AND organization_id = $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"Uuid",
"Uuid"
]
},
"nullable": [
false
]
},
"hash": "ed4f770f0bd31dc8dc731e73843d8c71a2462290c837d72e1def2af3f7a5fc48"
}
@@ -0,0 +1,53 @@
{
"db_name": "PostgreSQL",
"query": "SELECT * FROM lesson_dependencies WHERE lesson_id = $1 AND organization_id = $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "organization_id",
"type_info": "Uuid"
},
{
"ordinal": 2,
"name": "lesson_id",
"type_info": "Uuid"
},
{
"ordinal": 3,
"name": "prerequisite_lesson_id",
"type_info": "Uuid"
},
{
"ordinal": 4,
"name": "min_score_percentage",
"type_info": "Float8"
},
{
"ordinal": 5,
"name": "created_at",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Uuid",
"Uuid"
]
},
"nullable": [
false,
false,
false,
false,
true,
false
]
},
"hash": "f531c2478ba9634cf935aa615c9320fb99006f6e5e66501a93520af637f8f1a5"
}
@@ -0,0 +1,58 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT id, rubric_id, name, description, max_points, position, created_at\n FROM rubric_criteria\n WHERE rubric_id = $1\n ORDER BY position ASC\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "rubric_id",
"type_info": "Uuid"
},
{
"ordinal": 2,
"name": "name",
"type_info": "Varchar"
},
{
"ordinal": 3,
"name": "description",
"type_info": "Text"
},
{
"ordinal": 4,
"name": "max_points",
"type_info": "Int4"
},
{
"ordinal": 5,
"name": "position",
"type_info": "Int4"
},
{
"ordinal": 6,
"name": "created_at",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": [
false,
false,
false,
true,
false,
false,
false
]
},
"hash": "f7a592c933c658314ed5228da68f5df87fbfbbb4acda6940b1fe57009517a6b7"
}
@@ -11,8 +11,8 @@ CREATE TABLE IF NOT EXISTS rubrics (
name VARCHAR(255) NOT NULL,
description TEXT,
total_points INTEGER NOT NULL DEFAULT 100,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_rubrics_org ON rubrics(organization_id);
@@ -26,7 +26,7 @@ CREATE TABLE IF NOT EXISTS rubric_criteria (
description TEXT,
max_points INTEGER NOT NULL,
position INTEGER NOT NULL DEFAULT 0,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_criteria_rubric ON rubric_criteria(rubric_id);
@@ -39,7 +39,7 @@ CREATE TABLE IF NOT EXISTS rubric_levels (
description TEXT,
points INTEGER NOT NULL,
position INTEGER NOT NULL DEFAULT 0,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_levels_criterion ON rubric_levels(criterion_id);
@@ -49,8 +49,8 @@ CREATE TABLE IF NOT EXISTS lesson_rubrics (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
lesson_id UUID NOT NULL REFERENCES lessons(id) ON DELETE CASCADE,
rubric_id UUID NOT NULL REFERENCES rubrics(id) ON DELETE CASCADE,
is_active BOOLEAN DEFAULT TRUE,
assigned_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
is_active BOOLEAN NOT NULL DEFAULT TRUE,
assigned_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
UNIQUE(lesson_id, rubric_id)
);
@@ -68,9 +68,9 @@ CREATE TABLE IF NOT EXISTS rubric_assessments (
total_score DECIMAL(5,2) NOT NULL,
max_score INTEGER NOT NULL,
feedback TEXT,
status VARCHAR(50) DEFAULT 'draft', -- draft, submitted, published
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
status VARCHAR(50) NOT NULL DEFAULT 'draft', -- draft, submitted, published
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_assessments_lesson ON rubric_assessments(lesson_id);
@@ -86,7 +86,7 @@ CREATE TABLE IF NOT EXISTS assessment_scores (
level_id UUID REFERENCES rubric_levels(id), -- selected performance level
points DECIMAL(5,2) NOT NULL,
feedback TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_scores_assessment ON assessment_scores(assessment_id);
@@ -6,7 +6,7 @@ CREATE TABLE lesson_dependencies (
lesson_id UUID NOT NULL REFERENCES lessons(id) ON DELETE CASCADE,
prerequisite_lesson_id UUID NOT NULL REFERENCES lessons(id) ON DELETE CASCADE,
min_score_percentage DOUBLE PRECISION,
created_at TIMESTAMPTZ DEFAULT NOW(),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(lesson_id, prerequisite_lesson_id),
CHECK (lesson_id != prerequisite_lesson_id)
);
+1 -1
View File
@@ -3534,7 +3534,7 @@ pub async fn delete_course(
.map_err(|_| StatusCode::NOT_FOUND)?;
// 2. Additional permission check for instructors
if !is_super_admin && !check_course_access(&pool, course.id, claims.sub, &claims.role).await? {
if !is_super_admin && !check_course_access(&pool, course.id, claims.sub, &claims.role).await.map_err(|(status, _)| status)? {
return Err(StatusCode::FORBIDDEN);
}
+22 -22
View File
@@ -119,7 +119,7 @@ pub async fn create_rubric(
)
.fetch_one(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
Ok(Json(rubric))
}
@@ -143,7 +143,7 @@ pub async fn list_course_rubrics(
)
.fetch_all(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
Ok(Json(rubrics))
}
@@ -167,7 +167,7 @@ pub async fn get_rubric_with_details(
)
.fetch_optional(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.ok_or((StatusCode::NOT_FOUND, "Rubric not found".to_string()))?;
// Get criteria
@@ -183,7 +183,7 @@ pub async fn get_rubric_with_details(
)
.fetch_all(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
// Get levels for each criterion
let mut criteria_with_levels = Vec::new();
@@ -200,7 +200,7 @@ pub async fn get_rubric_with_details(
)
.fetch_all(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
criteria_with_levels.push(CriterionWithLevels { criterion, levels });
}
@@ -235,7 +235,7 @@ pub async fn update_rubric(
)
.fetch_optional(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.ok_or((StatusCode::NOT_FOUND, "Rubric not found".to_string()))?;
Ok(Json(rubric))
@@ -254,7 +254,7 @@ pub async fn delete_rubric(
)
.execute(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
if result.rows_affected() == 0 {
return Err((StatusCode::NOT_FOUND, "Rubric not found".to_string()));
@@ -280,7 +280,7 @@ pub async fn create_criterion(
)
.fetch_optional(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.ok_or((StatusCode::NOT_FOUND, "Rubric not found".to_string()))?;
let position = payload.position.unwrap_or(0);
@@ -300,7 +300,7 @@ pub async fn create_criterion(
)
.fetch_one(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
// Update rubric total_points
let _= sqlx::query!(
@@ -314,7 +314,7 @@ pub async fn create_criterion(
)
.execute(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
Ok(Json(criterion))
}
@@ -347,7 +347,7 @@ pub async fn update_criterion(
)
.fetch_optional(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.ok_or((StatusCode::NOT_FOUND, "Criterion not found".to_string()))?;
// Update rubric total_points if max_points changed
@@ -363,7 +363,7 @@ pub async fn update_criterion(
)
.execute(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
}
Ok(Json(criterion))
@@ -382,7 +382,7 @@ pub async fn delete_criterion(
)
.fetch_optional(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.ok_or((StatusCode::NOT_FOUND, "Criterion not found".to_string()))?;
let result = sqlx::query!(
@@ -396,7 +396,7 @@ pub async fn delete_criterion(
)
.execute(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
if result.rows_affected() == 0 {
return Err((StatusCode::NOT_FOUND, "Criterion not found".to_string()));
@@ -414,7 +414,7 @@ pub async fn delete_criterion(
)
.execute(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
Ok(StatusCode::NO_CONTENT)
}
@@ -436,7 +436,7 @@ pub async fn create_level(
)
.fetch_optional(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.ok_or((StatusCode::NOT_FOUND, "Criterion not found".to_string()))?;
let position = payload.position.unwrap_or(0);
@@ -456,7 +456,7 @@ pub async fn create_level(
)
.fetch_one(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
Ok(Json(level))
}
@@ -492,7 +492,7 @@ pub async fn update_level(
)
.fetch_optional(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.ok_or((StatusCode::NOT_FOUND, "Level not found".to_string()))?;
Ok(Json(level))
@@ -518,7 +518,7 @@ pub async fn delete_level(
)
.execute(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
if result.rows_affected() == 0 {
return Err((StatusCode::NOT_FOUND, "Level not found".to_string()));
@@ -548,7 +548,7 @@ pub async fn assign_rubric_to_lesson(
)
.fetch_one(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
Ok(Json(lesson_rubric))
}
@@ -566,7 +566,7 @@ pub async fn unassign_rubric_from_lesson(
)
.execute(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
if result.rows_affected() == 0 {
return Err((StatusCode::NOT_FOUND, "Lesson rubric not found".to_string()));
@@ -595,7 +595,7 @@ pub async fn get_lesson_rubrics(
)
.fetch_all(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
.map_err(|e: sqlx::Error| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
Ok(Json(rubrics))
}