diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000000000000000000000000000000000..bfd7ac53df9f103f6dc8853738c63fd364445fde --- /dev/null +++ b/.editorconfig @@ -0,0 +1,20 @@ +# Configuration for known file extensions +[*.{css,js,json,less,md,py,rst,sass,scss,xml,yaml,yml}] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true + +[*.{json,yml,yaml,rst,md}] +indent_size = 2 + +# Do not configure editor for libs and autogenerated content +[{*/static/{lib,src/lib}/**,*/static/description/index.html,*/readme/../README.rst}] +charset = unset +end_of_line = unset +indent_size = unset +indent_style = unset +insert_final_newline = false +trim_trailing_whitespace = false diff --git a/.eslintrc.yml b/.eslintrc.yml new file mode 100644 index 0000000000000000000000000000000000000000..d4cc423ccda9db9691205c9da83307af97b2670f --- /dev/null +++ b/.eslintrc.yml @@ -0,0 +1,187 @@ +env: + browser: true + es6: true + +# See https://github.com/OCA/odoo-community.org/issues/37#issuecomment-470686449 +parserOptions: + ecmaVersion: 2017 + +overrides: + - files: + - "**/*.esm.js" + parserOptions: + sourceType: module + +# Globals available in Odoo that shouldn't produce errorings +globals: + _: readonly + $: readonly + fuzzy: readonly + jQuery: readonly + moment: readonly + odoo: readonly + openerp: readonly + owl: 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 0000000000000000000000000000000000000000..e397e8ed4e3e7f7fe7785dd391bb80aa6d85575e --- /dev/null +++ b/.flake8 @@ -0,0 +1,12 @@ +[flake8] +max-line-length = 88 +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 +per-file-ignores= + __init__.py:F401 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..818770fb1bdc0a144e924c9a5940f0b035df8a0d --- /dev/null +++ b/.gitignore @@ -0,0 +1,75 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +/.venv +/.pytest_cache + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +bin/ +build/ +develop-eggs/ +dist/ +eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg +*.eggs + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.cache +nosetests.xml +coverage.xml + +# Translations +*.mo + +# Pycharm +.idea + +# Eclipse +.settings + +# Visual Studio cache/options directory +.vs/ +.vscode + +# OSX Files +.DS_Store + +# Django stuff: +*.log + +# Mr Developer +.mr.developer.cfg +.project +.pydevproject + +# Rope +.ropeproject + +# Sphinx documentation +docs/_build/ + +# Backup files +*~ +*.swp + +# OCA rules +!static/lib/ diff --git a/.isort.cfg b/.isort.cfg new file mode 100644 index 0000000000000000000000000000000000000000..0ec187efd1bf802844749f508cda0c8f138970f9 --- /dev/null +++ b/.isort.cfg @@ -0,0 +1,13 @@ +[settings] +; see https://github.com/psf/black +multi_line_output=3 +include_trailing_comma=True +force_grid_wrap=0 +combine_as_imports=True +use_parentheses=True +line_length=88 +known_odoo=odoo +known_odoo_addons=odoo.addons +sections=FUTURE,STDLIB,THIRDPARTY,ODOO,ODOO_ADDONS,FIRSTPARTY,LOCALFOLDER +default_section=THIRDPARTY +ensure_newline_before_comments = True diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..8a5999af4419f630dda23d9366b51967b8322ed3 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,127 @@ +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.*) +default_language_version: + 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://le-filament.com"] + - 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://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 diff --git a/.prettierrc.yml b/.prettierrc.yml new file mode 100644 index 0000000000000000000000000000000000000000..5b6d4b361ace92f3877993bf2848fac190d8fab6 --- /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 0000000000000000000000000000000000000000..dc6270e15be0c08da00e768a570f27c785d8630e --- /dev/null +++ b/.pylintrc @@ -0,0 +1,87 @@ +[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=Le Filament +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=14.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, + 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 new file mode 100644 index 0000000000000000000000000000000000000000..43ea23947166ff8080219007cfae43ec54a28f8e --- /dev/null +++ b/.pylintrc-mandatory @@ -0,0 +1,64 @@ +[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=Le Filament +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=14.0 + +[MESSAGES CONTROL] +disable=all + +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 + +[REPORTS] +msg-template={path}:{line}: [{msg_id}({symbol}), {obj}] {msg} +output-format=colorized +reports=no diff --git a/README.rst b/README.rst index 0d5472934cc7370d12d7cd1f90cc20ba7fb72fd9..0853f05c55fac3232970400db32925fad820a792 100644 --- a/README.rst +++ b/README.rst @@ -26,7 +26,7 @@ Il implémente également la fonction de connexion à Alfresco pour le module CM Usage ===== -Pour configurer ce module, les données suivantes sont à renseigner dans le menu **Configuration > APIs CG Scop > Alfresco > Configuration connexion** : +Pour configurer ce module, les données suivantes sont à renseigner dans le menu **Configuration > APIs CG Scop > Alfresco > Configuration connexion** : * *alfresco_login* : login de connexion à l'API * *alfresco_password* : password de connexion à l'API diff --git a/__init__.py b/__init__.py index b9f967ea92a89276401151d71f466ffe3e0a4f33..311c9edac9731273aa9175579ffd9777f58f7a7b 100644 --- a/__init__.py +++ b/__init__.py @@ -1,5 +1,4 @@ # © 2019 Le Filament (<http://www.le-filament.com>) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from . import controllers -from . import models +from . import controllers, models diff --git a/__manifest__.py b/__manifest__.py index 254cb43d457a601586fde207b8a57d64037c76ea..22ce2c177d3f4dc765ae905244bbd4f22788ada0 100644 --- a/__manifest__.py +++ b/__manifest__.py @@ -1,23 +1,26 @@ { "name": "CG SCOP - Connecteur Alfresco", "summary": "Connecteur Alfresco", - "version": "12.0.1.0.1", + "version": "14.0.1.0.0", "development_status": "Beta", "author": "Le Filament", "license": "AGPL-3", "application": False, "depends": [ - 'base', - 'web', - 'cmis', + "base", + "web", + "cmis", ], "data": [ "views/assets.xml", "views/cmis_backend.xml", ], - 'qweb': [ - 'static/src/xml/*.xml', + "qweb": [ + "static/src/xml/*.xml", ], - 'installable': True, - 'auto_install': False, + "installable": True, + "auto_install": False, + "external_dependencies": { + "python": ["cmislib"], + }, } diff --git a/controllers/main.py b/controllers/main.py index aafe908bc6ca9243c9ebf6edaec651557952e749..d9657c875fa6a6b375e2363fe1022102c5f78fcd 100644 --- a/controllers/main.py +++ b/controllers/main.py @@ -5,20 +5,20 @@ from odoo import http class AlfrescoController(http.Controller): - - @http.route( - ['/web/alfresco/session'], - type="json", auth="user", method=['POST']) + @http.route(["/web/alfresco/session"], type="json", auth="user", method=["POST"]) def get_alf_ticket(self, username): - data = http.request.env['cgscop.alfresco'].alfresco_get_ticket(username) + data = http.request.env["cgscop.alfresco"].alfresco_get_ticket(username) return data # ------------------------------------------------------ # Override parent # ------------------------------------------------------ @http.route( - '/web/cmis/field/create_value', - type='json', methods=['POST'], auth="user") + "/web/cmis/field/create_value", + type="json", + methods=["POST"], + auth="user", + ) def create_field_value(self, model_name, res_id, field_name): """ Override parent to return dict with res_id key to avoid error on OCB diff --git a/models/api_alfresco.py b/models/api_alfresco.py index eb83decaf3386371eda5b73cea1fb6ca2da4b109..30cca33a113642dce60e5a76ffd336569be11b0f 100644 --- a/models/api_alfresco.py +++ b/models/api_alfresco.py @@ -1,28 +1,35 @@ # © 2019 Le Filament (<http://www.le-filament.com>) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -import requests import logging import xml.etree.ElementTree as et -from odoo import models, exceptions, fields -from cmislib.exceptions import CmisException, ContentAlreadyExistsException, \ - ObjectNotFoundException, UpdateConflictException, InvalidArgumentException +import requests +from cmislib.exceptions import ( + CmisException, + ContentAlreadyExistsException, + InvalidArgumentException, + ObjectNotFoundException, + UpdateConflictException, +) + +from odoo import _, exceptions, models _logger = logging.getLogger(__name__) class CgscopAlfresco(models.AbstractModel): - """ Appelle l'API alfresco et implémente les fonctions suivantes : + """Appelle l'API alfresco et implémente les fonctions suivantes : alfresco_list_docs : liste les documents """ - _name = 'cgscop.alfresco' - _description = 'Connecteur Alfresco' + + _name = "cgscop.alfresco" + _description = "Connecteur Alfresco" def alfresco_get_by_url(self, url, call_type, json=None): - """ Création de la requête à Alfresco - + """Création de la requête à Alfresco + :param url: action API Alfresco :param call_type: post/get :param json: data to post @@ -30,35 +37,35 @@ class CgscopAlfresco(models.AbstractModel): @return response au format JSON """ _logger.info("Calling %s" % url) - param = self.env['cmis.backend'].sudo().search([ - ['active', '=', True]]) + param = self.env["cmis.backend"].sudo().search([["active", "=", True]]) if not param: - raise exceptions.Warning( - "La connexion avec Alfresco n'est pas configurée !") - return False + raise exceptions.UserError( + _("La connexion avec Alfresco n'est pas configurée !") + ) alfresco_url = param.url alfresco_ssl = param.ssl - basicAuthCredentials = ( - param.username, - param.password) + basicAuthCredentials = (param.username, param.password) try: - if call_type == 'get': + if call_type == "get": response = requests.get( alfresco_url + url, auth=basicAuthCredentials, - verify=alfresco_ssl) - elif call_type == 'post': + verify=alfresco_ssl, + ) + elif call_type == "post": response = requests.post( alfresco_url + url, auth=basicAuthCredentials, json=json, - verify=alfresco_ssl) - elif call_type == 'delete': + verify=alfresco_ssl, + ) + elif call_type == "delete": response = requests.delete( alfresco_url + url, auth=basicAuthCredentials, json=json, - verify=alfresco_ssl) + verify=alfresco_ssl, + ) except Exception as err: _logger.warning( "Erreur de connexion. URL: %s", @@ -69,157 +76,140 @@ class CgscopAlfresco(models.AbstractModel): # Gestion erreur API if response.status_code not in [200, 201]: try: - message = response.json().get('message') - except: + message = response.json().get("message") + except Exception: message = response.text - raise exceptions.Warning( - "L'appel url '%s' a échoué\n" - "- Code erreur : %d\n" - "- Message : %s" % ( - response.url, - response.status_code, - message)) + raise exceptions.ValidationError( + _( + "L'appel url '%s' a échoué\n" + "- Code erreur : %d\n" + "- Message : %s" % (response.url, response.status_code, message) + ) + ) # Si dossier déjà créé - elif (response.text.find("NUMADHERENT d") > 0 or - response.text.find("SIRET d") > 0 or - response.text.find("RAISONSOCIALE d") > 0): - return response.json().get('dossiersExistants')[0] + elif ( + response.text.find("NUMADHERENT d") > 0 + or response.text.find("SIRET d") > 0 + or response.text.find("RAISONSOCIALE d") > 0 + ): + return response.json().get("dossiersExistants")[0] return response # Get Methods def alfresco_list_docs(self, node_id): - """ Liste les documents pour un organisme (raison sociale) - :param name: raison sociale de la structure + """Liste les documents pour un organisme (raison sociale) + :param name: raison sociale de la structure """ - url = '/alfresco/s/erp/listedocuments?nodeId=' + node_id - return self.alfresco_get_by_url(url=url, call_type='get').json() + url = "/alfresco/s/erp/listedocuments?nodeId=" + node_id + return self.alfresco_get_by_url(url=url, call_type="get").json() def alfresco_list_type(self): - """ Liste le valeurs du formulaire de dépôt d'un nouveau document + """Liste le valeurs du formulaire de dépôt d'un nouveau document @return: dict des valeurs possibles pour période, validité, type """ - url = '/alfresco/s/api/properties?nsp=crm&n=document' - list_type = self.alfresco_get_by_url(url=url, call_type='get').json() + url = "/alfresco/s/api/properties?nsp=crm&n=document" + list_type = self.alfresco_get_by_url(url=url, call_type="get").json() return { - 'periode': self.get_allowed_values( - list_type=list_type, - value='crm:periode'), - 'type': self.get_allowed_values( - list_type=list_type, - value='crm:type'), + "periode": self.get_allowed_values( + list_type=list_type, value="crm:periode" + ), + "type": self.get_allowed_values(list_type=list_type, value="crm:type"), } def alfresco_get_doc(self, nodeRef): - """ Retourne le contenu d'un document en base64 - :param nodeRef: id Alfresco + """Retourne le contenu d'un document en base64 + :param nodeRef: id Alfresco """ - url = '/alfresco/s/document/' + nodeRef - return self.alfresco_get_by_url(url=url, call_type='get').json() + url = "/alfresco/s/document/" + nodeRef + return self.alfresco_get_by_url(url=url, call_type="get").json() def alfresco_get_ticket(self, username): - """ Liste les documents pour un organisme (raison sociale) - :param username: username de l'utilisateur + """Liste les documents pour un organisme (raison sociale) + :param username: username de l'utilisateur """ - url = '/alfresco/s/authentifier-entantque?compte=' + username - result = self.alfresco_get_by_url(url=url, call_type='get') + url = "/alfresco/s/authentifier-entantque?compte=" + username + result = self.alfresco_get_by_url(url=url, call_type="get") tree = et.ElementTree(et.fromstring(result.content)) root = tree.getroot() return root[0].text # Post Methods def alfresco_create_organism(self, partner): - """ Création d'un dossier Organisme + """Création d'un dossier Organisme :param partner: objet Odoo créé @return: id Alfresco (nodeRef) du dossier """ - url = '/alfresco/s/erp/createdossierorganisme' + url = "/alfresco/s/erp/createdossierorganisme" json = { - 'raisonSociale': partner.name, + "raisonSociale": partner.name, "id": partner.id, "siret": partner.siret, "numAdherent": partner.member_number, - "ur": partner.ur_id + "ur": partner.ur_id, } return self.get_nodeRef( - self.alfresco_get_by_url(url=url, call_type='post', json=json).json()) + self.alfresco_get_by_url(url=url, call_type="post", json=json).json() + ) def alfresco_update_organism(self, partner): - """ Mise à jour d'un dossier Organisme + """Mise à jour d'un dossier Organisme :param partner: objet Odoo créé @return: id Alfresco (nodeRef) du dossier """ - url = '/alfresco/s/erp/updatedossierorganisme/' + partner.id_alfresco + url = "/alfresco/s/erp/updatedossierorganisme/" + partner.id_alfresco json = { - 'raisonSociale': partner.name, + "raisonSociale": partner.name, "id": partner.id, "siret": partner.siret, "numAdherent": partner.member_number, - "ur": partner.ur_id + "ur": partner.ur_id, } return self.get_nodeRef( - self.alfresco_get_by_url(url=url, call_type='post', json=json).json()) - - def alfresco_upload(self, partner, type, periode, validite, filename, mimetype, doc): - """ Upload d'un document sur Alfresco - - :param doc: document encodé en base64 - - @return: id Alfresco (nodeRef) du fichier - """ - url = '/alfresco/s/erp/depotdocument' - json = { - 'folderNodeId': partner.id_alfresco, - 'periode': periode, - 'type': type, - 'nomOrigine': filename, - 'mimeType': mimetype, - 'contentBase64': doc, - } - return self.get_nodeRef( - self.alfresco_get_by_url(url=url, call_type='post', json=json).json()) + self.alfresco_get_by_url(url=url, call_type="post", json=json).json() + ) # Delete Methods def alfresco_remove(self, nodeRef): - """ Supprime un document d'Alfresco - :param id_doc: id du document Alfresco + """Supprime un document d'Alfresco + :param id_doc: id du document Alfresco """ - url = '/alfresco/s/document/' + nodeRef - return self.alfresco_get_by_url(url=url, call_type='delete').json() + url = "/alfresco/s/document/" + nodeRef + return self.alfresco_get_by_url(url=url, call_type="delete").json() # Others def get_allowed_values(self, list_type, value): - """ Fonction qui itère dans l'objet retourné - """ - list_selected = list(filter( - lambda i: i['name'] == value, - list_type)) - return list_selected[0].get( - 'constraints')[0].get('parameters')[0].get('allowedValues') + """Fonction qui itère dans l'objet retourné""" + list_selected = list(filter(lambda i: i["name"] == value, list_type)) + return ( + list_selected[0] + .get("constraints")[0] + .get("parameters")[0] + .get("allowedValues") + ) def get_nodeRef(self, result): - """ Renvoie la référence Alfresco d'un JSON contenant au premier + """Renvoie la référence Alfresco d'un JSON contenant au premier niveau la clé "nodeRef" puis supprime le chemin du workspace """ - return result.get('nodeRef', '').replace( - 'workspace://SpacesStore/', '') + return result.get("nodeRef", "").replace("workspace://SpacesStore/", "") - def push_alfresco_file( - self, file, name, metadata=None, backend=None, folder=None): + def push_alfresco_file(self, file, name, metadata=None, backend=None, folder=None): """ - Ajoute un fichier sur la GED Alfresco - @return: fonction get_partner_files() de res.partner + Ajoute un fichier sur la GED Alfresco + @return: fonction get_partner_files() de res.partner """ if not backend: - backend = self.env['cmis.backend'].search([], limit=1) + backend = self.env["cmis.backend"].search([], limit=1) if not folder: raise exceptions.ValidationError( - "Le dossier parent n'existe pas ou n'est pas renseigné!") + _("Le dossier parent n'existe pas ou n'est pas renseigné !") + ) cmis_obj = backend.get_cmis_repository().getObject(folder) @@ -228,20 +218,30 @@ class CgscopAlfresco(models.AbstractModel): name=name, properties=metadata, contentFile=file, - contentType='application/pdf' + contentType="application/pdf", ) return file_upload except CmisException: raise exceptions.ValidationError( - """Erreur de mise à jour Alfresco : - Le document existe déjà dans Alfresco""") - except (ContentAlreadyExistsException, ObjectNotFoundException, - UpdateConflictException, InvalidArgumentException) as e: + _( + "Erreur de mise à jour Alfresco : Le document existe déjà dans Alfresco" + ) + ) + except ( + ContentAlreadyExistsException, + ObjectNotFoundException, + UpdateConflictException, + InvalidArgumentException, + ) as e: _logger.error(e) raise exceptions.ValidationError( - """Erreur de mise à jour Alfresco : + _( + """Erreur de mise à jour Alfresco : - Code : %s - Url : %s - - Détail : %s""" % (e.status, e.url, e.details)) + - Détail : %s""" + % (e.status, e.url, e.details) + ) + ) except Exception as e: raise exceptions.ValidationError(e) diff --git a/models/cmis_backend.py b/models/cmis_backend.py index 1e67b5d246711be0cafa9ea1d09266819c088ac3..8b76546e840476c40fb8f5d83eb8010c0c3afc73 100644 --- a/models/cmis_backend.py +++ b/models/cmis_backend.py @@ -1,12 +1,12 @@ # © 2019 Le Filament (<http://www.le-filament.com>) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from odoo import models, fields +from odoo import fields, models class CgscopAlfrescoConnection(models.Model): - _inherit = 'cmis.backend' + _inherit = "cmis.backend" - url = fields.Char('URL') - ssl = fields.Boolean('Connexion SSL', default=False) - active = fields.Boolean('Actif', default=False) + url = fields.Char("URL") + ssl = fields.Boolean("Connexion SSL", default=False) + active = fields.Boolean("Actif", default=False) diff --git a/security/ir.model.access.csv b/security/ir.model.access.csv deleted file mode 100644 index 58262d4440d02ecccad693faa23505f01ced8a9f..0000000000000000000000000000000000000000 --- a/security/ir.model.access.csv +++ /dev/null @@ -1 +0,0 @@ -id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink \ No newline at end of file diff --git a/static/description/icon.png b/static/description/icon.png index 82ef47760a441cf229b5009f0a18ccf3842fbfa5..499652a2c9c0307f875bafc145b6fbafa133da72 100644 Binary files a/static/description/icon.png and b/static/description/icon.png differ diff --git a/static/src/js/form_widgets.js b/static/src/js/form_widgets.js index 6c9332884377de185d403b6ae736e27615994866..24c8e136bb35124e5ff6a570c53ec2b340507684 100644 --- a/static/src/js/form_widgets.js +++ b/static/src/js/form_widgets.js @@ -1,88 +1,85 @@ -/*--------------------------------------------------------------- +/* --------------------------------------------------------------- Copyright 2020 Le Filament License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). ------------------------------------------------------------------*/ -odoo.define('cgscop_alfresco.form_widgets', function(require) { +odoo.define("cgscop_alfresco.form_widgets", function (require) { "use strict"; - var core = require('web.core'); - var form_widgets = require('cmis_web.form_widgets'); - var lf_form_widgets = require('lefilament_alfodoo.form_widgets'); - var session = require('web.session'); + var core = require("web.core"); + var form_widgets = require("cmis_web.form_widgets"); + var lf_form_widgets = require("lefilament_alfodoo.form_widgets"); + var session = require("web.session"); form_widgets.CmisObjectWrapper.include({ /* - * Surcharge les fonction parse_object (téléchargement) - * et get_content_url (preview) pour passer le ticket - * l'url appelée - */ + * Surcharge les fonction parse_object (téléchargement) + * et get_content_url (preview) pour passer le ticket + * l'url appelée + */ parse_object: function (cmis_object) { this._super.apply(this, arguments); if (this.cmis_session.alf_ticket) { - this.url = this.cmis_session.getContentStreamURL(this.objectId, 'attachment', {'alf_ticket': this.cmis_session.alf_ticket}); + this.url = this.cmis_session.getContentStreamURL( + this.objectId, + "attachment", + {alf_ticket: this.cmis_session.alf_ticket} + ); } }, get_content_url: function () { - var options = {} + var options = {}; if (this.cmis_session.alf_ticket) { - options = {'alf_ticket': this.cmis_session.alf_ticket}; + options = {alf_ticket: this.cmis_session.alf_ticket}; } - return this.cmis_session.getContentStreamURL(this.objectId, 'inline', options); + return this.cmis_session.getContentStreamURL( + this.objectId, + "inline", + options + ); }, }), + form_widgets.FieldCmisFolder.include({ + /** + * Surcharge la fonction d'initialisation de la session CMIS pour + * passer le token de l'utilisateur + */ + init_cmis_session: function () { + var self = this; + $.when(this.cmis_config_loaded).done(function () { + self.cmis_session = cmis.createSession(self.cmis_location); + self.cmis_session.setGlobalHandlers( + self.on_cmis_error, + self.on_cmis_error + ); - form_widgets.FieldCmisFolder.include({ - /** - * Surcharge la fonction d'initialisation de la session CMIS pour - * passer le token de l'utilisateur - */ - init_cmis_session: function () { - var self = this; - $.when(this.cmis_config_loaded).done(function () { - self.cmis_session = cmis.createSession(self.cmis_location); - self.cmis_session.setGlobalHandlers(self.on_cmis_error, self.on_cmis_error); - - // CGSCOP : appel vers la fonction custom - self._rpc({route:'/web/alfresco/session', params:{ - 'username': session.username - }}).done(function (result) { - self.cmis_session['alf_ticket'] = result; - self.cmis_session.setCredentials('ROLE_TICKET', result); + // CGSCOP : appel vers la fonction custom + self._rpc({ + route: "/web/alfresco/session", + params: { + username: session.username, + }, + }).then(function (result) { + self.cmis_session.alf_ticket = result; + self.cmis_session.setCredentials("ROLE_TICKET", result); + }); + self.cmis_session_initialized.resolve(); + self.cmis_session.setCharacterSet(document.characterSet); }); - self.cmis_session_initialized.resolve(); - self.cmis_session.setCharacterSet(document.characterSet); - }); - }, + }, - load_cmis_repositories: function () { - /** - * Surcharge la fonction de chargement des repositories après initialisation - * du dossier initial pour recharger correctement la page - */ - var dfd = $.Deferred(); - var self = this; - if (this.cmis_session.repositories) { - return dfd.resolve(); - } else { + load_cmis_repositories: function () { + /** + * Surcharge la fonction de chargement des repositories après initialisation + * du dossier initial pour recharger correctement la page + */ + var dfd = $.Deferred(); + var self = this; + if (this.cmis_session.repositories) { + return dfd.resolve(); + } if (self.cmis_session.alf_ticket) { self.cmis_session - .loadRepositories() - .ok(function (data) { - dfd.resolve(); - }) - .notOk(function (error) { - self.on_cmis_error(error); - dfd.reject(error); - }); - } else { - // CGSCOP : appel vers la fonction custom - self._rpc({route:'/web/alfresco/session', params:{ - 'username': session.username - }}).done(function (result) { - self.cmis_session['alf_ticket'] = result; - self.cmis_session.setCredentials('ROLE_TICKET', result); - self.cmis_session .loadRepositories() .ok(function (data) { dfd.resolve(); @@ -91,52 +88,76 @@ odoo.define('cgscop_alfresco.form_widgets', function(require) { self.on_cmis_error(error); dfd.reject(error); }); + } else { + // CGSCOP : appel vers la fonction custom + self._rpc({ + route: "/web/alfresco/session", + params: { + username: session.username, + }, + }).then(function (result) { + self.cmis_session.alf_ticket = result; + self.cmis_session.setCredentials("ROLE_TICKET", result); + self.cmis_session + .loadRepositories() + .ok(function (data) { + dfd.resolve(); + }) + .notOk(function (error) { + self.on_cmis_error(error); + dfd.reject(error); + }); }); } - } - return dfd.promise(); - }, - }); + return dfd.promise(); + }, + }); lf_form_widgets.CmisMetadataDialog.include({ /* - * Surcharge la fonction on_click_metadata - * pour la gestion des erreurs spécifique à la CG Scop - */ + * Surcharge la fonction on_click_metadata + * pour la gestion des erreurs spécifique à la CG Scop + */ on_click_metadata: function () { var self = this; - this.metadata = {'cmis:name': Date.now().toString() + '_' + this.file.name} + this.metadata = {"cmis:name": Date.now().toString() + "_" + this.file.name}; _.each(this.parent_metadata, function (meta) { if (meta.value) { self.metadata[meta.name] = meta.value; } else if (meta.field_value) { self.metadata[meta.name] = self.record[meta.field_value]; } else { - self.metadata[meta.name] = self.$el.find("#" + meta.name.replace(":", "-"))[0].value; + self.metadata[meta.name] = self.$el.find( + "#" + meta.name.replace(":", "-") + )[0].value; } }); this.cmis_session - .createDocument(this.parent_cmisobject.objectId, this.file, this.metadata, this.file.mimeType) + .createDocument( + this.parent_cmisobject.objectId, + this.file, + this.metadata, + this.file.mimeType + ) .ok(function (new_cmisobject) { - self.getParent().trigger('cmis_node_created', [new_cmisobject]); - self.$el.parents('.modal').modal('hide'); + self.getParent().trigger("cmis_node_created", [new_cmisobject]); + self.$el.parents(".modal").modal("hide"); }) .notOk(function (error) { - console.log(error) - if (error) { - console.error(error.text); - if (error.type == 'application/json') { - var jerror = JSON.parse(error.text); - if (jerror.exception === 'objectNotFound') { - self.getParent().refresh_datatable(); - self.$el.parents('.modal').modal('hide'); - return; - } - } + console.log(error); + if (error) { + console.error(error.text); + if (error.type == "application/json") { + var jerror = JSON.parse(error.text); + if (jerror.exception === "objectNotFound") { + self.getParent().refresh_datatable(); + self.$el.parents(".modal").modal("hide"); + return; + } } + } }); }, - }); -}); \ No newline at end of file +}); diff --git a/views/assets.xml b/views/assets.xml index dd5c433db3bd1f5c3d7c654ece1a57db667dfb27..8c46ab50459173ba5bdbc0352e861be85094a02a 100644 --- a/views/assets.xml +++ b/views/assets.xml @@ -1,11 +1,17 @@ -<?xml version="1.0"?> +<?xml version="1.0" ?> <!-- Copyright 2020 Le Filament License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> - <odoo> - <template id="assets_backend" name="cgscop_alfodoo_assets" inherit_id="cmis_web.assets_backend"> + <template + id="assets_backend" + name="cgscop_alfodoo_assets" + inherit_id="cmis_web.assets_backend" + > <xpath expr="." position="inside"> - <script type="text/javascript" src="/cgscop_alfresco/static/src/js/form_widgets.js"/> + <script + type="text/javascript" + src="/cgscop_alfresco/static/src/js/form_widgets.js" + /> </xpath> </template> </odoo> diff --git a/views/cmis_backend.xml b/views/cmis_backend.xml index 89f7da529a579fa62af3a08ff8c47309b14671ed..89aa082c19f594558ebb993f34026ed0da162ee7 100644 --- a/views/cmis_backend.xml +++ b/views/cmis_backend.xml @@ -1,20 +1,19 @@ -<?xml version="1.0"?> +<?xml version="1.0" ?> <!-- Copyright 2019 Le Filament License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> - <odoo> <data> <record id="view_cmis_backend_cgscop_form_inherited" model="ir.ui.view"> <field name="name">cmis.backend.cgscop.form</field> <field name="model">cmis.backend</field> - <field name="inherit_id" ref="cmis.cmis_backend_form_view"/> + <field name="inherit_id" ref="cmis.cmis_backend_form_view" /> <field name="arch" type="xml"> <sheet position="inside"> <group name="cgscop" string="API Alfresco CG Scop"> - <field name="url"/> - <field name="ssl"/> - <field name="active"/> + <field name="url" /> + <field name="ssl" /> + <field name="active" /> </group> </sheet> </field>