Skip to content

Commit ada814f

Browse files
committed
[IMP] server: menuitem - validate groups attribute
1 parent 7863e72 commit ada814f

File tree

7 files changed

+202
-38
lines changed

7 files changed

+202
-38
lines changed

server/src/core/diagnostic_codes_list.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,4 +408,8 @@ OLS05052, DiagnosticSetting::Error, "Parent menuitem with id '{0}' does not exis
408408
* A menuitem is specifying an action that has not been declared before the menuitem.
409409
*/
410410
OLS05053, DiagnosticSetting::Error, "Action with id '{0}' does not exist",
411+
/**
412+
* A menuitem is specifying a group that has not been declared before the menuitem
413+
*/
414+
OLS05054, DiagnosticSetting::Error, "Group with id '{0}' does not exist",
411415
}

server/src/core/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ pub mod python_validator;
1616
pub mod python_utils;
1717
pub mod symbols;
1818
pub mod xml_arch_builder;
19-
pub mod xml_arch_builder_rng_validation;
19+
pub mod xml_arch_builder_rng_validation;
20+
pub mod xml_data;

server/src/core/python_odoo_builder.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use crate::core::file_mgr::{FileMgr};
1313
use crate::constants::{OYarn, SymType};
1414
use crate::core::model::{Model, ModelData};
1515
use crate::core::symbols::symbol::Symbol;
16+
use crate::core::xml_data::{XmlData, XmlDataRecord};
1617
use crate::threads::SessionInfo;
1718
use crate::utils::compare_semver;
1819
use crate::{oyarn, Sy, S};
@@ -84,8 +85,12 @@ impl PythonOdooBuilder {
8485
let xml_id_model_name = oyarn!("model_{}", model_name.replace(".", "_").as_str());
8586
let module = module.upgrade().unwrap();
8687
let mut module = module.borrow_mut();
87-
let set = module.as_module_package_mut().xml_ids.entry(xml_id_model_name).or_insert(PtrWeakHashSet::new());
88-
set.insert(sym.clone());
88+
let set = module.as_module_package_mut().xml_ids.entry(xml_id_model_name.clone()).or_insert(vec![]);
89+
set.push(XmlData::RECORD(XmlDataRecord {
90+
xml_symbol: sym.clone(),
91+
model: Sy!("ir.model"),
92+
xml_id: Some(xml_id_model_name),
93+
}));
8994
});
9095
session.sync_odoo.models.insert(model_name.clone(), Rc::new(RefCell::new(model)));
9196
}

server/src/core/symbols/module_symbol.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use std::collections::{HashMap, HashSet};
88
use crate::core::csv_arch_builder::CsvArchBuilder;
99
use crate::core::diagnostics::{create_diagnostic, DiagnosticCode};
1010
use crate::core::xml_arch_builder::XmlArchBuilder;
11+
use crate::core::xml_data::XmlData;
1112
use crate::{constants::*, oyarn, Sy};
1213
use crate::core::file_mgr::{FileInfo, FileMgr, NoqaInfo};
1314
use crate::core::import_resolver::find_module;
@@ -40,7 +41,7 @@ pub struct ModuleSymbol {
4041
all_depends: HashSet<OYarn>, //computed all depends to avoid too many recomputations
4142
data: Vec<(String, TextRange)>, // TODO
4243
pub module_symbols: HashMap<OYarn, Rc<RefCell<Symbol>>>,
43-
pub xml_ids: HashMap<OYarn, PtrWeakHashSet<Weak<RefCell<Symbol>>>>,
44+
pub xml_ids: HashMap<OYarn, Vec<XmlData>>,
4445
pub arch_status: BuildStatus,
4546
pub arch_eval_status: BuildStatus,
4647
pub odoo_status: BuildStatus,

server/src/core/xml_arch_builder.rs

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ use roxmltree::{Attribute, Node};
66
use tracing::{error, warn};
77
use weak_table::PtrWeakHashSet;
88

9-
use crate::{constants::{BuildStatus, BuildSteps, OYarn}, core::{diagnostics::{create_diagnostic, DiagnosticCode}, entry_point::EntryPointType}, threads::SessionInfo, Sy};
9+
use crate::{core::{diagnostics::{create_diagnostic, DiagnosticCode}}};
10+
use crate::{constants::{BuildStatus, BuildSteps, OYarn, EXTENSION_NAME}, core::{entry_point::EntryPointType, xml_data::XmlData}, oyarn, threads::SessionInfo, Sy, S};
1011

1112
use super::{file_mgr::FileInfo, symbols::{symbol::Symbol}};
1213

@@ -44,7 +45,8 @@ impl XmlArchBuilder {
4445
session: &mut SessionInfo,
4546
id: Option<String>,
4647
node: &Node,
47-
diagnostics: &mut Vec<Diagnostic>,
48+
mut xml_data: XmlData,
49+
diagnostics: &mut Vec<Diagnostic>
4850
) {
4951
if !self.is_in_main_ep {
5052
return;
@@ -77,29 +79,15 @@ impl XmlArchBuilder {
7779
xml_module = m.upgrade().unwrap();
7880
}
7981
}
80-
let xml_module_bw = xml_module.borrow();
81-
let already_existing = xml_module_bw.as_module_package().xml_ids.get(&Sy!(id.clone())).cloned();
82-
drop(xml_module_bw);
83-
let mut found_one = false;
84-
if let Some(existing) = already_existing {
85-
//Check that it exists a main xml_id
86-
for s in existing.iter() {
87-
if Rc::ptr_eq(&s, &xml_module) {
88-
found_one = true;
89-
break;
90-
}
91-
}
92-
} else {
93-
xml_module.borrow_mut().as_module_package_mut().xml_ids.insert(Sy!(id.clone()), PtrWeakHashSet::new());
94-
}
95-
if !found_one && !Rc::ptr_eq(&xml_module, &module) {
96-
// no diagnostic to create.
82+
if xml_module.borrow().as_module_package().xml_ids.get(&Sy!(id.clone())).is_none() {
83+
xml_module.borrow_mut().as_module_package_mut().xml_ids.insert(Sy!(id.clone()), vec![]);
9784
}
98-
xml_module.borrow_mut().as_module_package_mut().xml_ids.get_mut(&Sy!(id)).unwrap().insert(self.xml_symbol.clone());
85+
xml_data.set_symbol(self.xml_symbol.clone());
86+
xml_module.borrow_mut().as_module_package_mut().xml_ids.get_mut(&Sy!(id)).unwrap().push(xml_data);
9987
}
10088
}
10189

102-
pub fn get_xml_ids(&self, session: &mut SessionInfo, xml_id: &str, attr: &Attribute, diagnostics: &mut Vec<Diagnostic>) -> Vec<Rc<RefCell<Symbol>>> {
90+
pub fn get_xml_ids(&self, session: &mut SessionInfo, xml_id: &str, attr: &Attribute, diagnostics: &mut Vec<Diagnostic>) -> Vec<XmlData> {
10391
let mut res = vec![];
10492
if !self.is_in_main_ep {
10593
return res;
@@ -134,9 +122,23 @@ impl XmlArchBuilder {
134122
return res;
135123
}
136124
let module = module.unwrap();
137-
for module in module.borrow().as_module_package().this_and_dependencies(session).iter() {
138-
if let Some(xml) = module.borrow().as_module_package().xml_ids.get(&oyarn!("{}", id_split.last().unwrap())) {
139-
res.extend(xml.iter());
125+
if let Some(xml) = module.borrow().as_module_package().xml_ids.get(&oyarn!("{}", id_split.last().unwrap())) {
126+
res.extend(xml.iter().map(|x| x.clone()));
127+
}
128+
res
129+
}
130+
131+
pub fn get_group_ids(&self, session: &mut SessionInfo, xml_id: &str, attr: &Attribute, diagnostics: &mut Vec<Diagnostic>) -> Vec<XmlData> {
132+
let xml_ids = self.get_xml_ids(session, xml_id, attr, diagnostics);
133+
let mut res = vec![];
134+
for data in xml_ids.iter() {
135+
match data {
136+
XmlData::RECORD(r) => {
137+
if r.model == "res.groups" {
138+
res.push(data.clone());
139+
}
140+
},
141+
_ => {}
140142
}
141143
}
142144
res

server/src/core/xml_arch_builder_rng_validation.rs

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ use once_cell::sync::Lazy;
33
use regex::Regex;
44
use roxmltree::Node;
55

6-
use crate::{core::diagnostics::{create_diagnostic, DiagnosticCode}, threads::SessionInfo, S};
6+
use crate::{core::diagnostics::{create_diagnostic, DiagnosticCode}};
7+
use crate::{constants::{BuildStatus, BuildSteps, OYarn, EXTENSION_NAME}, core::xml_data::{XmlData, XmlDataActWindow, XmlDataDelete, XmlDataMenuItem, XmlDataRecord, XmlDataReport, XmlDataTemplate}, oyarn, threads::SessionInfo, Sy, S};
78

89
use super::xml_arch_builder::XmlArchBuilder;
910

@@ -76,7 +77,20 @@ impl XmlArchBuilder {
7677
}
7778
}
7879
},
79-
"name" | "groups" | "active" => {},
80+
"groups" => {
81+
for group in attr.value().split(",") {
82+
let group = group.trim_start_matches("-");
83+
if self.get_group_ids(session, group, &attr, diagnostics).is_empty() {
84+
if let Some(diagnostic) = create_diagnostic(session, DiagnosticCode::OLS05054, &[group]) {
85+
diagnostics.push(Diagnostic {
86+
range: Range { start: Position::new(attr.range().start as u32, 0), end: Position::new(attr.range().end as u32, 0) },
87+
..diagnostic.clone()
88+
});
89+
}
90+
}
91+
}
92+
},
93+
"name" | "active" => {},
8094
"action" => {
8195
if (has_parent || is_submenu) && node.has_children() {
8296
let other_than_text = node.children().any(|c| !c.is_text() && !c.is_comment());
@@ -91,7 +105,7 @@ impl XmlArchBuilder {
91105
}
92106
//check that action exists
93107
if self.get_xml_ids(session, attr.value(), &attr, diagnostics).is_empty() {
94-
if let Some(diagnostic) = create_diagnostic(session, DiagnosticCode::OLS05053, &[]) {
108+
if let Some(diagnostic) = create_diagnostic(session, DiagnosticCode::OLS05053, &[attr.value()]) {
95109
diagnostics.push(Diagnostic {
96110
range: Range { start: Position::new(attr.range().start as u32, 0), end: Position::new(attr.range().end as u32, 0) },
97111
..diagnostic.clone()
@@ -110,7 +124,7 @@ impl XmlArchBuilder {
110124
} else {
111125
//check that parent exists
112126
if self.get_xml_ids(session, attr.value(), &attr, diagnostics).is_empty() {
113-
if let Some(diagnostic) = create_diagnostic(session, DiagnosticCode::OLS05052, &[]) {
127+
if let Some(diagnostic) = create_diagnostic(session, DiagnosticCode::OLS05052, &[attr.value()]) {
114128
diagnostics.push(Diagnostic {
115129
range: Range { start: Position::new(attr.range().start as u32, 0), end: Position::new(attr.range().end as u32, 0) },
116130
..diagnostic.clone()
@@ -160,7 +174,11 @@ impl XmlArchBuilder {
160174
self.load_menuitem(session, &child, true, diagnostics);
161175
}
162176
}
163-
self.on_operation_creation(session, found_id, node, diagnostics);
177+
let data = XmlData::MENUITEM(XmlDataMenuItem {
178+
xml_symbol: self.xml_symbol.clone(),
179+
xml_id: found_id.clone().map(|id| oyarn!("{}", id)),
180+
});
181+
self.on_operation_creation(session, found_id, node, data, diagnostics);
164182
true
165183
}
166184

@@ -206,7 +224,12 @@ impl XmlArchBuilder {
206224
}
207225
}
208226
}
209-
self.on_operation_creation(session, found_id, node, diagnostics);
227+
let data = XmlData::RECORD(XmlDataRecord {
228+
xml_symbol: self.xml_symbol.clone(),
229+
model: oyarn!("{}", node.attribute("model").unwrap()),
230+
xml_id: found_id.clone().map(|id| oyarn!("{}", id)),
231+
});
232+
self.on_operation_creation(session, found_id, node, data, diagnostics);
210233
true
211234
}
212235

@@ -420,7 +443,11 @@ impl XmlArchBuilder {
420443
if node.tag_name().name() != "template" { return false; }
421444
//no interesting rule to check, as 'any' is valid
422445
let found_id = node.attribute("id").map(|s| s.to_string());
423-
self.on_operation_creation(session, found_id, node, diagnostics);
446+
let data = XmlData::TEMPLATE(XmlDataTemplate {
447+
xml_symbol: self.xml_symbol.clone(),
448+
xml_id: found_id.clone().map(|id| oyarn!("{}", id)),
449+
});
450+
self.on_operation_creation(session, found_id, node, data, diagnostics);
424451
true
425452
}
426453

@@ -452,7 +479,12 @@ impl XmlArchBuilder {
452479
});
453480
}
454481
}
455-
self.on_operation_creation(session, found_id, node, diagnostics);
482+
let data = XmlData::DELETE(XmlDataDelete {
483+
xml_symbol: self.xml_symbol.clone(),
484+
xml_id: found_id.clone().map(|id| oyarn!("{}", id)),
485+
model: Sy!(node.attribute("model").unwrap().to_string()),
486+
});
487+
self.on_operation_creation(session, found_id, node, data, diagnostics);
456488
true
457489
}
458490

@@ -514,7 +546,13 @@ impl XmlArchBuilder {
514546
});
515547
}
516548
}
517-
self.on_operation_creation(session, found_id, node, diagnostics);
549+
let data = XmlData::ACT_WINDOW(XmlDataActWindow {
550+
xml_symbol: self.xml_symbol.clone(),
551+
xml_id: found_id.clone().map(|id| oyarn!("{}", id)),
552+
res_model: Sy!(node.attribute("res_model").unwrap().to_string()),
553+
name: Sy!(node.attribute("name").unwrap().to_string()),
554+
});
555+
self.on_operation_creation(session, found_id, node, data, diagnostics);
518556
true
519557
}
520558

@@ -554,7 +592,14 @@ impl XmlArchBuilder {
554592
});
555593
}
556594
}
557-
self.on_operation_creation(session, found_id, node, diagnostics);
595+
let data = XmlData::REPORT(XmlDataReport {
596+
xml_symbol: self.xml_symbol.clone(),
597+
xml_id: found_id.clone().map(|id| oyarn!("{}", id)),
598+
name: Sy!(node.attribute("name").unwrap().to_string()),
599+
model: Sy!(node.attribute("model").unwrap().to_string()),
600+
string: Sy!(node.attribute("string").unwrap().to_string()),
601+
});
602+
self.on_operation_creation(session, found_id, node, data, diagnostics);
558603
true
559604
}
560605

server/src/core/xml_data.rs

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
use std::{cell::RefCell, rc::Rc};
2+
3+
use crate::{constants::OYarn, core::symbols::symbol::Symbol};
4+
5+
6+
#[derive(Debug, Clone)]
7+
pub enum XmlData {
8+
RECORD(XmlDataRecord),
9+
MENUITEM(XmlDataMenuItem),
10+
TEMPLATE(XmlDataTemplate),
11+
DELETE(XmlDataDelete),
12+
ACT_WINDOW(XmlDataActWindow),
13+
REPORT(XmlDataReport),
14+
}
15+
16+
#[derive(Debug, Clone)]
17+
pub struct XmlDataRecord {
18+
pub xml_symbol: Rc<RefCell<Symbol>>,
19+
pub model: OYarn,
20+
pub xml_id: Option<OYarn>,
21+
}
22+
23+
#[derive(Debug, Clone)]
24+
pub struct XmlDataMenuItem {
25+
pub xml_symbol: Rc<RefCell<Symbol>>,
26+
pub xml_id: Option<OYarn>,
27+
}
28+
29+
#[derive(Debug, Clone)]
30+
pub struct XmlDataTemplate {
31+
pub xml_symbol: Rc<RefCell<Symbol>>,
32+
pub xml_id: Option<OYarn>,
33+
}
34+
35+
#[derive(Debug, Clone)]
36+
pub struct XmlDataDelete {
37+
pub xml_symbol: Rc<RefCell<Symbol>>,
38+
pub xml_id: Option<OYarn>,
39+
pub model: OYarn,
40+
}
41+
42+
#[derive(Debug, Clone)]
43+
pub struct XmlDataActWindow {
44+
pub xml_symbol: Rc<RefCell<Symbol>>,
45+
pub xml_id: Option<OYarn>,
46+
pub name: OYarn,
47+
pub res_model: OYarn,
48+
}
49+
50+
#[derive(Debug, Clone)]
51+
pub struct XmlDataReport {
52+
pub xml_symbol: Rc<RefCell<Symbol>>,
53+
pub xml_id: Option<OYarn>,
54+
pub name: OYarn,
55+
pub model: OYarn,
56+
pub string: OYarn,
57+
}
58+
59+
impl XmlData {
60+
61+
pub fn set_symbol(&mut self, xml_symbol: Rc<RefCell<Symbol>>) {
62+
match self {
63+
XmlData::RECORD(ref mut record) => {
64+
record.xml_symbol = xml_symbol;
65+
},
66+
XmlData::MENUITEM(ref mut menu_item) => {
67+
menu_item.xml_symbol = xml_symbol;
68+
},
69+
XmlData::TEMPLATE(ref mut template) => {
70+
template.xml_symbol = xml_symbol;
71+
},
72+
XmlData::DELETE(ref mut delete) => {
73+
delete.xml_symbol = xml_symbol;
74+
},
75+
XmlData::ACT_WINDOW(ref mut act_window) => {
76+
act_window.xml_symbol = xml_symbol;
77+
},
78+
XmlData::REPORT(ref mut report) => {
79+
report.xml_symbol = xml_symbol;
80+
},
81+
}
82+
}
83+
84+
pub fn get_symbol(&self) -> Option<Rc<RefCell<Symbol>>> {
85+
match self {
86+
XmlData::RECORD(ref record) => {
87+
Some(record.xml_symbol.clone())
88+
},
89+
XmlData::MENUITEM(ref menu_item) => {
90+
Some(menu_item.xml_symbol.clone())
91+
},
92+
XmlData::TEMPLATE(ref template) => {
93+
Some(template.xml_symbol.clone())
94+
},
95+
XmlData::DELETE(ref delete) => {
96+
Some(delete.xml_symbol.clone())
97+
},
98+
XmlData::ACT_WINDOW(ref act_window) => {
99+
Some(act_window.xml_symbol.clone())
100+
},
101+
XmlData::REPORT(ref report) => {
102+
Some(report.xml_symbol.clone())
103+
},
104+
}
105+
}
106+
}

0 commit comments

Comments
 (0)