From 6d45c755f2215c3eda3466d641bd96952096e7a8 Mon Sep 17 00:00:00 2001 From: Florent THOMAS Date: Sat, 5 Feb 2022 23:09:02 +0100 Subject: [PATCH] clean up --- .eslintrc.yml | 180 +++++++++++++ .flake8 | 10 + .pre-commit-config.yaml | 239 ++++++++---------- .prettierrc.yml | 8 + .pylintrc | 88 +++++++ .pylintrc-mandatory | 2 +- document_page/__manifest__.py | 55 ++-- document_page/chmod | 0 document_page/demo/document_page.xml | 16 +- document_page/images/category_list.png | Bin document_page/images/create_category.png | Bin document_page/images/create_page.png | Bin document_page/images/page_history.png | Bin document_page/images/page_list.png | Bin document_page/models/document_page.py | 168 ++++++------ document_page/models/document_page_history.py | 43 ++-- document_page/readme/CONTRIBUTORS.rst | 4 +- .../security/document_page_security.xml | 31 ++- document_page/static/description/icon.png | Bin document_page/static/description/index.html | 0 .../static/src/css/document_page.css | 17 +- .../static/src/js/document_page_kanban.js | 30 +-- document_page/tests/test_document_page.py | 52 ++-- .../tests/test_document_page_create_menu.py | 16 +- .../tests/test_document_page_history.py | 13 +- .../tests/test_document_page_show_diff.py | 14 +- document_page/views/document_page.xml | 197 ++++++++++----- document_page/views/document_page_assets.xml | 18 +- .../views/document_page_category.xml | 168 ++++++++---- document_page/views/document_page_history.xml | 60 +++-- document_page/views/report_document_page.xml | 2 +- .../wizard/document_page_create_menu.py | 64 +++-- .../wizard/document_page_create_menu.xml | 22 +- .../wizard/document_page_show_diff.py | 14 +- .../wizard/document_page_show_diff.xml | 19 +- 35 files changed, 988 insertions(+), 562 deletions(-) create mode 100644 .eslintrc.yml create mode 100644 .flake8 create mode 100644 .prettierrc.yml create mode 100644 .pylintrc create mode 100644 document_page/chmod mode change 100644 => 100755 document_page/images/category_list.png mode change 100644 => 100755 document_page/images/create_category.png mode change 100644 => 100755 document_page/images/create_page.png mode change 100644 => 100755 document_page/images/page_history.png mode change 100644 => 100755 document_page/images/page_list.png mode change 100644 => 100755 document_page/static/description/icon.png mode change 100644 => 100755 document_page/static/description/index.html mode change 100755 => 100644 document_page/views/document_page_category.xml mode change 100755 => 100644 document_page/views/document_page_history.xml mode change 100755 => 100644 document_page/views/report_document_page.xml diff --git a/.eslintrc.yml b/.eslintrc.yml new file mode 100644 index 00000000..88f2881b --- /dev/null +++ b/.eslintrc.yml @@ -0,0 +1,180 @@ +env: + browser: true + +# See https://github.com/OCA/odoo-community.org/issues/37#issuecomment-470686449 +parserOptions: + ecmaVersion: 2017 + +# Globals available in Odoo that shouldn't produce errorings +globals: + _: readonly + $: readonly + fuzzy: readonly + jQuery: readonly + moment: readonly + odoo: readonly + openerp: readonly + Promise: readonly + +# Styling is handled by Prettier, so we only need to enable AST rules; +# see https://github.com/OCA/maintainer-quality-tools/pull/618#issuecomment-558576890 +rules: + accessor-pairs: warn + array-callback-return: warn + callback-return: warn + capitalized-comments: + - warn + - always + - ignoreConsecutiveComments: true + ignoreInlineComments: true + complexity: + - warn + - 15 + constructor-super: warn + dot-notation: warn + eqeqeq: warn + global-require: warn + handle-callback-err: warn + id-blacklist: warn + id-match: warn + init-declarations: error + max-depth: warn + max-nested-callbacks: warn + max-statements-per-line: warn + no-alert: warn + no-array-constructor: warn + no-caller: warn + no-case-declarations: warn + no-class-assign: warn + no-cond-assign: error + no-const-assign: error + no-constant-condition: warn + no-control-regex: warn + no-debugger: error + no-delete-var: warn + no-div-regex: warn + no-dupe-args: error + no-dupe-class-members: error + no-dupe-keys: error + no-duplicate-case: error + no-duplicate-imports: error + no-else-return: warn + no-empty-character-class: warn + no-empty-function: error + no-empty-pattern: error + no-empty: warn + no-eq-null: error + no-eval: error + no-ex-assign: error + no-extend-native: warn + no-extra-bind: warn + no-extra-boolean-cast: warn + no-extra-label: warn + no-fallthrough: warn + no-func-assign: error + no-global-assign: error + no-implicit-coercion: + - warn + - allow: ["~"] + no-implicit-globals: warn + no-implied-eval: warn + no-inline-comments: warn + no-inner-declarations: warn + no-invalid-regexp: warn + no-irregular-whitespace: warn + no-iterator: warn + no-label-var: warn + no-labels: warn + no-lone-blocks: warn + no-lonely-if: error + no-mixed-requires: error + no-multi-str: warn + no-native-reassign: error + no-negated-condition: warn + no-negated-in-lhs: error + no-new-func: warn + no-new-object: warn + no-new-require: warn + no-new-symbol: warn + no-new-wrappers: warn + no-new: warn + no-obj-calls: warn + no-octal-escape: warn + no-octal: warn + no-param-reassign: warn + no-path-concat: warn + no-process-env: warn + no-process-exit: warn + no-proto: warn + no-prototype-builtins: warn + no-redeclare: warn + no-regex-spaces: warn + no-restricted-globals: warn + no-restricted-imports: warn + no-restricted-modules: warn + no-restricted-syntax: warn + no-return-assign: error + no-script-url: warn + no-self-assign: warn + no-self-compare: warn + no-sequences: warn + no-shadow-restricted-names: warn + no-shadow: warn + no-sparse-arrays: warn + no-sync: warn + no-this-before-super: warn + no-throw-literal: warn + no-undef-init: warn + no-undef: error + no-unmodified-loop-condition: warn + no-unneeded-ternary: error + no-unreachable: error + no-unsafe-finally: error + no-unused-expressions: error + no-unused-labels: error + no-unused-vars: error + no-use-before-define: error + no-useless-call: warn + no-useless-computed-key: warn + no-useless-concat: warn + no-useless-constructor: warn + no-useless-escape: warn + no-useless-rename: warn + no-void: warn + no-with: warn + operator-assignment: [error, always] + prefer-const: warn + radix: warn + require-yield: warn + sort-imports: warn + spaced-comment: [error, always] + strict: [error, function] + use-isnan: error + valid-jsdoc: + - warn + - prefer: + arg: param + argument: param + augments: extends + constructor: class + exception: throws + func: function + method: function + prop: property + return: returns + virtual: abstract + yield: yields + preferType: + array: Array + bool: Boolean + boolean: Boolean + number: Number + object: Object + str: String + string: String + requireParamDescription: false + requireReturn: false + requireReturnDescription: false + requireReturnType: false + valid-typeof: warn + yoda: warn diff --git a/.flake8 b/.flake8 new file mode 100644 index 00000000..44ed868f --- /dev/null +++ b/.flake8 @@ -0,0 +1,10 @@ +[flake8] +max-line-length = 80 +max-complexity = 16 +# B = bugbear +# B9 = bugbear opinionated (incl line length) +select = C,E,F,W,B,B9 +# E203: whitespace before ':' (black behaviour) +# E501: flake8 line length (covered by bugbear B950) +# W503: line break before binary operator (black behaviour) +ignore = E203,E501,W503 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cae2ce26..eb782539 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,137 +1,108 @@ exclude: | - (?x) - # NOT INSTALLABLE ADDONS - # END NOT INSTALLABLE ADDONS - # Files and folders generated by bots, to avoid loops - ^setup/|/static/description/index\.html$| - # We don't want to mess with tool-generated files - .svg$|/tests/([^/]+/)?cassettes/|^.copier-answers.yml$|^.github/| - # Maybe reactivate this when all README files include prettier ignore tags? - ^README\.md$| - # Library files can have extraneous formatting (even minimized) - /static/(src/)?lib/| - # Repos using Sphinx to generate docs don't need prettying - ^docs/_templates/.*\.html$| - # You don't usually want a bot to modify your legal texts - (LICENSE.*|COPYING.*) + (?x) + # Files and folders generated by bots, to avoid loops + ^setup/|/static/description/index\.html$| + # Maybe reactivate this when all README files include prettier ignore tags? + ^README\.md$| + # Library files can have extraneous formatting (even minimized) + /static/(src/)?lib/| + # Repos using Sphinx to generate docs don't need prettying + ^docs/_templates/.*\.html$| + # You don't usually want a bot to modify your legal texts + (LICENSE.*|COPYING.*) default_language_version: - python: python3 - node: "14.13.0" + python: python3 + node: "14.13.0" repos: - - repo: local - hooks: - # These files are most likely copier diff rejection junks; if found, - # review them manually, fix the problem (if needed) and remove them - - id: forbidden-files - name: forbidden files - entry: found forbidden files; remove them - language: fail - files: "\\.rej$" - #- repo: https://github.com/oca/maintainer-tools - #rev: ab1d7f6 - #hooks: - #update the NOT INSTALLABLE ADDONS section above - #- id: oca-update-pre-commit-excluded-addons - #- id: oca-fix-manifest-website - #args: ["https://github.com/OCA/project"] - - repo: https://github.com/myint/autoflake - rev: v1.4 - hooks: - - id: autoflake - args: - - --expand-star-imports - - --ignore-init-module-imports - - --in-place - - --remove-all-unused-imports - - --remove-duplicate-keys - - --remove-unused-variables - - repo: https://github.com/psf/black - rev: 20.8b1 - hooks: - - id: black - - repo: https://github.com/pre-commit/mirrors-prettier - rev: v2.1.2 - hooks: - - id: prettier - name: prettier (with plugin-xml) - additional_dependencies: - - "prettier@2.1.2" - - "@prettier/plugin-xml@0.12.0" - args: - - --plugin=@prettier/plugin-xml - files: \.(css|htm|html|js|json|jsx|less|md|scss|toml|ts|xml|yaml|yml)$ - - repo: https://github.com/pre-commit/mirrors-eslint - rev: v7.8.1 - hooks: - - id: eslint - verbose: true - args: - - --color - - --fix - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.2.0 - hooks: - - id: trailing-whitespace - # exclude autogenerated files - exclude: /README\.rst$|\.pot?$ - - id: end-of-file-fixer - # exclude autogenerated files - exclude: /README\.rst$|\.pot?$ - - id: debug-statements - - id: fix-encoding-pragma - args: ["--remove"] - - id: check-case-conflict - - id: check-docstring-first - - id: check-executables-have-shebangs - - id: check-merge-conflict - # exclude files where underlines are not distinguishable from merge conflicts - exclude: /README\.rst$|^docs/.*\.rst$ - - id: check-symlinks - - id: check-xml - - id: mixed-line-ending - args: ["--fix=lf"] - - repo: https://github.com/asottile/pyupgrade - rev: v2.7.2 - hooks: - - id: pyupgrade - args: ["--keep-percent-format"] - - repo: https://github.com/PyCQA/isort - rev: 5.5.1 - hooks: - - id: isort - name: isort except __init__.py - args: - - --settings=. - exclude: /__init__\.py$ - - repo: https://github.com/acsone/setuptools-odoo - rev: 2.6.0 - hooks: - - id: setuptools-odoo-make-default - - id: setuptools-odoo-get-requirements - args: - - --output - - requirements.txt - - --header - - "# generated from manifests external_dependencies" - - repo: https://gitlab.com/PyCQA/flake8 - rev: 3.8.3 - hooks: - - id: flake8 - name: flake8 - additional_dependencies: ["flake8-bugbear==20.1.4"] - - repo: https://github.com/PyCQA/pylint - rev: pylint-2.5.3 - hooks: - - id: pylint - name: pylint with optional checks - args: - - --rcfile=.pylintrc - - --exit-zero - verbose: true - additional_dependencies: &pylint_deps - - pylint-odoo==3.5.0 - - id: pylint - name: pylint with mandatory checks - args: - - --rcfile=.pylintrc-mandatory - additional_dependencies: *pylint_deps + - repo: https://github.com/myint/autoflake + rev: v1.4 + hooks: + - id: autoflake + args: ["-i", "--ignore-init-module-imports"] + - repo: https://github.com/psf/black + rev: 19.10b0 + hooks: + - id: black + - repo: https://github.com/prettier/pre-commit + rev: "v1.19.1" + hooks: + - id: prettier + # TODO Avoid awebdeveloper/pre-commit-prettier if possible + # HACK https://github.com/prettier/prettier/issues/7407 + - repo: https://github.com/awebdeveloper/pre-commit-prettier + rev: v0.0.1 + hooks: + - id: prettier + name: prettier xml plugin + additional_dependencies: + - "prettier@1.19.1" + - "@prettier/plugin-xml@0.7.2" + files: \.xml$ + - repo: https://github.com/pre-commit/mirrors-eslint + rev: v6.8.0 + hooks: + - id: eslint + verbose: true + args: + - --color + - --fix + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v2.4.0 + hooks: + - id: trailing-whitespace + # exclude autogenerated files + exclude: /README\.rst$|\.pot?$ + - id: end-of-file-fixer + # exclude autogenerated files + exclude: /README\.rst$|\.pot?$ + - id: debug-statements + - id: fix-encoding-pragma + args: ["--remove"] + - id: check-case-conflict + - id: check-docstring-first + - id: check-executables-have-shebangs + - id: check-merge-conflict + # exclude files where underlines are not distinguishable from merge conflicts + exclude: /README\.rst$|^docs/.*\.rst$ + - id: check-symlinks + - id: check-xml + - id: mixed-line-ending + args: ["--fix=lf"] + - repo: https://gitlab.com/pycqa/flake8 + rev: 3.7.9 + hooks: + - id: flake8 + name: flake8 except __init__.py + exclude: /__init__\.py$ + additional_dependencies: ["flake8-bugbear==19.8.0"] + - id: flake8 + name: flake8 only __init__.py + args: ["--extend-ignore=F401"] # ignore unused imports in __init__.py + files: /__init__\.py$ + additional_dependencies: ["flake8-bugbear==19.8.0"] + - repo: https://github.com/pre-commit/mirrors-pylint + rev: v2.5.3 + hooks: + - id: pylint + name: pylint with optional checks + args: ["--rcfile=.pylintrc", "--exit-zero"] + verbose: true + additional_dependencies: ["pylint-odoo==3.5.0"] + - id: pylint + name: pylint with mandatory checks + args: ["--rcfile=.pylintrc-mandatory"] + additional_dependencies: ["pylint-odoo==3.5.0"] + - repo: https://github.com/asottile/pyupgrade + rev: v1.26.2 + hooks: + - id: pyupgrade + - repo: https://github.com/pre-commit/mirrors-isort + rev: v4.3.21 + hooks: + - id: isort + name: isort except __init__.py + exclude: /__init__\.py$ + - repo: https://github.com/acsone/setuptools-odoo + rev: 2.5.2 + hooks: + - id: setuptools-odoo-make-default diff --git a/.prettierrc.yml b/.prettierrc.yml new file mode 100644 index 00000000..5b6d4b36 --- /dev/null +++ b/.prettierrc.yml @@ -0,0 +1,8 @@ +# Defaults for all prettier-supported languages. +# Prettier will complete this with settings from .editorconfig file. +bracketSpacing: false +printWidth: 88 +proseWrap: always +semi: true +trailingComma: "es5" +xmlWhitespaceSensitivity: "strict" diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 00000000..74a0926a --- /dev/null +++ b/.pylintrc @@ -0,0 +1,88 @@ +[MASTER] +load-plugins=pylint_odoo +score=n + +[ODOOLINT] +readme_template_url="https://github.com/OCA/maintainer-tools/blob/master/template/module/README.rst" +manifest_required_authors=Odoo Community Association (OCA) +manifest_required_keys=license +manifest_deprecated_keys=description,active +license_allowed=AGPL-3,GPL-2,GPL-2 or any later version,GPL-3,GPL-3 or any later version,LGPL-3 +valid_odoo_versions=12.0 + +[MESSAGES CONTROL] +disable=all + +# This .pylintrc contains optional AND mandatory checks and is meant to be +# loaded in an IDE to have it check everything, in the hope this will make +# optional checks more visible to contributors who otherwise never look at a +# green travis to see optional checks that failed. +# .pylintrc-mandatory containing only mandatory checks is used the pre-commit +# config as a blocking check. + +enable=anomalous-backslash-in-string, + api-one-deprecated, + api-one-multi-together, + assignment-from-none, + attribute-deprecated, + class-camelcase, + dangerous-default-value, + dangerous-view-replace-wo-priority, + development-status-allowed, + duplicate-id-csv, + duplicate-key, + duplicate-xml-fields, + duplicate-xml-record-id, + eval-referenced, + eval-used, + incoherent-interpreter-exec-perm, + license-allowed, + manifest-author-string, + manifest-deprecated-key, + manifest-required-author, + manifest-required-key, + manifest-version-format, + method-compute, + method-inverse, + method-required-super, + method-search, + openerp-exception-warning, + pointless-statement, + pointless-string-statement, + print-used, + redundant-keyword-arg, + redundant-modulename-xml, + reimported, + relative-import, + return-in-init, + rst-syntax-error, + sql-injection, + too-few-format-args, + translation-field, + translation-required, + unreachable, + use-vim-comment, + wrong-tabs-instead-of-spaces, + xml-syntax-error, + # messages that do not cause the lint step to fail + consider-merging-classes-inherited, + create-user-wo-reset-password, + dangerous-filter-wo-user, + deprecated-module, + file-not-used, + invalid-commit, + missing-manifest-dependency, + missing-newline-extrafiles, + missing-readme, + no-utf8-coding-comment, + odoo-addons-relative-import, + old-api7-method-defined, + redefined-builtin, + too-complex, + unnecessary-utf8-coding-comment + + +[REPORTS] +msg-template={path}:{line}: [{msg_id}({symbol}), {obj}] {msg} +output-format=colorized +reports=no diff --git a/.pylintrc-mandatory b/.pylintrc-mandatory index d103a97e..ed05c824 100644 --- a/.pylintrc-mandatory +++ b/.pylintrc-mandatory @@ -8,7 +8,7 @@ manifest_required_authors=Odoo Community Association (OCA) manifest_required_keys=license manifest_deprecated_keys=description,active license_allowed=AGPL-3,GPL-2,GPL-2 or any later version,GPL-3,GPL-3 or any later version,LGPL-3 -valid_odoo_versions={{ odoo_version }} +valid_odoo_versions=12.0 [MESSAGES CONTROL] disable=all diff --git a/document_page/__manifest__.py b/document_page/__manifest__.py index 0cc80d53..608d4fe9 100644 --- a/document_page/__manifest__.py +++ b/document_page/__manifest__.py @@ -3,36 +3,31 @@ { - 'name': 'Documentation Page', - 'version': '12.0.1.2.0', - 'category': 'Knowledge Management', - 'author': 'OpenERP SA, Odoo Community Association (OCA)', - 'images': [ - 'images/category_list.png', - 'images/create_category.png', - 'images/page_list.png', - 'images/create_page.png', - 'images/customer_invoice.jpeg', - 'images/page_history.png', + "name": "Documentation Page", + "version": "12.0.1.2.0", + "category": "Knowledge Management", + "author": "OpenERP SA, Odoo Community Association (OCA)", + "images": [ + "images/category_list.png", + "images/create_category.png", + "images/page_list.png", + "images/create_page.png", + "images/customer_invoice.jpeg", + "images/page_history.png", ], - 'website': 'https://github.com/OCA/knowledge', - 'license': 'AGPL-3', - 'depends': [ - 'mail', - 'knowledge', - ], - 'data': [ - 'security/document_page_security.xml', - 'security/ir.model.access.csv', - 'wizard/document_page_create_menu.xml', - 'wizard/document_page_show_diff.xml', - 'views/document_page.xml', - 'views/document_page_category.xml', - 'views/document_page_history.xml', - 'views/document_page_assets.xml', - 'views/report_document_page.xml', - ], - 'demo': [ - 'demo/document_page.xml' + "website": "https://github.com/OCA/knowledge", + "license": "AGPL-3", + "depends": ["mail", "knowledge"], + "data": [ + "security/document_page_security.xml", + "security/ir.model.access.csv", + "wizard/document_page_create_menu.xml", + "wizard/document_page_show_diff.xml", + "views/document_page.xml", + "views/document_page_category.xml", + "views/document_page_history.xml", + "views/document_page_assets.xml", + "views/report_document_page.xml", ], + "demo": ["demo/document_page.xml"], } diff --git a/document_page/chmod b/document_page/chmod new file mode 100644 index 00000000..e69de29b diff --git a/document_page/demo/document_page.xml b/document_page/demo/document_page.xml index a45a1157..f3c959b3 100644 --- a/document_page/demo/document_page.xml +++ b/document_page/demo/document_page.xml @@ -1,9 +1,11 @@ - + - + @@ -11,7 +13,7 @@ 1.0 Init category - + Summary of the feature Long explanation @@ -25,7 +27,7 @@ Additional ressources OpenERP 6.1. Functional Demo - + 1.0 Init @@ -56,7 +58,7 @@ company, with your clients and implement it now for your business.
Personalise Dashboards - + 1.0 Init @@ -99,7 +101,7 @@ you change your mind there is a reset button to return to the default view.
Touchscreen Point of Sale - + 1.0 Init diff --git a/document_page/images/category_list.png b/document_page/images/category_list.png old mode 100644 new mode 100755 diff --git a/document_page/images/create_category.png b/document_page/images/create_category.png old mode 100644 new mode 100755 diff --git a/document_page/images/create_page.png b/document_page/images/create_page.png old mode 100644 new mode 100755 diff --git a/document_page/images/page_history.png b/document_page/images/page_history.png old mode 100644 new mode 100755 diff --git a/document_page/images/page_list.png b/document_page/images/page_list.png old mode 100644 new mode 100755 diff --git a/document_page/models/document_page.py b/document_page/models/document_page.py index 79599f3a..a9b4165f 100644 --- a/document_page/models/document_page.py +++ b/document_page/models/document_page.py @@ -1,7 +1,7 @@ # Copyright (C) 2004-2010 Tiny SPRL (). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import api, fields, models, _ +from odoo import _, api, fields, models from odoo.exceptions import ValidationError @@ -9,53 +9,46 @@ class DocumentPage(models.Model): """This class is use to manage Document.""" _name = "document.page" - _inherit = ['mail.thread', 'mail.activity.mixin'] + _inherit = ["mail.thread", "mail.activity.mixin"] _description = "Document Page" _parent_name = "parent_id" _parent_store = True - _rec_name = 'complete_name' - _order = 'type, sequence, complete_name' - + _rec_name = "complete_name" + _order = "type, sequence, complete_name" - name = fields.Char('Title', required=True) + name = fields.Char("Title", required=True) type = fields.Selection( - [('content', 'Content'), ('category', 'Category')], - 'Type', + [("content", "Content"), ("category", "Category")], + "Type", help="Page type", - default="content" + default="content", ) active = fields.Boolean(default=True) parent_id = fields.Many2one( - 'document.page', - 'Category', - domain=[('type', '=', 'category')] - ) - child_ids = fields.One2many( - 'document.page', - 'parent_id', - 'Children' + "document.page", "Category", domain=[("type", "=", "category")] ) + child_ids = fields.One2many("document.page", "parent_id", "Children") content = fields.Text( "Content", - compute='_compute_content', - inverse='_inverse_content', - search='_search_content', + compute="_compute_content", + inverse="_inverse_content", + search="_search_content", required=True, copy=True, ) # no-op computed field draft_name = fields.Char( - string='Name', - help='Name for the changes made', + string="Name", + help="Name for the changes made", compute=lambda x: x, inverse=lambda x: x, ) # no-op computed field draft_summary = fields.Char( - string='Summary', - help='Describe the changes made', + string="Summary", + help="Describe the changes made", compute=lambda x: x, inverse=lambda x: x, ) @@ -63,91 +56,88 @@ class DocumentPage(models.Model): template = fields.Html( "Template", help="Template that will be used as a content template " - "for all new page of this category.", + "for all new page of this category.", ) history_head = fields.Many2one( - 'document.page.history', - 'HEAD', - compute='_compute_history_head', + "document.page.history", + "HEAD", + compute="_compute_history_head", store=True, auto_join=True, ) history_ids = fields.One2many( - 'document.page.history', - 'page_id', - 'History', - order='create_date DESC', - readonly=True, - ) - menu_id = fields.Many2one( - 'ir.ui.menu', - "Menu", + "document.page.history", + "page_id", + "History", + order="create_date DESC", readonly=True, ) + menu_id = fields.Many2one("ir.ui.menu", "Menu", readonly=True,) content_date = fields.Datetime( - 'Last Contribution Date', - related='history_head.create_date', + "Last Contribution Date", + related="history_head.create_date", store=True, index=True, readonly=True, ) content_uid = fields.Many2one( - 'res.users', - 'Last Contributor', - related='history_head.create_uid', + "res.users", + "Last Contributor", + related="history_head.create_uid", store=True, index=True, readonly=True, ) company_id = fields.Many2one( - 'res.company', - 'Company', - help='If set, page is accessible only from this company', + "res.company", + "Company", + help="If set, page is accessible only from this company", index=True, - ondelete='cascade', + ondelete="cascade", ) backend_url = fields.Char( - string='Backend URL', - help='Use it to link resources univocally', - compute='_compute_backend_url', + string="Backend URL", + help="Use it to link resources univocally", + compute="_compute_backend_url", ) - + sequence = fields.Integer( - string='Sequence', - default=10, - help="Used to organise the category.") + string="Sequence", default=10, help="Used to organise the category." + ) parent_path = fields.Char(index=True) complete_name = fields.Char( - 'Complete Name', compute='_compute_complete_name', - store=True) - - image = fields.Binary( - "Image", attachment=True, + "Complete Name", compute="_compute_complete_name", store=True ) - - color = fields.Integer(string='Color Index') + image = fields.Binary("Image", attachment=True,) - @api.multi + color = fields.Integer(string="Color Index") + + @api.multi def write(self, vals): child_ids = self - if vals.get('color', False) and len(vals) ==1: - child_ids = self.search([('type', '=', 'category'), ('parent_id', 'child_of', self.ids)]) + if vals.get("color", False) and len(vals) == 1: + child_ids = self.search( + [("type", "=", "category"), + ("parent_id", "child_of", self.ids)] + ) res = super(DocumentPage, child_ids).write(vals) return res - @api.depends('name', 'parent_id.complete_name') + @api.depends("name", "parent_id.complete_name") def _compute_complete_name(self): for category in self: if category.parent_id: - category.complete_name = '%s / %s' % (category.parent_id.complete_name, category.name) + category.complete_name = "{} / {}".format( + category.parent_id.complete_name, category.name, + ) else: category.complete_name = category.name - @api.depends('menu_id', 'parent_id.menu_id') + @api.depends("menu_id", "parent_id.menu_id") def _compute_backend_url(self): - tmpl = '/web#id={}&model=document.page&view_type=form' + tmpl = "/web#id={}&model=document.page&view_type=form" for rec in self: url = tmpl.format(rec.id) # retrieve action @@ -157,13 +147,13 @@ class DocumentPage(models.Model): action = parent.menu_id.action parent = parent.parent_id if action: - url += '&action={}'.format(action.id) + url += "&action={}".format(action.id) rec.backend_url = url - @api.constrains('parent_id') + @api.constrains("parent_id") def _check_parent_id(self): if not self._check_recursion(): - raise ValidationError(_('You cannot create recursive categories.')) + raise ValidationError(_("You cannot create recursive categories.")) @api.multi def _get_page_index(self, link=True): @@ -172,7 +162,7 @@ class DocumentPage(models.Model): index = [] for subpage in self.child_ids: index += ["
  • " + subpage._get_page_index() + "
  • "] - r = '' + r = "" if link: r = '{}'.format(self.backend_url, self.name) if index: @@ -180,35 +170,37 @@ class DocumentPage(models.Model): return r @api.multi - @api.depends('history_head') + @api.depends("history_head") def _compute_content(self): for rec in self: - if rec.type == 'category': + if rec.type == "category": rec.content = rec._get_page_index(link=False) else: if rec.history_head: rec.content = rec.history_head.content else: # html widget's default, so it doesn't trigger ghost save - rec.content = '


    ' + rec.content = "


    " @api.multi def _inverse_content(self): for rec in self: - if rec.type == 'content' and \ - rec.content != rec.history_head.content: - rec._create_history({ - 'name': rec.draft_name, - 'summary': rec.draft_summary, - 'content': rec.content, - }) + if rec.type == "content" and \ + rec.content != rec.history_head.content: + rec._create_history( + { + "name": rec.draft_name, + "summary": rec.draft_summary, + "content": rec.content, + } + ) @api.multi def _search_content(self, operator, value): - return [('history_head.content', operator, value)] + return [("history_head.content", operator, value)] @api.multi - @api.depends('history_ids') + @api.depends("history_ids") def _compute_history_head(self): for rec in self: if rec.history_ids: @@ -217,20 +209,20 @@ class DocumentPage(models.Model): @api.multi def _create_history(self, vals): self.ensure_one() - history = self.env['document.page.history'] - vals['page_id'] = self.id + history = self.env["document.page.history"] + vals["page_id"] = self.id return history.create(vals) @api.onchange("parent_id") def _onchange_parent_id(self): """We Set it the right content to the new parent.""" - if not self.content or self.content == '


    ': + if not self.content or self.content == "


    ": if self.parent_id and self.parent_id.type == "category": - self.content = self.parent_id.template + self.content = self.parent_id.template @api.multi def unlink(self): - menus = self.mapped('menu_id') + menus = self.mapped("menu_id") res = super().unlink() menus.unlink() return res diff --git a/document_page/models/document_page_history.py b/document_page/models/document_page_history.py index 7467cf05..bb27a204 100644 --- a/document_page/models/document_page_history.py +++ b/document_page/models/document_page_history.py @@ -2,6 +2,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). import difflib + from odoo import api, fields, models from odoo.tools.translate import _ @@ -11,19 +12,19 @@ class DocumentPageHistory(models.Model): _name = "document.page.history" _description = "Document Page History" - _order = 'id DESC' + _order = "id DESC" - page_id = fields.Many2one('document.page', 'Page', ondelete='cascade') + page_id = fields.Many2one("document.page", "Page", ondelete="cascade") name = fields.Char(index=True) summary = fields.Char(index=True) content = fields.Text() - diff = fields.Text(compute='_compute_diff') + diff = fields.Text(compute="_compute_diff") company_id = fields.Many2one( - 'res.company', - 'Company', - help='If set, page is accessible only from this company', - related='page_id.company_id', + "res.company", + "Company", + help="If set, page is accessible only from this company", + related="page_id.company_id", store=True, index=True, readonly=True, @@ -32,13 +33,16 @@ class DocumentPageHistory(models.Model): @api.multi def _compute_diff(self): """Shows a diff between this version and the previous version""" - history = self.env['document.page.history'] + history = self.env["document.page.history"] for rec in self: - prev = history.search([ - ('page_id', '=', rec.page_id.id), - ('create_date', '<', rec.create_date)], + prev = history.search( + [ + ("page_id", "=", rec.page_id.id), + ("create_date", "<", rec.create_date), + ], limit=1, - order='create_date DESC') + order="create_date DESC", + ) if prev: rec.diff = self._get_diff(prev.id, rec.id) else: @@ -47,23 +51,24 @@ class DocumentPageHistory(models.Model): @api.model def _get_diff(self, v1, v2): """Return the difference between two version of document version.""" - text1 = v1 and self.browse(v1).content or '' - text2 = v2 and self.browse(v2).content or '' + text1 = v1 and self.browse(v1).content or "" + text2 = v2 and self.browse(v2).content or "" # Include line breaks to make it more readable # TODO: consider using a beautify library directly on the content - text1 = text1.replace('

    ', '

    \r\n

    ') - text2 = text2.replace('

    ', '

    \r\n

    ') + text1 = text1.replace("

    ", "

    \r\n

    ") + text2 = text2.replace("

    ", "

    \r\n

    ") line1 = text1.splitlines(True) line2 = text2.splitlines(True) if line1 == line2: - return _('There are no changes in revisions.') + return _("There are no changes in revisions.") else: diff = difflib.HtmlDiff() return diff.make_table( - line1, line2, + line1, + line2, "Revision-{}".format(v1), "Revision-{}".format(v2), - context=True + context=True, ) @api.multi diff --git a/document_page/readme/CONTRIBUTORS.rst b/document_page/readme/CONTRIBUTORS.rst index 9b215ad0..53394afd 100644 --- a/document_page/readme/CONTRIBUTORS.rst +++ b/document_page/readme/CONTRIBUTORS.rst @@ -10,5 +10,5 @@ * Víctor Martínez * Mind And Go : - - * Florent THOMAS \ No newline at end of file + + * Florent THOMAS diff --git a/document_page/security/document_page_security.xml b/document_page/security/document_page_security.xml index e05a2811..331c92b4 100644 --- a/document_page/security/document_page_security.xml +++ b/document_page/security/document_page_security.xml @@ -1,31 +1,38 @@ - + Editor - - + + Manager - - - + + + document_page multi-company - - - ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])] + + + ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])] document_page_history multi-company - - - ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])] + + + ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])] diff --git a/document_page/static/description/icon.png b/document_page/static/description/icon.png old mode 100644 new mode 100755 diff --git a/document_page/static/description/index.html b/document_page/static/description/index.html old mode 100644 new mode 100755 diff --git a/document_page/static/src/css/document_page.css b/document_page/static/src/css/document_page.css index 00a6336c..7216ecd7 100644 --- a/document_page/static/src/css/document_page.css +++ b/document_page/static/src/css/document_page.css @@ -1,29 +1,28 @@ table.diff { - font-family: Courier; - border: medium; + font-family: Courier; + border: medium; } table.diff .diff_header { - background-color: #e0e0e0 + background-color: #e0e0e0; } table.diff td.diff_header { - text-align: right + text-align: right; } table.diff .diff_next { - background-color:#c0c0c0 + background-color: #c0c0c0; } table.diff .diff_add { - background-color:#aaffaa + background-color: #aaffaa; } table.diff .diff_chg { - background-color:#ffff77 + background-color: #ffff77; } table.diff .diff_sub { - background-color:#ffaaaa + background-color: #ffaaaa; } - diff --git a/document_page/static/src/js/document_page_kanban.js b/document_page/static/src/js/document_page_kanban.js index dbef7002..18af8b41 100644 --- a/document_page/static/src/js/document_page_kanban.js +++ b/document_page/static/src/js/document_page_kanban.js @@ -1,28 +1,28 @@ -odoo.define('document_page.update_kanban', function (require) { - 'use strict'; - - var core = require('web.core'); - var Dialog = require('web.Dialog'); - var KanbanRecord = require('web.KanbanRecord'); - - var QWeb = core.qweb; - var _t = core._t; +odoo.define("document_page.update_kanban", function(require) { + "use strict"; + + var KanbanRecord = require("web.KanbanRecord"); KanbanRecord.include({ - //-------------------------------------------------------------------------- + // -------------------------------------------------------------------------- // Private - //-------------------------------------------------------------------------- + // -------------------------------------------------------------------------- /** * @override * @private */ - _openRecord: function () { - if (this.modelName === 'document.page' && this.$(".o_document_page_kanban_boxes a").length) { - this.$('.o_document_page_kanban_boxes a').first().click(); + _openRecord: function() { + if ( + this.modelName === "document.page" && + this.$(".o_document_page_kanban_boxes a").length + ) { + this.$(".o_document_page_kanban_boxes a") + .first() + .click(); } else { this._super.apply(this, arguments); } - }, + } }); }); diff --git a/document_page/tests/test_document_page.py b/document_page/tests/test_document_page.py index 3a67f08e..72366362 100644 --- a/document_page/tests/test_document_page.py +++ b/document_page/tests/test_document_page.py @@ -3,55 +3,53 @@ from odoo.tests import common class TestDocumentPage(common.TransactionCase): - def setUp(self): super(TestDocumentPage, self).setUp() - self.page_obj = self.env['document.page'] - self.history_obj = self.env['document.page.history'] - self.category1 = self.env.ref('document_page.demo_category1') - self.page1 = self.env.ref('document_page.demo_page1') + self.page_obj = self.env["document.page"] + self.history_obj = self.env["document.page.history"] + self.category1 = self.env.ref("document_page.demo_category1") + self.page1 = self.env.ref("document_page.demo_page1") def test_page_creation(self): - page = self.page_obj.create({ - 'name': 'Test Page 1', - 'parent_id': self.category1.id, - 'content': 'Test content' - }) - self.assertEqual(page.content, 'Test content') + page = self.page_obj.create( + { + "name": "Test Page 1", + "parent_id": self.category1.id, + "content": "Test content", + } + ) + self.assertEqual(page.content, "Test content") self.assertEqual(len(page.history_ids), 1) - page.content = 'New content for Demo Page' + page.content = "New content for Demo Page" self.assertEqual(len(page.history_ids), 2) def test_category_template(self): - page = self.page_obj.create({ - 'name': 'Test Page 2', - 'parent_id': self.category1.id, - }) + page = self.page_obj.create( + {"name": "Test Page 2", "parent_id": self.category1.id} + ) page._onchange_parent_id() self.assertEqual(page.content, self.category1.template) def test_page_history_diff(self): page = self.page_obj.create({ - 'name': 'Test Page 3', - 'content': 'Test content' - }) - page.content = 'New content' + "name": "Test Page 3", + "content": "Test content"}) + page.content = "New content" self.assertIsNotNone(page.history_ids[0].diff) def test_page_link(self): page = self.page_obj.create({ - 'name': 'Test Page 3', - 'content': 'Test content' - }) + "name": "Test Page 3", + "content": "Test content"}) self.assertEqual( page.backend_url, - '/web#id={}&model=document.page&view_type=form'.format(page.id) + "/web#id={}&model=document.page&view_type=form".format(page.id), ) - menu = self.env.ref('knowledge.menu_document') + menu = self.env.ref("knowledge.menu_document") page.menu_id = menu self.assertEqual( page.backend_url, - '/web#id={}&model=document.page&view_type=form&action={}'.format( + "/web#id={}&model=document.page&view_type=form&action={}".format( page.id, menu.action.id - ) + ), ) diff --git a/document_page/tests/test_document_page_create_menu.py b/document_page/tests/test_document_page_create_menu.py index 96c21e24..82dbf378 100644 --- a/document_page/tests/test_document_page_create_menu.py +++ b/document_page/tests/test_document_page_create_menu.py @@ -7,23 +7,23 @@ class TestDocumentPageCreateMenu(common.TransactionCase): def test_page_menu_creation(self): """Test page menu creation.""" - menu_parent = self.env.ref('knowledge.menu_document') + menu_parent = self.env.ref("knowledge.menu_document") - menu_created = self.env['document.page.create.menu'].create( - {'menu_name': 'Wiki Test menu', 'menu_parent_id': menu_parent.id} + menu_created = self.env["document.page.create.menu"].create( + {"menu_name": "Wiki Test menu", "menu_parent_id": menu_parent.id} ) - menu = self.env['document.page.create.menu'].search( - [('id', '=', menu_created.id)] + menu = self.env["document.page.create.menu"].search( + [("id", "=", menu_created.id)] ) menu.with_context( - active_id=[self.ref('document_page.demo_page1')] + active_id=[self.ref("document_page.demo_page1")] ).document_page_menu_create() fields_list = ["menu_name", "menu_name"] res = menu.with_context( - active_id=[self.ref('document_page.demo_page1')] + active_id=[self.ref("document_page.demo_page1")] ).default_get(fields_list) - self.assertEqual(res['menu_name'], 'OpenERP 6.1. Functional Demo') + self.assertEqual(res["menu_name"], "OpenERP 6.1. Functional Demo") diff --git a/document_page/tests/test_document_page_history.py b/document_page/tests/test_document_page_history.py index a80f4cc4..856be77f 100644 --- a/document_page/tests/test_document_page_history.py +++ b/document_page/tests/test_document_page_history.py @@ -1,4 +1,3 @@ - from odoo.tests import common @@ -7,14 +6,14 @@ class TestDocumentPageHistory(common.TransactionCase): def test_page_history_demo_page1(self): """Test page history demo page1.""" - page = self.env.ref('document_page.demo_page1') - page.content = 'Test content updated' - history_document = self.env['document.page.history'] - history_pages = history_document.search([('page_id', '=', page.id)]) + page = self.env.ref("document_page.demo_page1") + page.content = "Test content updated" + history_document = self.env["document.page.history"] + history_pages = history_document.search([("page_id", "=", page.id)]) active_ids = [i.id for i in history_pages] result = history_document._get_diff(active_ids[0], active_ids[0]) - self.assertEqual(result, 'There are no changes in revisions.') + self.assertEqual(result, "There are no changes in revisions.") result = history_document._get_diff(active_ids[0], active_ids[1]) - self.assertNotEqual(result, 'There are no changes in revisions.') + self.assertNotEqual(result, "There are no changes in revisions.") diff --git a/document_page/tests/test_document_page_show_diff.py b/document_page/tests/test_document_page_show_diff.py index 34bc16f7..811c35e7 100644 --- a/document_page/tests/test_document_page_show_diff.py +++ b/document_page/tests/test_document_page_show_diff.py @@ -8,12 +8,12 @@ class TestDocumentPageShowDiff(common.TransactionCase): def test_show_demo_page1_diff(self): """Show test page history difference.""" - page = self.env.ref('document_page.demo_page1') + page = self.env.ref("document_page.demo_page1") - show_diff_object = self.env['wizard.document.page.history.show_diff'] + show_diff_object = self.env["wizard.document.page.history.show_diff"] - history_document = self.env['document.page.history'] - history_pages = history_document.search([('page_id', '=', page.id)]) + history_document = self.env["document.page.history"] + history_pages = history_document.search([("page_id", "=", page.id)]) self.assertTrue( show_diff_object.with_context( @@ -21,10 +21,10 @@ class TestDocumentPageShowDiff(common.TransactionCase): )._get_diff() ) - page.write({'content': 'Text content updated'}) - page.write({'content': 'Text updated'}) + page.write({"content": "Text content updated"}) + page.write({"content": "Text updated"}) - history_pages = history_document.search([('page_id', '=', page.id)]) + history_pages = history_document.search([("page_id", "=", page.id)]) with self.assertRaises(UserError): show_diff_object.with_context( diff --git a/document_page/views/document_page.xml b/document_page/views/document_page.xml index d30d419e..39c5a9bd 100644 --- a/document_page/views/document_page.xml +++ b/document_page/views/document_page.xml @@ -1,4 +1,4 @@ - + @@ -9,9 +9,9 @@ 100 - - - + + + @@ -22,12 +22,12 @@ document.page - - - - - - + + + + + + @@ -40,52 +40,93 @@

    -
    - +

    - +

    - +
    - - - - - + + + + + - - + + - - - - - + + + + +
    - - - + + +
    @@ -96,11 +137,17 @@ document.page
    - +

    - +

    - +
    @@ -111,15 +158,30 @@ document.page - - - - + + + + - - - + + + @@ -134,8 +196,8 @@ {'default_type': 'content'} form tree,form - - + +

    Click to create a new web page. @@ -144,40 +206,45 @@ - + tree - - + + - + form - - + + - + - + + id="action_related_page_create_menu" + name="Create Menu" + res_model="document.page.create.menu" + target="new" + view_type="form" + view_mode="form" + src_model="document.page" + /> diff --git a/document_page/views/document_page_assets.xml b/document_page/views/document_page_assets.xml index f4625c8e..a192ea4d 100644 --- a/document_page/views/document_page_assets.xml +++ b/document_page/views/document_page_assets.xml @@ -1,10 +1,20 @@ - + -