fix: resolve 9 critical bugs from full local testing

- Migrate 5 OWL components from deprecated useService("rpc") to useService("orm") for Odoo 19
- Fix _paginate() signature mismatch across 6 controllers (dual calling convention)
- Fix taxonomy API serializers referencing non-existent fields (icon, difficulty)
- Fix branding controller validate_token() called with wrong arguments
- Add .sudo() to exam template/question model access under auth='none'
- Restore missing encoach_core files (security groups, permissions seed, core models)
- Create encoach_api shared controller utilities module
- Add Entity list/form/search views and menu items
- Add Taxonomy (Subjects/Domains/Topics) views and menu items
- Fix deprecated XML group expand="0" patterns across 15 view files
- Remove stale model references from adaptive __init__.py and access CSV
- Update .gitignore to exclude local dev artifacts

Tested: 97% pass rate (64/66 tests) across UI navigation, CRUD, and API endpoints.
Made-with: Cursor
This commit is contained in:
Yamen Ahmad
2026-04-07 03:43:48 +04:00
parent 6c93c5d600
commit d98cd55b99
58 changed files with 1401 additions and 213 deletions

View File

@@ -1,8 +1,3 @@
from . import proficiency
from . import learning_plan
from . import learning_plan_item
from . import diagnostic_session
from . import content_cache
from . import adaptive_event
from . import adaptive_path
from . import adaptive_settings

View File

@@ -1,18 +1,4 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_proficiency_student,encoach.proficiency.student,model_encoach_proficiency,encoach_core.group_encoach_student,1,0,0,0
access_proficiency_teacher,encoach.proficiency.teacher,model_encoach_proficiency,encoach_core.group_encoach_teacher,1,1,1,0
access_proficiency_admin,encoach.proficiency.admin,model_encoach_proficiency,encoach_core.group_encoach_admin,1,1,1,1
access_learning_plan_student,encoach.learning.plan.student,model_encoach_learning_plan,encoach_core.group_encoach_student,1,1,0,0
access_learning_plan_teacher,encoach.learning.plan.teacher,model_encoach_learning_plan,encoach_core.group_encoach_teacher,1,1,1,0
access_learning_plan_admin,encoach.learning.plan.admin,model_encoach_learning_plan,encoach_core.group_encoach_admin,1,1,1,1
access_plan_item_student,encoach.learning.plan.item.student,model_encoach_learning_plan_item,encoach_core.group_encoach_student,1,1,0,0
access_plan_item_teacher,encoach.learning.plan.item.teacher,model_encoach_learning_plan_item,encoach_core.group_encoach_teacher,1,1,1,0
access_plan_item_admin,encoach.learning.plan.item.admin,model_encoach_learning_plan_item,encoach_core.group_encoach_admin,1,1,1,1
access_diagnostic_student,encoach.diagnostic.session.student,model_encoach_diagnostic_session,encoach_core.group_encoach_student,1,1,1,0
access_diagnostic_teacher,encoach.diagnostic.session.teacher,model_encoach_diagnostic_session,encoach_core.group_encoach_teacher,1,1,1,0
access_diagnostic_admin,encoach.diagnostic.session.admin,model_encoach_diagnostic_session,encoach_core.group_encoach_admin,1,1,1,1
access_content_cache_student,encoach.content.cache.student,model_encoach_content_cache,encoach_core.group_encoach_student,1,0,0,0
access_content_cache_admin,encoach.content.cache.admin,model_encoach_content_cache,encoach_core.group_encoach_admin,1,1,1,1
access_adaptive_event_user,encoach.adaptive.event.user,model_encoach_adaptive_event,base.group_user,1,1,1,1
access_adaptive_path_user,encoach.adaptive.path.user,model_encoach_adaptive_path,base.group_user,1,1,1,1
access_adaptive_settings_user,encoach.adaptive.settings.user,model_encoach_adaptive_settings,base.group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
access_proficiency_student encoach.proficiency.student model_encoach_proficiency encoach_core.group_encoach_student 1 0 0 0
access_proficiency_teacher encoach.proficiency.teacher model_encoach_proficiency encoach_core.group_encoach_teacher 1 1 1 0
access_proficiency_admin encoach.proficiency.admin model_encoach_proficiency encoach_core.group_encoach_admin 1 1 1 1
access_learning_plan_student encoach.learning.plan.student model_encoach_learning_plan encoach_core.group_encoach_student 1 1 0 0
access_learning_plan_teacher encoach.learning.plan.teacher model_encoach_learning_plan encoach_core.group_encoach_teacher 1 1 1 0
access_learning_plan_admin encoach.learning.plan.admin model_encoach_learning_plan encoach_core.group_encoach_admin 1 1 1 1
access_plan_item_student encoach.learning.plan.item.student model_encoach_learning_plan_item encoach_core.group_encoach_student 1 1 0 0
access_plan_item_teacher encoach.learning.plan.item.teacher model_encoach_learning_plan_item encoach_core.group_encoach_teacher 1 1 1 0
access_plan_item_admin encoach.learning.plan.item.admin model_encoach_learning_plan_item encoach_core.group_encoach_admin 1 1 1 1
access_diagnostic_student encoach.diagnostic.session.student model_encoach_diagnostic_session encoach_core.group_encoach_student 1 1 1 0
access_diagnostic_teacher encoach.diagnostic.session.teacher model_encoach_diagnostic_session encoach_core.group_encoach_teacher 1 1 1 0
access_diagnostic_admin encoach.diagnostic.session.admin model_encoach_diagnostic_session encoach_core.group_encoach_admin 1 1 1 1
access_content_cache_student encoach.content.cache.student model_encoach_content_cache encoach_core.group_encoach_student 1 0 0 0
access_content_cache_admin encoach.content.cache.admin model_encoach_content_cache encoach_core.group_encoach_admin 1 1 1 1
2 access_adaptive_event_user encoach.adaptive.event.user model_encoach_adaptive_event base.group_user 1 1 1 1
3 access_adaptive_path_user encoach.adaptive.path.user model_encoach_adaptive_path base.group_user 1 1 1 1
4 access_adaptive_settings_user encoach.adaptive.settings.user model_encoach_adaptive_settings base.group_user 1 1 1 1

View File

@@ -11,7 +11,7 @@ class SignalTimeline extends Component {
static props = ["*"];
setup() {
this.rpc = useService("rpc");
this.orm = useService("orm");
this.action = useService("action");
this.state = useState({
loading: true,
@@ -36,12 +36,12 @@ class SignalTimeline extends Component {
async loadStudentList() {
try {
this.state.studentList = await this.rpc("/web/dataset/call_kw", {
model: "res.users",
method: "search_read",
args: [[["account_source", "!=", false]], ["name", "email"]],
kwargs: { limit: 50, order: "name" },
});
this.state.studentList = await this.orm.searchRead(
"res.users",
[["account_source", "!=", false]],
["name", "email"],
{ limit: 50, order: "name" },
);
} catch (e) {
console.error("Failed to load students:", e);
} finally {
@@ -70,18 +70,17 @@ class SignalTimeline extends Component {
}
const [events, students] = await Promise.all([
this.rpc("/web/dataset/call_kw", {
model: "encoach.adaptive.event",
method: "search_read",
args: [domain, ["student_id", "course_id", "event_type", "signal_name", "signal_value", "decision", "context", "created_at"]],
kwargs: { limit: 100, order: "created_at desc" },
}),
this.rpc("/web/dataset/call_kw", {
model: "res.users",
method: "search_read",
args: [[["id", "=", this.state.studentId]], ["name", "email"]],
kwargs: {},
}),
this.orm.searchRead(
"encoach.adaptive.event",
domain,
["student_id", "course_id", "event_type", "signal_name", "signal_value", "decision", "context", "created_at"],
{ limit: 100, order: "created_at desc" },
),
this.orm.searchRead(
"res.users",
[["id", "=", this.state.studentId]],
["name", "email"],
),
]);
this.state.student = students.length ? students[0] : null;

View File

@@ -53,9 +53,7 @@
<filter string="Signals" name="signal" domain="[('event_type', '=', 'signal')]"/>
<filter string="Decisions" name="decision" domain="[('event_type', '=', 'decision')]"/>
<separator/>
<group expand="0" string="Group By">
<filter string="Student" name="group_student" context="{'group_by': 'student_id'}"/>
</group>
<filter string="Student" name="group_student" context="{'group_by': 'student_id'}"/>
</search>
</field>
</record>