Merge lp:~openerp-dev/openobject-server/trunk-project-task-stage-access-rights-ima into lp:openobject-server

Proposed by Ishwar Malvi(OpenERP)
Status: Needs review
Proposed branch: lp:~openerp-dev/openobject-server/trunk-project-task-stage-access-rights-ima
Merge into: lp:openobject-server
Diff against target: 279 lines (+269/-0)
1 file modified
openerp/osv/orm.py (+269/-0)
To merge this branch: bzr merge lp:~openerp-dev/openobject-server/trunk-project-task-stage-access-rights-ima
Reviewer Review Type Date Requested Status
OpenERP Core Team Pending
Review via email: mp+191981@code.launchpad.net

Description of the change

Hello,
     I have updated __view_look_dom_arch method in orm for kanban view to set groups right in xml.

Thanks,
Ishwar Malvi

To post a comment you must log in.
4952. By Ishwar Malvi(OpenERP)

[MERGE]with latest.

4953. By Bharat Devnani (Open ERP)

[MERGE] merged with main server

Unmerged revisions

4953. By Bharat Devnani (Open ERP)

[MERGE] merged with main server

4952. By Ishwar Malvi(OpenERP)

[MERGE]with latest.

4951. By Ishwar Malvi(OpenERP)

[MERGE]with trunk.

4950. By Vidhin Mehta (OpenERP)

[IMP]set group right in xml for kanban view.

4949. By Ishwar Malvi(OpenERP)

[IMP]improved code.

4948. By Ishwar Malvi(OpenERP)

[IMP]hide the link add a new column,edit and delete in kanban if the user has not the right to do it.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'openerp/osv/orm.py'
--- openerp/osv/orm.py 2014-02-20 16:05:48 +0000
+++ openerp/osv/orm.py 2014-03-04 06:27:49 +0000
@@ -1704,6 +1704,275 @@
1704 return any([self.pool.get('res.users').has_group(cr, uid, group_ext_id)1704 return any([self.pool.get('res.users').has_group(cr, uid, group_ext_id)
1705 for group_ext_id in groups.split(',')])1705 for group_ext_id in groups.split(',')])
17061706
1707 def __view_look_dom(self, cr, user, node, view_id, in_tree_view, model_fields, context=None):
1708 """Return the description of the fields in the node.
1709
1710 In a normal call to this method, node is a complete view architecture
1711 but it is actually possible to give some sub-node (this is used so
1712 that the method can call itself recursively).
1713
1714 Originally, the field descriptions are drawn from the node itself.
1715 But there is now some code calling fields_get() in order to merge some
1716 of those information in the architecture.
1717
1718 """
1719 if context is None:
1720 context = {}
1721 result = False
1722 fields = {}
1723 children = True
1724
1725 modifiers = {}
1726
1727 def encode(s):
1728 if isinstance(s, unicode):
1729 return s.encode('utf8')
1730 return s
1731
1732 def check_group(node):
1733 """Apply group restrictions, may be set at view level or model level::
1734 * at view level this means the element should be made invisible to
1735 people who are not members
1736 * at model level (exclusively for fields, obviously), this means
1737 the field should be completely removed from the view, as it is
1738 completely unavailable for non-members
1739
1740 :return: True if field should be included in the result of fields_view_get
1741 """
1742 if node.tag == 'field' and node.get('name') in self._all_columns:
1743 column = self._all_columns[node.get('name')].column
1744 if column.groups and not self.user_has_groups(cr, user,
1745 groups=column.groups,
1746 context=context):
1747 node.getparent().remove(node)
1748 fields.pop(node.get('name'), None)
1749 # no point processing view-level ``groups`` anymore, return
1750 return False
1751 if node.get('groups'):
1752 can_see = self.user_has_groups(cr, user,
1753 groups=node.get('groups'),
1754 context=context)
1755 if not can_see:
1756 node.set('invisible', '1')
1757 modifiers['invisible'] = True
1758 if 'attrs' in node.attrib:
1759 del(node.attrib['attrs']) #avoid making field visible later
1760 del(node.attrib['groups'])
1761 return True
1762
1763 if node.tag in ('field', 'node', 'arrow'):
1764 if node.get('object'):
1765 attrs = {}
1766 views = {}
1767 xml = "<form>"
1768 for f in node:
1769 if f.tag == 'field':
1770 xml += etree.tostring(f, encoding="utf-8")
1771 xml += "</form>"
1772 new_xml = etree.fromstring(encode(xml))
1773 ctx = context.copy()
1774 ctx['base_model_name'] = self._name
1775 xarch, xfields = self.pool[node.get('object')].__view_look_dom_arch(cr, user, new_xml, view_id, ctx)
1776 views['form'] = {
1777 'arch': xarch,
1778 'fields': xfields
1779 }
1780 attrs = {'views': views}
1781 fields = xfields
1782 if node.get('name'):
1783 attrs = {}
1784 try:
1785 if node.get('name') in self._columns:
1786 column = self._columns[node.get('name')]
1787 else:
1788 column = self._inherit_fields[node.get('name')][2]
1789 except Exception:
1790 column = False
1791
1792 if column:
1793 relation = self.pool[column._obj] if column._obj else None
1794
1795 children = False
1796 views = {}
1797 for f in node:
1798 if f.tag in ('form', 'tree', 'graph', 'kanban'):
1799 node.remove(f)
1800 ctx = context.copy()
1801 ctx['base_model_name'] = self._name
1802 xarch, xfields = relation.__view_look_dom_arch(cr, user, f, view_id, ctx)
1803 views[str(f.tag)] = {
1804 'arch': xarch,
1805 'fields': xfields
1806 }
1807 attrs = {'views': views}
1808 if node.get('widget') and node.get('widget') == 'selection':
1809 # Prepare the cached selection list for the client. This needs to be
1810 # done even when the field is invisible to the current user, because
1811 # other events could need to change its value to any of the selectable ones
1812 # (such as on_change events, refreshes, etc.)
1813
1814 # If domain and context are strings, we keep them for client-side, otherwise
1815 # we evaluate them server-side to consider them when generating the list of
1816 # possible values
1817 # TODO: find a way to remove this hack, by allow dynamic domains
1818 dom = []
1819 if column._domain and not isinstance(column._domain, basestring):
1820 dom = list(column._domain)
1821 dom += eval(node.get('domain', '[]'), {'uid': user, 'time': time})
1822 search_context = dict(context)
1823 if column._context and not isinstance(column._context, basestring):
1824 search_context.update(column._context)
1825 attrs['selection'] = relation._name_search(cr, user, '', dom, context=search_context, limit=None, name_get_uid=1)
1826 if (node.get('required') and not int(node.get('required'))) or not column.required:
1827 attrs['selection'].append((False, ''))
1828 fields[node.get('name')] = attrs
1829
1830 field = model_fields.get(node.get('name'))
1831 if field:
1832 transfer_field_to_modifiers(field, modifiers)
1833
1834
1835 elif node.tag in ('form', 'tree'):
1836 result = self.view_header_get(cr, user, False, node.tag, context)
1837 if result:
1838 node.set('string', result)
1839 in_tree_view = node.tag == 'tree'
1840
1841 elif node.tag == 'calendar':
1842 for additional_field in ('date_start', 'date_delay', 'date_stop', 'color'):
1843 if node.get(additional_field):
1844 fields[node.get(additional_field)] = {}
1845
1846 if not check_group(node):
1847 # node must be removed, no need to proceed further with its children
1848 return fields
1849
1850 # The view architeture overrides the python model.
1851 # Get the attrs before they are (possibly) deleted by check_group below
1852 transfer_node_to_modifiers(node, modifiers, context, in_tree_view)
1853
1854 # TODO remove attrs couterpart in modifiers when invisible is true ?
1855
1856 # translate view
1857 if 'lang' in context:
1858 if node.text and node.text.strip():
1859 trans = self.pool.get('ir.translation')._get_source(cr, user, self._name, 'view', context['lang'], node.text.strip())
1860 if trans:
1861 node.text = node.text.replace(node.text.strip(), trans)
1862 if node.tail and node.tail.strip():
1863 trans = self.pool.get('ir.translation')._get_source(cr, user, self._name, 'view', context['lang'], node.tail.strip())
1864 if trans:
1865 node.tail = node.tail.replace(node.tail.strip(), trans)
1866
1867 if node.get('string') and not result:
1868 trans = self.pool.get('ir.translation')._get_source(cr, user, self._name, 'view', context['lang'], node.get('string'))
1869 if trans == node.get('string') and ('base_model_name' in context):
1870 # If translation is same as source, perhaps we'd have more luck with the alternative model name
1871 # (in case we are in a mixed situation, such as an inherited view where parent_view.model != model
1872 trans = self.pool.get('ir.translation')._get_source(cr, user, context['base_model_name'], 'view', context['lang'], node.get('string'))
1873 if trans:
1874 node.set('string', trans)
1875
1876 for attr_name in ('confirm', 'sum', 'avg', 'help', 'placeholder'):
1877 attr_value = node.get(attr_name)
1878 if attr_value:
1879 trans = self.pool.get('ir.translation')._get_source(cr, user, self._name, 'view', context['lang'], attr_value)
1880 if trans:
1881 node.set(attr_name, trans)
1882
1883 for f in node:
1884 if children or (node.tag == 'field' and f.tag in ('filter','separator')):
1885 fields.update(self.__view_look_dom(cr, user, f, view_id, in_tree_view, model_fields, context))
1886
1887 transfer_modifiers_to_node(modifiers, node)
1888 return fields
1889
1890 def _disable_workflow_buttons(self, cr, user, node):
1891 """ Set the buttons in node to readonly if the user can't activate them. """
1892 if user == 1:
1893 # admin user can always activate workflow buttons
1894 return node
1895
1896 # TODO handle the case of more than one workflow for a model or multiple
1897 # transitions with different groups and same signal
1898 usersobj = self.pool.get('res.users')
1899 buttons = (n for n in node.getiterator('button') if n.get('type') != 'object')
1900 for button in buttons:
1901 user_groups = usersobj.read(cr, user, [user], ['groups_id'])[0]['groups_id']
1902 cr.execute("""SELECT DISTINCT t.group_id
1903 FROM wkf
1904 INNER JOIN wkf_activity a ON a.wkf_id = wkf.id
1905 INNER JOIN wkf_transition t ON (t.act_to = a.id)
1906 WHERE wkf.osv = %s
1907 AND t.signal = %s
1908 AND t.group_id is NOT NULL
1909 """, (self._name, button.get('name')))
1910 group_ids = [x[0] for x in cr.fetchall() if x[0]]
1911 can_click = not group_ids or bool(set(user_groups).intersection(group_ids))
1912 button.set('readonly', str(int(not can_click)))
1913 return node
1914
1915 def __view_look_dom_arch(self, cr, user, node, view_id, context=None):
1916 """ Return an architecture and a description of all the fields.
1917
1918 The field description combines the result of fields_get() and
1919 __view_look_dom().
1920
1921 :param node: the architecture as as an etree
1922 :return: a tuple (arch, fields) where arch is the given node as a
1923 string and fields is the description of all the fields.
1924
1925 """
1926 fields = {}
1927 if node.tag == 'diagram':
1928 if node.getchildren()[0].tag == 'node':
1929 node_model = self.pool[node.getchildren()[0].get('object')]
1930 node_fields = node_model.fields_get(cr, user, None, context)
1931 fields.update(node_fields)
1932 if not node.get("create") and not node_model.check_access_rights(cr, user, 'create', raise_exception=False):
1933 node.set("create", 'false')
1934 if node.getchildren()[1].tag == 'arrow':
1935 arrow_fields = self.pool[node.getchildren()[1].get('object')].fields_get(cr, user, None, context)
1936 fields.update(arrow_fields)
1937 else:
1938 fields = self.fields_get(cr, user, None, context)
1939 fields_def = self.__view_look_dom(cr, user, node, view_id, False, fields, context=context)
1940 node = self._disable_workflow_buttons(cr, user, node)
1941 if node.tag in ('kanban', 'tree', 'form', 'gantt'):
1942 for action, operation in (('create', 'create'), ('delete', 'unlink'), ('edit', 'write')):
1943 if not node.get(action) and not self.check_access_rights(cr, user, operation, raise_exception=False):
1944 node.set(action, 'false')
1945 if node.tag in ('kanban'):
1946 group_by_field = node.get('default_group_by')
1947 if group_by_field:
1948 group_by_object = self.fields_get(cr, user, None, context)[group_by_field]
1949 if (group_by_object['type'] == 'many2one'):
1950 group_by_model = self.pool.get(group_by_object['relation'])
1951 for action, operation in (('group_create', 'create'), ('group_delete', 'unlink'), ('group_edit', 'write')):
1952 if not node.get(action) and not group_by_model.check_access_rights(cr, user, operation, raise_exception=False):
1953 node.set(action, 'false')
1954
1955 arch = etree.tostring(node, encoding="utf-8").replace('\t', '')
1956 for k in fields.keys():
1957 if k not in fields_def:
1958 del fields[k]
1959 for field in fields_def:
1960 if field == 'id':
1961 # sometime, the view may contain the (invisible) field 'id' needed for a domain (when 2 objects have cross references)
1962 fields['id'] = {'readonly': True, 'type': 'integer', 'string': 'ID'}
1963 elif field in fields:
1964 fields[field].update(fields_def[field])
1965 else:
1966 cr.execute('select name, model from ir_ui_view where (id=%s or inherit_id=%s) and arch like %s', (view_id, view_id, '%%%s%%' % field))
1967 res = cr.fetchall()[:]
1968 model = res[0][1]
1969 res.insert(0, ("Can't find field '%s' in the following view parts composing the view of object model '%s':" % (field, model), None))
1970 msg = "\n * ".join([r[0] for r in res])
1971 msg += "\n\nEither you wrongly customized this view, or some modules bringing those views are not compatible with your current data model"
1972 _logger.error(msg)
1973 raise except_orm('View error', msg)
1974 return arch, fields
1975
1707 def _get_default_form_view(self, cr, user, context=None):1976 def _get_default_form_view(self, cr, user, context=None):
1708 """ Generates a default single-line form view using all fields1977 """ Generates a default single-line form view using all fields
1709 of the current model except the m2m and o2m ones.1978 of the current model except the m2m and o2m ones.