Browse Source
Merge branch '8.0' of https://github.com/oca/server-tools into 8.0-add-database_cleanup
pull/95/head
Merge branch '8.0' of https://github.com/oca/server-tools into 8.0-add-database_cleanup
pull/95/head
Anthony Muschang
10 years ago
203 changed files with 9920 additions and 0 deletions
-
56.gitignore
-
29.travis.yml
-
661LICENSE
-
12README.md
-
23__unported__/auth_admin_passkey/__init__.py
-
66__unported__/auth_admin_passkey/__openerp__.py
-
34__unported__/auth_admin_passkey/data/ir_config_parameter.xml
-
101__unported__/auth_admin_passkey/i18n/auth_admin_passkey.pot
-
120__unported__/auth_admin_passkey/i18n/fr.po
-
24__unported__/auth_admin_passkey/model/__init__.py
-
76__unported__/auth_admin_passkey/model/res_config.py
-
137__unported__/auth_admin_passkey/model/res_users.py
-
BIN__unported__/auth_admin_passkey/static/src/img/icon.png
-
23__unported__/auth_admin_passkey/tests/__init__.py
-
99__unported__/auth_admin_passkey/tests/test_auth_admin_passkey.py
-
47__unported__/auth_admin_passkey/view/res_config_view.xml
-
56__unported__/auth_from_http_basic/__init__.py
-
62__unported__/auth_from_http_basic/__openerp__.py
-
20__unported__/auth_from_http_basic_logout/__init__.py
-
57__unported__/auth_from_http_basic_logout/__openerp__.py
-
23__unported__/auth_from_http_basic_logout/i18n/auth_from_http_basic_logout.pot
-
27__unported__/auth_from_http_basic_logout/i18n/nl.po
-
BIN__unported__/auth_from_http_basic_logout/static/src/img/icon.png
-
48__unported__/auth_from_http_basic_logout/static/src/js/auth_from_http_basic_logout.js
-
24__unported__/base_external_dbsource/__init__.py
-
66__unported__/base_external_dbsource/__openerp__.py
-
175__unported__/base_external_dbsource/base_external_dbsource.py
-
15__unported__/base_external_dbsource/base_external_dbsource_demo.xml
-
54__unported__/base_external_dbsource/base_external_dbsource_view.xml
-
BIN__unported__/base_external_dbsource/images/screenshot01.png
-
2__unported__/base_external_dbsource/security/ir.model.access.csv
-
9__unported__/base_external_dbsource/test/dbsource_connect.yml
-
22__unported__/configuration_helper/__init__.py
-
82__unported__/configuration_helper/__openerp__.py
-
114__unported__/configuration_helper/config.py
-
1__unported__/email_template_template/__init__.py
-
105__unported__/email_template_template/__openerp__.py
-
16__unported__/email_template_template/i18n/email_template_template.pot
-
21__unported__/email_template_template/model/__init__.py
-
61__unported__/email_template_template/model/email_template.py
-
70__unported__/email_template_template/view/email_template.xml
-
25__unported__/fetchmail_attach_from_folder/__init__.py
-
46__unported__/fetchmail_attach_from_folder/__openerp__.py
-
26__unported__/fetchmail_attach_from_folder/match_algorithm/__init__.py
-
43__unported__/fetchmail_attach_from_folder/match_algorithm/base.py
-
45__unported__/fetchmail_attach_from_folder/match_algorithm/email_domain.py
-
57__unported__/fetchmail_attach_from_folder/match_algorithm/email_exact.py
-
58__unported__/fetchmail_attach_from_folder/match_algorithm/openerp_standard.py
-
24__unported__/fetchmail_attach_from_folder/model/__init__.py
-
278__unported__/fetchmail_attach_from_folder/model/fetchmail_server.py
-
131__unported__/fetchmail_attach_from_folder/model/fetchmail_server_folder.py
-
2__unported__/fetchmail_attach_from_folder/security/ir.model.access.csv
-
56__unported__/fetchmail_attach_from_folder/view/fetchmail_server.xml
-
23__unported__/fetchmail_attach_from_folder/wizard/__init__.py
-
129__unported__/fetchmail_attach_from_folder/wizard/attach_mail_manually.py
-
29__unported__/fetchmail_attach_from_folder/wizard/attach_mail_manually.xml
-
24__unported__/import_odbc/__init__.py
-
101__unported__/import_odbc/__openerp__.py
-
BIN__unported__/import_odbc/images/snapshot1.png
-
BIN__unported__/import_odbc/images/snapshot2.png
-
216__unported__/import_odbc/import_odbc.py
-
15__unported__/import_odbc/import_odbc_demo.xml
-
90__unported__/import_odbc/import_odbc_view.xml
-
2__unported__/import_odbc/security/ir.model.access.csv
-
0__unported__/ir_config_parameter_viewer/__init__.py
-
20__unported__/ir_config_parameter_viewer/__openerp__.py
-
16__unported__/ir_config_parameter_viewer/i18n/ir_config_parameter_viewer.pot
-
36__unported__/ir_config_parameter_viewer/ir_config_parameter_view.xml
-
1__unported__/mail_environment/__init__.py
-
68__unported__/mail_environment/__openerp__.py
-
225__unported__/mail_environment/env_mail.py
-
16__unported__/mail_environment/i18n/mail_environment.pot
-
27__unported__/mail_environment/mail_view.xml
-
1__unported__/security_protector/__init__.py
-
25__unported__/security_protector/__openerp__.py
-
8__unported__/security_protector/data.xml
-
16__unported__/security_protector/i18n/security_protector.pot
-
47__unported__/security_protector/security_protector.py
-
8__unported__/security_protector/security_view.xml
-
22__unported__/server_env_base_external_referentials/__init__.py
-
47__unported__/server_env_base_external_referentials/__openerp__.py
-
54__unported__/server_env_base_external_referentials/base_external_referentials.py
-
16__unported__/server_env_base_external_referentials/i18n/server_env_base_external_referentials.pot
-
1__unported__/super_calendar/AUTHORS.txt
-
21__unported__/super_calendar/__init__.py
-
88__unported__/super_calendar/__openerp__.py
-
15__unported__/super_calendar/cron_data.xml
-
212__unported__/super_calendar/i18n/it.po
-
211__unported__/super_calendar/i18n/ru.po
-
210__unported__/super_calendar/i18n/super_calendar.pot
-
4__unported__/super_calendar/security/ir.model.access.csv
-
163__unported__/super_calendar/super_calendar.py
-
144__unported__/super_calendar/super_calendar_view.xml
-
22__unported__/users_ldap_groups/__init__.py
-
61__unported__/users_ldap_groups/__openerp__.py
-
16__unported__/users_ldap_groups/i18n/users_ldap_groups.pot
-
2__unported__/users_ldap_groups/security/ir.model.access.csv
-
107__unported__/users_ldap_groups/users_ldap_groups.py
-
27__unported__/users_ldap_groups/users_ldap_groups.xml
-
47__unported__/users_ldap_groups/users_ldap_groups_operators.py
@ -0,0 +1,56 @@ |
|||||
|
# Byte-compiled / optimized / DLL files |
||||
|
__pycache__/ |
||||
|
*.py[cod] |
||||
|
|
||||
|
# C extensions |
||||
|
*.so |
||||
|
|
||||
|
# Distribution / packaging |
||||
|
.Python |
||||
|
env/ |
||||
|
bin/ |
||||
|
build/ |
||||
|
develop-eggs/ |
||||
|
dist/ |
||||
|
eggs/ |
||||
|
lib/ |
||||
|
lib64/ |
||||
|
parts/ |
||||
|
sdist/ |
||||
|
var/ |
||||
|
*.egg-info/ |
||||
|
.installed.cfg |
||||
|
*.egg |
||||
|
|
||||
|
# 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 |
||||
|
|
||||
|
# Mr Developer |
||||
|
.mr.developer.cfg |
||||
|
.project |
||||
|
.pydevproject |
||||
|
|
||||
|
# Rope |
||||
|
.ropeproject |
||||
|
|
||||
|
# Sphinx documentation |
||||
|
docs/_build/ |
||||
|
|
||||
|
# Backup files |
||||
|
*~ |
||||
|
*.swp |
@ -0,0 +1,29 @@ |
|||||
|
language: python |
||||
|
|
||||
|
python: |
||||
|
- "2.7" |
||||
|
|
||||
|
env: |
||||
|
- VERSION="8.0" ODOO_REPO="odoo/odoo" |
||||
|
- VERSION="8.0" ODOO_REPO="OCA/OCB" |
||||
|
- VERSION="8.0" UNIT_TEST="1" |
||||
|
|
||||
|
virtualenv: |
||||
|
system_site_packages: true |
||||
|
|
||||
|
env: |
||||
|
- VERSION="8.0" ODOO_REPO="odoo/odoo" |
||||
|
- VERSION="8.0" ODOO_REPO="OCA/OCB" |
||||
|
|
||||
|
install: |
||||
|
- git clone https://github.com/OCA/maintainer-quality-tools.git ${HOME}/maintainer-quality-tools |
||||
|
- export PATH=${HOME}/maintainer-quality-tools/travis:${PATH} |
||||
|
- travis_install_nightly |
||||
|
- sudo pip install python-ldap |
||||
|
- printf '[options]\n\nrunning_env = dev' > ${HOME}/.openerp_serverrc |
||||
|
- ln -s server_environment_files_sample ./server_environment_files |
||||
|
script: |
||||
|
- travis_run_tests |
||||
|
|
||||
|
after_success: |
||||
|
coveralls |
@ -0,0 +1,661 @@ |
|||||
|
GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
Version 3, 19 November 2007 |
||||
|
|
||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> |
||||
|
Everyone is permitted to copy and distribute verbatim copies |
||||
|
of this license document, but changing it is not allowed. |
||||
|
|
||||
|
Preamble |
||||
|
|
||||
|
The GNU Affero General Public License is a free, copyleft license for |
||||
|
software and other kinds of works, specifically designed to ensure |
||||
|
cooperation with the community in the case of network server software. |
||||
|
|
||||
|
The licenses for most software and other practical works are designed |
||||
|
to take away your freedom to share and change the works. By contrast, |
||||
|
our General Public Licenses are intended to guarantee your freedom to |
||||
|
share and change all versions of a program--to make sure it remains free |
||||
|
software for all its users. |
||||
|
|
||||
|
When we speak of free software, we are referring to freedom, not |
||||
|
price. Our General Public Licenses are designed to make sure that you |
||||
|
have the freedom to distribute copies of free software (and charge for |
||||
|
them if you wish), that you receive source code or can get it if you |
||||
|
want it, that you can change the software or use pieces of it in new |
||||
|
free programs, and that you know you can do these things. |
||||
|
|
||||
|
Developers that use our General Public Licenses protect your rights |
||||
|
with two steps: (1) assert copyright on the software, and (2) offer |
||||
|
you this License which gives you legal permission to copy, distribute |
||||
|
and/or modify the software. |
||||
|
|
||||
|
A secondary benefit of defending all users' freedom is that |
||||
|
improvements made in alternate versions of the program, if they |
||||
|
receive widespread use, become available for other developers to |
||||
|
incorporate. Many developers of free software are heartened and |
||||
|
encouraged by the resulting cooperation. However, in the case of |
||||
|
software used on network servers, this result may fail to come about. |
||||
|
The GNU General Public License permits making a modified version and |
||||
|
letting the public access it on a server without ever releasing its |
||||
|
source code to the public. |
||||
|
|
||||
|
The GNU Affero General Public License is designed specifically to |
||||
|
ensure that, in such cases, the modified source code becomes available |
||||
|
to the community. It requires the operator of a network server to |
||||
|
provide the source code of the modified version running there to the |
||||
|
users of that server. Therefore, public use of a modified version, on |
||||
|
a publicly accessible server, gives the public access to the source |
||||
|
code of the modified version. |
||||
|
|
||||
|
An older license, called the Affero General Public License and |
||||
|
published by Affero, was designed to accomplish similar goals. This is |
||||
|
a different license, not a version of the Affero GPL, but Affero has |
||||
|
released a new version of the Affero GPL which permits relicensing under |
||||
|
this license. |
||||
|
|
||||
|
The precise terms and conditions for copying, distribution and |
||||
|
modification follow. |
||||
|
|
||||
|
TERMS AND CONDITIONS |
||||
|
|
||||
|
0. Definitions. |
||||
|
|
||||
|
"This License" refers to version 3 of the GNU Affero General Public License. |
||||
|
|
||||
|
"Copyright" also means copyright-like laws that apply to other kinds of |
||||
|
works, such as semiconductor masks. |
||||
|
|
||||
|
"The Program" refers to any copyrightable work licensed under this |
||||
|
License. Each licensee is addressed as "you". "Licensees" and |
||||
|
"recipients" may be individuals or organizations. |
||||
|
|
||||
|
To "modify" a work means to copy from or adapt all or part of the work |
||||
|
in a fashion requiring copyright permission, other than the making of an |
||||
|
exact copy. The resulting work is called a "modified version" of the |
||||
|
earlier work or a work "based on" the earlier work. |
||||
|
|
||||
|
A "covered work" means either the unmodified Program or a work based |
||||
|
on the Program. |
||||
|
|
||||
|
To "propagate" a work means to do anything with it that, without |
||||
|
permission, would make you directly or secondarily liable for |
||||
|
infringement under applicable copyright law, except executing it on a |
||||
|
computer or modifying a private copy. Propagation includes copying, |
||||
|
distribution (with or without modification), making available to the |
||||
|
public, and in some countries other activities as well. |
||||
|
|
||||
|
To "convey" a work means any kind of propagation that enables other |
||||
|
parties to make or receive copies. Mere interaction with a user through |
||||
|
a computer network, with no transfer of a copy, is not conveying. |
||||
|
|
||||
|
An interactive user interface displays "Appropriate Legal Notices" |
||||
|
to the extent that it includes a convenient and prominently visible |
||||
|
feature that (1) displays an appropriate copyright notice, and (2) |
||||
|
tells the user that there is no warranty for the work (except to the |
||||
|
extent that warranties are provided), that licensees may convey the |
||||
|
work under this License, and how to view a copy of this License. If |
||||
|
the interface presents a list of user commands or options, such as a |
||||
|
menu, a prominent item in the list meets this criterion. |
||||
|
|
||||
|
1. Source Code. |
||||
|
|
||||
|
The "source code" for a work means the preferred form of the work |
||||
|
for making modifications to it. "Object code" means any non-source |
||||
|
form of a work. |
||||
|
|
||||
|
A "Standard Interface" means an interface that either is an official |
||||
|
standard defined by a recognized standards body, or, in the case of |
||||
|
interfaces specified for a particular programming language, one that |
||||
|
is widely used among developers working in that language. |
||||
|
|
||||
|
The "System Libraries" of an executable work include anything, other |
||||
|
than the work as a whole, that (a) is included in the normal form of |
||||
|
packaging a Major Component, but which is not part of that Major |
||||
|
Component, and (b) serves only to enable use of the work with that |
||||
|
Major Component, or to implement a Standard Interface for which an |
||||
|
implementation is available to the public in source code form. A |
||||
|
"Major Component", in this context, means a major essential component |
||||
|
(kernel, window system, and so on) of the specific operating system |
||||
|
(if any) on which the executable work runs, or a compiler used to |
||||
|
produce the work, or an object code interpreter used to run it. |
||||
|
|
||||
|
The "Corresponding Source" for a work in object code form means all |
||||
|
the source code needed to generate, install, and (for an executable |
||||
|
work) run the object code and to modify the work, including scripts to |
||||
|
control those activities. However, it does not include the work's |
||||
|
System Libraries, or general-purpose tools or generally available free |
||||
|
programs which are used unmodified in performing those activities but |
||||
|
which are not part of the work. For example, Corresponding Source |
||||
|
includes interface definition files associated with source files for |
||||
|
the work, and the source code for shared libraries and dynamically |
||||
|
linked subprograms that the work is specifically designed to require, |
||||
|
such as by intimate data communication or control flow between those |
||||
|
subprograms and other parts of the work. |
||||
|
|
||||
|
The Corresponding Source need not include anything that users |
||||
|
can regenerate automatically from other parts of the Corresponding |
||||
|
Source. |
||||
|
|
||||
|
The Corresponding Source for a work in source code form is that |
||||
|
same work. |
||||
|
|
||||
|
2. Basic Permissions. |
||||
|
|
||||
|
All rights granted under this License are granted for the term of |
||||
|
copyright on the Program, and are irrevocable provided the stated |
||||
|
conditions are met. This License explicitly affirms your unlimited |
||||
|
permission to run the unmodified Program. The output from running a |
||||
|
covered work is covered by this License only if the output, given its |
||||
|
content, constitutes a covered work. This License acknowledges your |
||||
|
rights of fair use or other equivalent, as provided by copyright law. |
||||
|
|
||||
|
You may make, run and propagate covered works that you do not |
||||
|
convey, without conditions so long as your license otherwise remains |
||||
|
in force. You may convey covered works to others for the sole purpose |
||||
|
of having them make modifications exclusively for you, or provide you |
||||
|
with facilities for running those works, provided that you comply with |
||||
|
the terms of this License in conveying all material for which you do |
||||
|
not control copyright. Those thus making or running the covered works |
||||
|
for you must do so exclusively on your behalf, under your direction |
||||
|
and control, on terms that prohibit them from making any copies of |
||||
|
your copyrighted material outside their relationship with you. |
||||
|
|
||||
|
Conveying under any other circumstances is permitted solely under |
||||
|
the conditions stated below. Sublicensing is not allowed; section 10 |
||||
|
makes it unnecessary. |
||||
|
|
||||
|
3. Protecting Users' Legal Rights From Anti-Circumvention Law. |
||||
|
|
||||
|
No covered work shall be deemed part of an effective technological |
||||
|
measure under any applicable law fulfilling obligations under article |
||||
|
11 of the WIPO copyright treaty adopted on 20 December 1996, or |
||||
|
similar laws prohibiting or restricting circumvention of such |
||||
|
measures. |
||||
|
|
||||
|
When you convey a covered work, you waive any legal power to forbid |
||||
|
circumvention of technological measures to the extent such circumvention |
||||
|
is effected by exercising rights under this License with respect to |
||||
|
the covered work, and you disclaim any intention to limit operation or |
||||
|
modification of the work as a means of enforcing, against the work's |
||||
|
users, your or third parties' legal rights to forbid circumvention of |
||||
|
technological measures. |
||||
|
|
||||
|
4. Conveying Verbatim Copies. |
||||
|
|
||||
|
You may convey verbatim copies of the Program's source code as you |
||||
|
receive it, in any medium, provided that you conspicuously and |
||||
|
appropriately publish on each copy an appropriate copyright notice; |
||||
|
keep intact all notices stating that this License and any |
||||
|
non-permissive terms added in accord with section 7 apply to the code; |
||||
|
keep intact all notices of the absence of any warranty; and give all |
||||
|
recipients a copy of this License along with the Program. |
||||
|
|
||||
|
You may charge any price or no price for each copy that you convey, |
||||
|
and you may offer support or warranty protection for a fee. |
||||
|
|
||||
|
5. Conveying Modified Source Versions. |
||||
|
|
||||
|
You may convey a work based on the Program, or the modifications to |
||||
|
produce it from the Program, in the form of source code under the |
||||
|
terms of section 4, provided that you also meet all of these conditions: |
||||
|
|
||||
|
a) The work must carry prominent notices stating that you modified |
||||
|
it, and giving a relevant date. |
||||
|
|
||||
|
b) The work must carry prominent notices stating that it is |
||||
|
released under this License and any conditions added under section |
||||
|
7. This requirement modifies the requirement in section 4 to |
||||
|
"keep intact all notices". |
||||
|
|
||||
|
c) You must license the entire work, as a whole, under this |
||||
|
License to anyone who comes into possession of a copy. This |
||||
|
License will therefore apply, along with any applicable section 7 |
||||
|
additional terms, to the whole of the work, and all its parts, |
||||
|
regardless of how they are packaged. This License gives no |
||||
|
permission to license the work in any other way, but it does not |
||||
|
invalidate such permission if you have separately received it. |
||||
|
|
||||
|
d) If the work has interactive user interfaces, each must display |
||||
|
Appropriate Legal Notices; however, if the Program has interactive |
||||
|
interfaces that do not display Appropriate Legal Notices, your |
||||
|
work need not make them do so. |
||||
|
|
||||
|
A compilation of a covered work with other separate and independent |
||||
|
works, which are not by their nature extensions of the covered work, |
||||
|
and which are not combined with it such as to form a larger program, |
||||
|
in or on a volume of a storage or distribution medium, is called an |
||||
|
"aggregate" if the compilation and its resulting copyright are not |
||||
|
used to limit the access or legal rights of the compilation's users |
||||
|
beyond what the individual works permit. Inclusion of a covered work |
||||
|
in an aggregate does not cause this License to apply to the other |
||||
|
parts of the aggregate. |
||||
|
|
||||
|
6. Conveying Non-Source Forms. |
||||
|
|
||||
|
You may convey a covered work in object code form under the terms |
||||
|
of sections 4 and 5, provided that you also convey the |
||||
|
machine-readable Corresponding Source under the terms of this License, |
||||
|
in one of these ways: |
||||
|
|
||||
|
a) Convey the object code in, or embodied in, a physical product |
||||
|
(including a physical distribution medium), accompanied by the |
||||
|
Corresponding Source fixed on a durable physical medium |
||||
|
customarily used for software interchange. |
||||
|
|
||||
|
b) Convey the object code in, or embodied in, a physical product |
||||
|
(including a physical distribution medium), accompanied by a |
||||
|
written offer, valid for at least three years and valid for as |
||||
|
long as you offer spare parts or customer support for that product |
||||
|
model, to give anyone who possesses the object code either (1) a |
||||
|
copy of the Corresponding Source for all the software in the |
||||
|
product that is covered by this License, on a durable physical |
||||
|
medium customarily used for software interchange, for a price no |
||||
|
more than your reasonable cost of physically performing this |
||||
|
conveying of source, or (2) access to copy the |
||||
|
Corresponding Source from a network server at no charge. |
||||
|
|
||||
|
c) Convey individual copies of the object code with a copy of the |
||||
|
written offer to provide the Corresponding Source. This |
||||
|
alternative is allowed only occasionally and noncommercially, and |
||||
|
only if you received the object code with such an offer, in accord |
||||
|
with subsection 6b. |
||||
|
|
||||
|
d) Convey the object code by offering access from a designated |
||||
|
place (gratis or for a charge), and offer equivalent access to the |
||||
|
Corresponding Source in the same way through the same place at no |
||||
|
further charge. You need not require recipients to copy the |
||||
|
Corresponding Source along with the object code. If the place to |
||||
|
copy the object code is a network server, the Corresponding Source |
||||
|
may be on a different server (operated by you or a third party) |
||||
|
that supports equivalent copying facilities, provided you maintain |
||||
|
clear directions next to the object code saying where to find the |
||||
|
Corresponding Source. Regardless of what server hosts the |
||||
|
Corresponding Source, you remain obligated to ensure that it is |
||||
|
available for as long as needed to satisfy these requirements. |
||||
|
|
||||
|
e) Convey the object code using peer-to-peer transmission, provided |
||||
|
you inform other peers where the object code and Corresponding |
||||
|
Source of the work are being offered to the general public at no |
||||
|
charge under subsection 6d. |
||||
|
|
||||
|
A separable portion of the object code, whose source code is excluded |
||||
|
from the Corresponding Source as a System Library, need not be |
||||
|
included in conveying the object code work. |
||||
|
|
||||
|
A "User Product" is either (1) a "consumer product", which means any |
||||
|
tangible personal property which is normally used for personal, family, |
||||
|
or household purposes, or (2) anything designed or sold for incorporation |
||||
|
into a dwelling. In determining whether a product is a consumer product, |
||||
|
doubtful cases shall be resolved in favor of coverage. For a particular |
||||
|
product received by a particular user, "normally used" refers to a |
||||
|
typical or common use of that class of product, regardless of the status |
||||
|
of the particular user or of the way in which the particular user |
||||
|
actually uses, or expects or is expected to use, the product. A product |
||||
|
is a consumer product regardless of whether the product has substantial |
||||
|
commercial, industrial or non-consumer uses, unless such uses represent |
||||
|
the only significant mode of use of the product. |
||||
|
|
||||
|
"Installation Information" for a User Product means any methods, |
||||
|
procedures, authorization keys, or other information required to install |
||||
|
and execute modified versions of a covered work in that User Product from |
||||
|
a modified version of its Corresponding Source. The information must |
||||
|
suffice to ensure that the continued functioning of the modified object |
||||
|
code is in no case prevented or interfered with solely because |
||||
|
modification has been made. |
||||
|
|
||||
|
If you convey an object code work under this section in, or with, or |
||||
|
specifically for use in, a User Product, and the conveying occurs as |
||||
|
part of a transaction in which the right of possession and use of the |
||||
|
User Product is transferred to the recipient in perpetuity or for a |
||||
|
fixed term (regardless of how the transaction is characterized), the |
||||
|
Corresponding Source conveyed under this section must be accompanied |
||||
|
by the Installation Information. But this requirement does not apply |
||||
|
if neither you nor any third party retains the ability to install |
||||
|
modified object code on the User Product (for example, the work has |
||||
|
been installed in ROM). |
||||
|
|
||||
|
The requirement to provide Installation Information does not include a |
||||
|
requirement to continue to provide support service, warranty, or updates |
||||
|
for a work that has been modified or installed by the recipient, or for |
||||
|
the User Product in which it has been modified or installed. Access to a |
||||
|
network may be denied when the modification itself materially and |
||||
|
adversely affects the operation of the network or violates the rules and |
||||
|
protocols for communication across the network. |
||||
|
|
||||
|
Corresponding Source conveyed, and Installation Information provided, |
||||
|
in accord with this section must be in a format that is publicly |
||||
|
documented (and with an implementation available to the public in |
||||
|
source code form), and must require no special password or key for |
||||
|
unpacking, reading or copying. |
||||
|
|
||||
|
7. Additional Terms. |
||||
|
|
||||
|
"Additional permissions" are terms that supplement the terms of this |
||||
|
License by making exceptions from one or more of its conditions. |
||||
|
Additional permissions that are applicable to the entire Program shall |
||||
|
be treated as though they were included in this License, to the extent |
||||
|
that they are valid under applicable law. If additional permissions |
||||
|
apply only to part of the Program, that part may be used separately |
||||
|
under those permissions, but the entire Program remains governed by |
||||
|
this License without regard to the additional permissions. |
||||
|
|
||||
|
When you convey a copy of a covered work, you may at your option |
||||
|
remove any additional permissions from that copy, or from any part of |
||||
|
it. (Additional permissions may be written to require their own |
||||
|
removal in certain cases when you modify the work.) You may place |
||||
|
additional permissions on material, added by you to a covered work, |
||||
|
for which you have or can give appropriate copyright permission. |
||||
|
|
||||
|
Notwithstanding any other provision of this License, for material you |
||||
|
add to a covered work, you may (if authorized by the copyright holders of |
||||
|
that material) supplement the terms of this License with terms: |
||||
|
|
||||
|
a) Disclaiming warranty or limiting liability differently from the |
||||
|
terms of sections 15 and 16 of this License; or |
||||
|
|
||||
|
b) Requiring preservation of specified reasonable legal notices or |
||||
|
author attributions in that material or in the Appropriate Legal |
||||
|
Notices displayed by works containing it; or |
||||
|
|
||||
|
c) Prohibiting misrepresentation of the origin of that material, or |
||||
|
requiring that modified versions of such material be marked in |
||||
|
reasonable ways as different from the original version; or |
||||
|
|
||||
|
d) Limiting the use for publicity purposes of names of licensors or |
||||
|
authors of the material; or |
||||
|
|
||||
|
e) Declining to grant rights under trademark law for use of some |
||||
|
trade names, trademarks, or service marks; or |
||||
|
|
||||
|
f) Requiring indemnification of licensors and authors of that |
||||
|
material by anyone who conveys the material (or modified versions of |
||||
|
it) with contractual assumptions of liability to the recipient, for |
||||
|
any liability that these contractual assumptions directly impose on |
||||
|
those licensors and authors. |
||||
|
|
||||
|
All other non-permissive additional terms are considered "further |
||||
|
restrictions" within the meaning of section 10. If the Program as you |
||||
|
received it, or any part of it, contains a notice stating that it is |
||||
|
governed by this License along with a term that is a further |
||||
|
restriction, you may remove that term. If a license document contains |
||||
|
a further restriction but permits relicensing or conveying under this |
||||
|
License, you may add to a covered work material governed by the terms |
||||
|
of that license document, provided that the further restriction does |
||||
|
not survive such relicensing or conveying. |
||||
|
|
||||
|
If you add terms to a covered work in accord with this section, you |
||||
|
must place, in the relevant source files, a statement of the |
||||
|
additional terms that apply to those files, or a notice indicating |
||||
|
where to find the applicable terms. |
||||
|
|
||||
|
Additional terms, permissive or non-permissive, may be stated in the |
||||
|
form of a separately written license, or stated as exceptions; |
||||
|
the above requirements apply either way. |
||||
|
|
||||
|
8. Termination. |
||||
|
|
||||
|
You may not propagate or modify a covered work except as expressly |
||||
|
provided under this License. Any attempt otherwise to propagate or |
||||
|
modify it is void, and will automatically terminate your rights under |
||||
|
this License (including any patent licenses granted under the third |
||||
|
paragraph of section 11). |
||||
|
|
||||
|
However, if you cease all violation of this License, then your |
||||
|
license from a particular copyright holder is reinstated (a) |
||||
|
provisionally, unless and until the copyright holder explicitly and |
||||
|
finally terminates your license, and (b) permanently, if the copyright |
||||
|
holder fails to notify you of the violation by some reasonable means |
||||
|
prior to 60 days after the cessation. |
||||
|
|
||||
|
Moreover, your license from a particular copyright holder is |
||||
|
reinstated permanently if the copyright holder notifies you of the |
||||
|
violation by some reasonable means, this is the first time you have |
||||
|
received notice of violation of this License (for any work) from that |
||||
|
copyright holder, and you cure the violation prior to 30 days after |
||||
|
your receipt of the notice. |
||||
|
|
||||
|
Termination of your rights under this section does not terminate the |
||||
|
licenses of parties who have received copies or rights from you under |
||||
|
this License. If your rights have been terminated and not permanently |
||||
|
reinstated, you do not qualify to receive new licenses for the same |
||||
|
material under section 10. |
||||
|
|
||||
|
9. Acceptance Not Required for Having Copies. |
||||
|
|
||||
|
You are not required to accept this License in order to receive or |
||||
|
run a copy of the Program. Ancillary propagation of a covered work |
||||
|
occurring solely as a consequence of using peer-to-peer transmission |
||||
|
to receive a copy likewise does not require acceptance. However, |
||||
|
nothing other than this License grants you permission to propagate or |
||||
|
modify any covered work. These actions infringe copyright if you do |
||||
|
not accept this License. Therefore, by modifying or propagating a |
||||
|
covered work, you indicate your acceptance of this License to do so. |
||||
|
|
||||
|
10. Automatic Licensing of Downstream Recipients. |
||||
|
|
||||
|
Each time you convey a covered work, the recipient automatically |
||||
|
receives a license from the original licensors, to run, modify and |
||||
|
propagate that work, subject to this License. You are not responsible |
||||
|
for enforcing compliance by third parties with this License. |
||||
|
|
||||
|
An "entity transaction" is a transaction transferring control of an |
||||
|
organization, or substantially all assets of one, or subdividing an |
||||
|
organization, or merging organizations. If propagation of a covered |
||||
|
work results from an entity transaction, each party to that |
||||
|
transaction who receives a copy of the work also receives whatever |
||||
|
licenses to the work the party's predecessor in interest had or could |
||||
|
give under the previous paragraph, plus a right to possession of the |
||||
|
Corresponding Source of the work from the predecessor in interest, if |
||||
|
the predecessor has it or can get it with reasonable efforts. |
||||
|
|
||||
|
You may not impose any further restrictions on the exercise of the |
||||
|
rights granted or affirmed under this License. For example, you may |
||||
|
not impose a license fee, royalty, or other charge for exercise of |
||||
|
rights granted under this License, and you may not initiate litigation |
||||
|
(including a cross-claim or counterclaim in a lawsuit) alleging that |
||||
|
any patent claim is infringed by making, using, selling, offering for |
||||
|
sale, or importing the Program or any portion of it. |
||||
|
|
||||
|
11. Patents. |
||||
|
|
||||
|
A "contributor" is a copyright holder who authorizes use under this |
||||
|
License of the Program or a work on which the Program is based. The |
||||
|
work thus licensed is called the contributor's "contributor version". |
||||
|
|
||||
|
A contributor's "essential patent claims" are all patent claims |
||||
|
owned or controlled by the contributor, whether already acquired or |
||||
|
hereafter acquired, that would be infringed by some manner, permitted |
||||
|
by this License, of making, using, or selling its contributor version, |
||||
|
but do not include claims that would be infringed only as a |
||||
|
consequence of further modification of the contributor version. For |
||||
|
purposes of this definition, "control" includes the right to grant |
||||
|
patent sublicenses in a manner consistent with the requirements of |
||||
|
this License. |
||||
|
|
||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free |
||||
|
patent license under the contributor's essential patent claims, to |
||||
|
make, use, sell, offer for sale, import and otherwise run, modify and |
||||
|
propagate the contents of its contributor version. |
||||
|
|
||||
|
In the following three paragraphs, a "patent license" is any express |
||||
|
agreement or commitment, however denominated, not to enforce a patent |
||||
|
(such as an express permission to practice a patent or covenant not to |
||||
|
sue for patent infringement). To "grant" such a patent license to a |
||||
|
party means to make such an agreement or commitment not to enforce a |
||||
|
patent against the party. |
||||
|
|
||||
|
If you convey a covered work, knowingly relying on a patent license, |
||||
|
and the Corresponding Source of the work is not available for anyone |
||||
|
to copy, free of charge and under the terms of this License, through a |
||||
|
publicly available network server or other readily accessible means, |
||||
|
then you must either (1) cause the Corresponding Source to be so |
||||
|
available, or (2) arrange to deprive yourself of the benefit of the |
||||
|
patent license for this particular work, or (3) arrange, in a manner |
||||
|
consistent with the requirements of this License, to extend the patent |
||||
|
license to downstream recipients. "Knowingly relying" means you have |
||||
|
actual knowledge that, but for the patent license, your conveying the |
||||
|
covered work in a country, or your recipient's use of the covered work |
||||
|
in a country, would infringe one or more identifiable patents in that |
||||
|
country that you have reason to believe are valid. |
||||
|
|
||||
|
If, pursuant to or in connection with a single transaction or |
||||
|
arrangement, you convey, or propagate by procuring conveyance of, a |
||||
|
covered work, and grant a patent license to some of the parties |
||||
|
receiving the covered work authorizing them to use, propagate, modify |
||||
|
or convey a specific copy of the covered work, then the patent license |
||||
|
you grant is automatically extended to all recipients of the covered |
||||
|
work and works based on it. |
||||
|
|
||||
|
A patent license is "discriminatory" if it does not include within |
||||
|
the scope of its coverage, prohibits the exercise of, or is |
||||
|
conditioned on the non-exercise of one or more of the rights that are |
||||
|
specifically granted under this License. You may not convey a covered |
||||
|
work if you are a party to an arrangement with a third party that is |
||||
|
in the business of distributing software, under which you make payment |
||||
|
to the third party based on the extent of your activity of conveying |
||||
|
the work, and under which the third party grants, to any of the |
||||
|
parties who would receive the covered work from you, a discriminatory |
||||
|
patent license (a) in connection with copies of the covered work |
||||
|
conveyed by you (or copies made from those copies), or (b) primarily |
||||
|
for and in connection with specific products or compilations that |
||||
|
contain the covered work, unless you entered into that arrangement, |
||||
|
or that patent license was granted, prior to 28 March 2007. |
||||
|
|
||||
|
Nothing in this License shall be construed as excluding or limiting |
||||
|
any implied license or other defenses to infringement that may |
||||
|
otherwise be available to you under applicable patent law. |
||||
|
|
||||
|
12. No Surrender of Others' Freedom. |
||||
|
|
||||
|
If conditions are imposed on you (whether by court order, agreement or |
||||
|
otherwise) that contradict the conditions of this License, they do not |
||||
|
excuse you from the conditions of this License. If you cannot convey a |
||||
|
covered work so as to satisfy simultaneously your obligations under this |
||||
|
License and any other pertinent obligations, then as a consequence you may |
||||
|
not convey it at all. For example, if you agree to terms that obligate you |
||||
|
to collect a royalty for further conveying from those to whom you convey |
||||
|
the Program, the only way you could satisfy both those terms and this |
||||
|
License would be to refrain entirely from conveying the Program. |
||||
|
|
||||
|
13. Remote Network Interaction; Use with the GNU General Public License. |
||||
|
|
||||
|
Notwithstanding any other provision of this License, if you modify the |
||||
|
Program, your modified version must prominently offer all users |
||||
|
interacting with it remotely through a computer network (if your version |
||||
|
supports such interaction) an opportunity to receive the Corresponding |
||||
|
Source of your version by providing access to the Corresponding Source |
||||
|
from a network server at no charge, through some standard or customary |
||||
|
means of facilitating copying of software. This Corresponding Source |
||||
|
shall include the Corresponding Source for any work covered by version 3 |
||||
|
of the GNU General Public License that is incorporated pursuant to the |
||||
|
following paragraph. |
||||
|
|
||||
|
Notwithstanding any other provision of this License, you have |
||||
|
permission to link or combine any covered work with a work licensed |
||||
|
under version 3 of the GNU General Public License into a single |
||||
|
combined work, and to convey the resulting work. The terms of this |
||||
|
License will continue to apply to the part which is the covered work, |
||||
|
but the work with which it is combined will remain governed by version |
||||
|
3 of the GNU General Public License. |
||||
|
|
||||
|
14. Revised Versions of this License. |
||||
|
|
||||
|
The Free Software Foundation may publish revised and/or new versions of |
||||
|
the GNU Affero General Public License from time to time. Such new versions |
||||
|
will be similar in spirit to the present version, but may differ in detail to |
||||
|
address new problems or concerns. |
||||
|
|
||||
|
Each version is given a distinguishing version number. If the |
||||
|
Program specifies that a certain numbered version of the GNU Affero General |
||||
|
Public License "or any later version" applies to it, you have the |
||||
|
option of following the terms and conditions either of that numbered |
||||
|
version or of any later version published by the Free Software |
||||
|
Foundation. If the Program does not specify a version number of the |
||||
|
GNU Affero General Public License, you may choose any version ever published |
||||
|
by the Free Software Foundation. |
||||
|
|
||||
|
If the Program specifies that a proxy can decide which future |
||||
|
versions of the GNU Affero General Public License can be used, that proxy's |
||||
|
public statement of acceptance of a version permanently authorizes you |
||||
|
to choose that version for the Program. |
||||
|
|
||||
|
Later license versions may give you additional or different |
||||
|
permissions. However, no additional obligations are imposed on any |
||||
|
author or copyright holder as a result of your choosing to follow a |
||||
|
later version. |
||||
|
|
||||
|
15. Disclaimer of Warranty. |
||||
|
|
||||
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY |
||||
|
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT |
||||
|
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY |
||||
|
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, |
||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM |
||||
|
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF |
||||
|
ALL NECESSARY SERVICING, REPAIR OR CORRECTION. |
||||
|
|
||||
|
16. Limitation of Liability. |
||||
|
|
||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING |
||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS |
||||
|
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY |
||||
|
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE |
||||
|
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF |
||||
|
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD |
||||
|
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), |
||||
|
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF |
||||
|
SUCH DAMAGES. |
||||
|
|
||||
|
17. Interpretation of Sections 15 and 16. |
||||
|
|
||||
|
If the disclaimer of warranty and limitation of liability provided |
||||
|
above cannot be given local legal effect according to their terms, |
||||
|
reviewing courts shall apply local law that most closely approximates |
||||
|
an absolute waiver of all civil liability in connection with the |
||||
|
Program, unless a warranty or assumption of liability accompanies a |
||||
|
copy of the Program in return for a fee. |
||||
|
|
||||
|
END OF TERMS AND CONDITIONS |
||||
|
|
||||
|
How to Apply These Terms to Your New Programs |
||||
|
|
||||
|
If you develop a new program, and you want it to be of the greatest |
||||
|
possible use to the public, the best way to achieve this is to make it |
||||
|
free software which everyone can redistribute and change under these terms. |
||||
|
|
||||
|
To do so, attach the following notices to the program. It is safest |
||||
|
to attach them to the start of each source file to most effectively |
||||
|
state the exclusion of warranty; and each file should have at least |
||||
|
the "copyright" line and a pointer to where the full notice is found. |
||||
|
|
||||
|
<one line to give the program's name and a brief idea of what it does.> |
||||
|
Copyright (C) <year> <name of author> |
||||
|
|
||||
|
This program is free software: you can redistribute it and/or modify |
||||
|
it under the terms of the GNU Affero General Public License as published |
||||
|
by the Free Software Foundation, either version 3 of the License, or |
||||
|
(at your option) any later version. |
||||
|
|
||||
|
This program is distributed in the hope that it will be useful, |
||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
GNU Affero General Public License for more details. |
||||
|
|
||||
|
You should have received a copy of the GNU Affero General Public License |
||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
|
||||
|
Also add information on how to contact you by electronic and paper mail. |
||||
|
|
||||
|
If your software can interact with users remotely through a computer |
||||
|
network, you should also make sure that it provides a way for users to |
||||
|
get its source. For example, if your program is a web application, its |
||||
|
interface could display a "Source" link that leads users to an archive |
||||
|
of the code. There are many ways you could offer source, and different |
||||
|
solutions will be better for different programs; see section 13 for the |
||||
|
specific requirements. |
||||
|
|
||||
|
You should also get your employer (if you work as a programmer) or school, |
||||
|
if any, to sign a "copyright disclaimer" for the program, if necessary. |
||||
|
For more information on this, and how to apply and follow the GNU AGPL, see |
||||
|
<http://www.gnu.org/licenses/>. |
@ -0,0 +1,12 @@ |
|||||
|
[![Build Status](https://travis-ci.org/OCA/server-tools.svg?branch=8.0)](https://travis-ci.org/OCA/server-tools) |
||||
|
[![Coverage Status](https://coveralls.io/repos/OCA/server-tools/badge.png?branch=8.0)](https://coveralls.io/r/OCA/server-tools?branch=8.0) |
||||
|
|
||||
|
Server Environment And Tools |
||||
|
============================ |
||||
|
|
||||
|
This project aim to deal with modules related to manage Odoo server environment and provide useful tools. You'll find modules that: |
||||
|
|
||||
|
- Manage configuration depending on environment (devs, test, prod,..) |
||||
|
- Keep the security on update |
||||
|
- Manage email settings |
||||
|
-... |
@ -0,0 +1,23 @@ |
|||||
|
# -*- encoding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Admin Passkey module for OpenERP |
||||
|
# Copyright (C) 2013-2014 GRAP (http://www.grap.coop) |
||||
|
# @author Sylvain LE GAL (https://twitter.com/legalsylvain) |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
from . import model |
@ -0,0 +1,66 @@ |
|||||
|
# -*- encoding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Admin Passkey module for OpenERP |
||||
|
# Copyright (C) 2013-2014 GRAP (http://www.grap.coop) |
||||
|
# @author Sylvain LE GAL (https://twitter.com/legalsylvain) |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
{ |
||||
|
'name': 'Authentification - Admin Passkey', |
||||
|
'version': '2.1.1', |
||||
|
'category': 'base', |
||||
|
'description': """ |
||||
|
Admin password become a passkey for all active logins |
||||
|
===================================================== |
||||
|
|
||||
|
Functionality : |
||||
|
--------------- |
||||
|
* Administrator has now the possibility to login in with any login; |
||||
|
* By default, OpenERP will send a mail to user and admin to indicate them; |
||||
|
* If a user and the admin have the same password, admin will be informed; |
||||
|
|
||||
|
Technical information : |
||||
|
----------------------- |
||||
|
* Create two ir_config_parameter to enable / disable mail sending; |
||||
|
|
||||
|
Copyright, Author and Licence : |
||||
|
------------------------------- |
||||
|
* Copyright : 2014, Groupement Régional Alimentaire de Proximité; |
||||
|
* Author : Sylvain LE GAL (https://twitter.com/legalsylvain); |
||||
|
* Licence : AGPL-3 (http://www.gnu.org/licenses/) |
||||
|
""", |
||||
|
'author': 'GRAP', |
||||
|
'website': 'http://www.grap.coop', |
||||
|
'license': 'AGPL-3', |
||||
|
'depends': [ |
||||
|
'mail', |
||||
|
], |
||||
|
'data': [ |
||||
|
'data/ir_config_parameter.xml', |
||||
|
'view/res_config_view.xml', |
||||
|
], |
||||
|
'demo': [], |
||||
|
'js': [], |
||||
|
'css': [], |
||||
|
'qweb': [], |
||||
|
'images': [], |
||||
|
'post_load': '', |
||||
|
'application': False, |
||||
|
'installable': False, |
||||
|
'auto_install': False, |
||||
|
} |
@ -0,0 +1,34 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<!-- ********************************************************************** --> |
||||
|
<!--Admin Passkey module for OpenERP --> |
||||
|
<!--Copyright (C) 2013-2014 GRAP (http://www.grap.coop) --> |
||||
|
<!--@author Sylvain LE GAL (https://twitter.com/legalsylvain) --> |
||||
|
|
||||
|
<!--This program is free software: you can redistribute it and/or modify --> |
||||
|
<!--it under the terms of the GNU Affero General Public License as --> |
||||
|
<!--published by the Free Software Foundation, either version 3 of the --> |
||||
|
<!--License, or (at your option) any later version. --> |
||||
|
|
||||
|
<!--This program is distributed in the hope that it will be useful, --> |
||||
|
<!--but WITHOUT ANY WARRANTY; without even the implied warranty of --> |
||||
|
<!--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --> |
||||
|
<!--GNU Affero General Public License for more details. --> |
||||
|
|
||||
|
<!--You should have received a copy of the GNU Affero General Public License--> |
||||
|
<!--along with this program. If not, see <http://www.gnu.org/licenses/>. --> |
||||
|
<!-- ********************************************************************** --> |
||||
|
<openerp> |
||||
|
<data noupdate="1"> |
||||
|
|
||||
|
<record id="send_to_admin" model="ir.config_parameter"> |
||||
|
<field name="key">auth_admin_passkey.send_to_admin</field> |
||||
|
<field name="value">True</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="send_to_user" model="ir.config_parameter"> |
||||
|
<field name="key">auth_admin_passkey.send_to_user</field> |
||||
|
<field name="value">True</field> |
||||
|
</record> |
||||
|
|
||||
|
</data> |
||||
|
</openerp> |
@ -0,0 +1,101 @@ |
|||||
|
############################################################################## |
||||
|
# |
||||
|
# Admin Passkey module for OpenERP |
||||
|
# Copyright (C) 2013-2014 GRAP (http://www.grap.coop) |
||||
|
# @author Sylvain LE GAL (https://twitter.com/legalsylvain) |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
# Translation of OpenERP Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * auth_admin_passkey |
||||
|
# |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: OpenERP Server 7.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2014-03-23 20:41+0000\n" |
||||
|
"PO-Revision-Date: 2014-03-23 20:41+0000\n" |
||||
|
"Last-Translator: <>\n" |
||||
|
"Language-Team: \n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Plural-Forms: \n" |
||||
|
|
||||
|
#. module: auth_admin_passkey |
||||
|
#: code:addons/auth_admin_passkey/model/res_users.py:66 |
||||
|
#, python-format |
||||
|
msgid "<pre>User with login '%s' has the same password as you.</pre>" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: auth_admin_passkey |
||||
|
#: code:addons/auth_admin_passkey/model/res_users.py:44 |
||||
|
#, python-format |
||||
|
msgid "Admin user used his passkey to login with '%s'.\n" |
||||
|
"\n" |
||||
|
"\n" |
||||
|
"\n" |
||||
|
"Technicals informations belows : \n" |
||||
|
"\n" |
||||
|
"- Login date : %s\n" |
||||
|
"\n" |
||||
|
"" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: auth_admin_passkey |
||||
|
#: view:base.config.settings:0 |
||||
|
msgid "Passkey" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: auth_admin_passkey |
||||
|
#: code:addons/auth_admin_passkey/model/res_users.py:42 |
||||
|
#, python-format |
||||
|
msgid "Passkey used" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: auth_admin_passkey |
||||
|
#: field:base.config.settings,auth_admin_passkey_send_to_admin:0 |
||||
|
msgid "Send email to admin user." |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: auth_admin_passkey |
||||
|
#: field:base.config.settings,auth_admin_passkey_send_to_user:0 |
||||
|
msgid "Send email to user." |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: auth_admin_passkey |
||||
|
#: code:_description:0 |
||||
|
#: model:ir.model,name:auth_admin_passkey.model_res_users |
||||
|
#, python-format |
||||
|
msgid "Users" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: auth_admin_passkey |
||||
|
#: help:base.config.settings,auth_admin_passkey_send_to_user:0 |
||||
|
msgid "When the administrator use his password to login in with a different account, OpenERP will send an email to the account user." |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: auth_admin_passkey |
||||
|
#: help:base.config.settings,auth_admin_passkey_send_to_admin:0 |
||||
|
msgid "When the administrator use his password to login in with a different account, OpenERP will send an email to the admin user." |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: auth_admin_passkey |
||||
|
#: code:addons/auth_admin_passkey/model/res_users.py:64 |
||||
|
#, python-format |
||||
|
msgid "[WARNING] OpenERP Security Risk" |
||||
|
msgstr "" |
||||
|
|
@ -0,0 +1,120 @@ |
|||||
|
############################################################################## |
||||
|
# |
||||
|
# Admin Passkey module for OpenERP |
||||
|
# Copyright (C) 2013-2014 GRAP (http://www.grap.coop) |
||||
|
# @author Sylvain LE GAL (https://twitter.com/legalsylvain) |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
# Translation of OpenERP Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * auth_admin_passkey |
||||
|
# |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: OpenERP Server 7.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2014-03-23 20:41+0000\n" |
||||
|
"PO-Revision-Date: 2014-04-08 09:24+0000\n" |
||||
|
"Last-Translator: Sylvain LE GAL (GRAP) <Unknown>\n" |
||||
|
"Language-Team: \n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: 8bit\n" |
||||
|
"X-Launchpad-Export-Date: 2014-05-24 06:46+0000\n" |
||||
|
"X-Generator: Launchpad (build 17017)\n" |
||||
|
|
||||
|
#. module: auth_admin_passkey |
||||
|
#: code:addons/auth_admin_passkey/model/res_users.py:66 |
||||
|
#, python-format |
||||
|
msgid "<pre>User with login '%s' has the same password as you.</pre>" |
||||
|
msgstr "" |
||||
|
"<pre>L'utilisateur dont l'identifiant est '%s' a le même mot de passe que " |
||||
|
"vous.</pre>" |
||||
|
|
||||
|
#. module: auth_admin_passkey |
||||
|
#: code:addons/auth_admin_passkey/model/res_users.py:44 |
||||
|
#, python-format |
||||
|
msgid "" |
||||
|
"Admin user used his passkey to login with '%s'.\n" |
||||
|
"\n" |
||||
|
"\n" |
||||
|
"\n" |
||||
|
"Technicals informations belows : \n" |
||||
|
"\n" |
||||
|
"- Login date : %s\n" |
||||
|
"\n" |
||||
|
msgstr "" |
||||
|
"L'administrateur a utilisé son mot de passe \"bris de glace\" pour " |
||||
|
"s'identifier avec l'identifiant '%s'.\n" |
||||
|
"\n" |
||||
|
"\n" |
||||
|
"\n" |
||||
|
"Informations techniques ci-dessous : \n" |
||||
|
"\n" |
||||
|
"- Date d'authentification : %s\n" |
||||
|
"\n" |
||||
|
|
||||
|
#. module: auth_admin_passkey |
||||
|
#: view:base.config.settings:0 |
||||
|
msgid "Passkey" |
||||
|
msgstr "Mot de passe \"bris de glace\"" |
||||
|
|
||||
|
#. module: auth_admin_passkey |
||||
|
#: code:addons/auth_admin_passkey/model/res_users.py:42 |
||||
|
#, python-format |
||||
|
msgid "Passkey used" |
||||
|
msgstr "Mot de passe \"bris de glace\" utilisé" |
||||
|
|
||||
|
#. module: auth_admin_passkey |
||||
|
#: field:base.config.settings,auth_admin_passkey_send_to_admin:0 |
||||
|
msgid "Send email to admin user." |
||||
|
msgstr "Envoyer un email à l'administrateur." |
||||
|
|
||||
|
#. module: auth_admin_passkey |
||||
|
#: field:base.config.settings,auth_admin_passkey_send_to_user:0 |
||||
|
msgid "Send email to user." |
||||
|
msgstr "Envoyer un email à l'utilisateur." |
||||
|
|
||||
|
#. module: auth_admin_passkey |
||||
|
#: code:_description:0 |
||||
|
#: model:ir.model,name:auth_admin_passkey.model_res_users |
||||
|
#, python-format |
||||
|
msgid "Users" |
||||
|
msgstr "Utilisateurs" |
||||
|
|
||||
|
#. module: auth_admin_passkey |
||||
|
#: help:base.config.settings,auth_admin_passkey_send_to_user:0 |
||||
|
msgid "" |
||||
|
"When the administrator use his password to login in with a different " |
||||
|
"account, OpenERP will send an email to the account user." |
||||
|
msgstr "" |
||||
|
"Quand l'administrateur utilise son mot de passe pour s'authentifier avec un " |
||||
|
"compte différent, OpenERP lui enverra un mail." |
||||
|
|
||||
|
#. module: auth_admin_passkey |
||||
|
#: help:base.config.settings,auth_admin_passkey_send_to_admin:0 |
||||
|
msgid "" |
||||
|
"When the administrator use his password to login in with a different " |
||||
|
"account, OpenERP will send an email to the admin user." |
||||
|
msgstr "" |
||||
|
"Quand l'administrateur utilise son mot de passe pour s'authentifier avec un " |
||||
|
"compte différent, OpenERP enverra un mail à l'utilisateur." |
||||
|
|
||||
|
#. module: auth_admin_passkey |
||||
|
#: code:addons/auth_admin_passkey/model/res_users.py:64 |
||||
|
#, python-format |
||||
|
msgid "[WARNING] OpenERP Security Risk" |
||||
|
msgstr "[WARNING] Faille de sécurité sur OpenERP" |
@ -0,0 +1,24 @@ |
|||||
|
# -*- encoding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Admin Passkey module for OpenERP |
||||
|
# Copyright (C) 2013-2014 GRAP (http://www.grap.coop) |
||||
|
# @author Sylvain LE GAL (https://twitter.com/legalsylvain) |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
from . import res_config |
||||
|
from . import res_users |
@ -0,0 +1,76 @@ |
|||||
|
# -*- encoding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Admin Passkey module for OpenERP |
||||
|
# Copyright (C) 2013-2014 GRAP (http://www.grap.coop) |
||||
|
# @author Sylvain LE GAL (https://twitter.com/legalsylvain) |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
from openerp.osv import fields |
||||
|
from openerp.osv.orm import TransientModel |
||||
|
from openerp.tools.safe_eval import safe_eval |
||||
|
|
||||
|
|
||||
|
class base_config_settings(TransientModel): |
||||
|
_inherit = 'base.config.settings' |
||||
|
|
||||
|
# Getter / Setter Section |
||||
|
def get_default_auth_admin_passkey_send_to_admin( |
||||
|
self, cr, uid, ids, context=None): |
||||
|
icp = self.pool['ir.config_parameter'] |
||||
|
return { |
||||
|
'auth_admin_passkey_send_to_admin': safe_eval(icp.get_param( |
||||
|
cr, uid, 'auth_admin_passkey.send_to_admin', 'True')), |
||||
|
} |
||||
|
|
||||
|
def set_auth_admin_passkey_send_to_admin(self, cr, uid, ids, context=None): |
||||
|
config = self.browse(cr, uid, ids[0], context=context) |
||||
|
icp = self.pool['ir.config_parameter'] |
||||
|
icp.set_param( |
||||
|
cr, uid, 'auth_admin_passkey.send_to_admin', |
||||
|
repr(config.auth_admin_passkey_send_to_admin)) |
||||
|
|
||||
|
def get_default_auth_admin_passkey_send_to_user( |
||||
|
self, cr, uid, ids, context=None): |
||||
|
icp = self.pool['ir.config_parameter'] |
||||
|
return { |
||||
|
'auth_admin_passkey_send_to_user': safe_eval(icp.get_param( |
||||
|
cr, uid, 'auth_admin_passkey.send_to_user', 'True')), |
||||
|
} |
||||
|
|
||||
|
def set_auth_admin_passkey_send_to_user(self, cr, uid, ids, context=None): |
||||
|
config = self.browse(cr, uid, ids[0], context=context) |
||||
|
icp = self.pool['ir.config_parameter'] |
||||
|
icp.set_param( |
||||
|
cr, uid, 'auth_admin_passkey.send_to_user', |
||||
|
repr(config.auth_admin_passkey_send_to_user)) |
||||
|
|
||||
|
# Columns Section |
||||
|
_columns = { |
||||
|
'auth_admin_passkey_send_to_admin': fields.boolean( |
||||
|
'Send email to admin user.', |
||||
|
help="""When the administrator use his password to login in """ |
||||
|
"""with a different account, OpenERP will send an email """ |
||||
|
"""to the admin user.""", |
||||
|
), |
||||
|
'auth_admin_passkey_send_to_user': fields.boolean( |
||||
|
string='Send email to user.', |
||||
|
help="""When the administrator use his password to login in """ |
||||
|
"""with a different account, OpenERP will send an email """ |
||||
|
"""to the account user.""", |
||||
|
), |
||||
|
} |
@ -0,0 +1,137 @@ |
|||||
|
# -*- encoding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Admin Passkey module for OpenERP |
||||
|
# Copyright (C) 2013-2014 GRAP (http://www.grap.coop) |
||||
|
# @author Sylvain LE GAL (https://twitter.com/legalsylvain) |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
import datetime |
||||
|
|
||||
|
from openerp import SUPERUSER_ID |
||||
|
from openerp import pooler |
||||
|
from openerp import exceptions |
||||
|
from openerp.osv.orm import Model |
||||
|
from openerp.tools.translate import _ |
||||
|
from openerp.tools.safe_eval import safe_eval |
||||
|
|
||||
|
|
||||
|
class res_users(Model): |
||||
|
_inherit = "res.users" |
||||
|
|
||||
|
# Private Function section |
||||
|
def _get_translation(self, cr, lang, text): |
||||
|
context = {'lang': lang} # noqa: _() checks page for locals |
||||
|
return _(text) |
||||
|
|
||||
|
def _send_email_passkey(self, cr, user_id, user_agent_env): |
||||
|
""" Send a email to the admin of the system and / or the user |
||||
|
to inform passkey use.""" |
||||
|
mails = [] |
||||
|
mail_obj = self.pool['mail.mail'] |
||||
|
icp_obj = self.pool['ir.config_parameter'] |
||||
|
admin_user = self.browse(cr, SUPERUSER_ID, SUPERUSER_ID) |
||||
|
login_user = self.browse(cr, SUPERUSER_ID, user_id) |
||||
|
send_to_admin = safe_eval(icp_obj.get_param( |
||||
|
cr, SUPERUSER_ID, 'auth_admin_passkey.send_to_admin', 'True')) |
||||
|
send_to_user = safe_eval(icp_obj.get_param( |
||||
|
cr, SUPERUSER_ID, 'auth_admin_passkey.send_to_user', 'True')) |
||||
|
|
||||
|
if send_to_admin and admin_user.email: |
||||
|
mails.append({'email': admin_user.email, 'lang': admin_user.lang}) |
||||
|
if send_to_user and login_user.email: |
||||
|
mails.append({'email': login_user.email, 'lang': login_user.lang}) |
||||
|
|
||||
|
for mail in mails: |
||||
|
subject = self._get_translation( |
||||
|
cr, mail['lang'], _('Passkey used')) |
||||
|
body = self._get_translation( |
||||
|
cr, mail['lang'], |
||||
|
_("""Admin user used his passkey to login with '%s'.\n\n""" |
||||
|
"""\n\nTechnicals informations belows : \n\n""" |
||||
|
"""- Login date : %s\n\n""")) % ( |
||||
|
login_user.login, |
||||
|
datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")) |
||||
|
for k, v in user_agent_env.iteritems(): |
||||
|
body += ("- %s : %s\n\n") % (k, v) |
||||
|
mail_obj.create( |
||||
|
cr, SUPERUSER_ID, { |
||||
|
'email_to': mail['email'], |
||||
|
'subject': subject, |
||||
|
'body_html': '<pre>%s</pre>' % body}) |
||||
|
|
||||
|
def _send_email_same_password(self, cr, login_user): |
||||
|
""" Send a email to the admin user to inform that another user has the |
||||
|
same password as him.""" |
||||
|
mail_obj = self.pool['mail.mail'] |
||||
|
admin_user = self.browse(cr, SUPERUSER_ID, SUPERUSER_ID) |
||||
|
if admin_user.email: |
||||
|
mail_obj.create(cr, SUPERUSER_ID, { |
||||
|
'email_to': admin_user.email, |
||||
|
'subject': self._get_translation( |
||||
|
cr, admin_user.lang, _('[WARNING] OpenERP Security Risk')), |
||||
|
'body_html': self._get_translation( |
||||
|
cr, admin_user.lang, _( |
||||
|
"""<pre>User with login '%s' has the same """ |
||||
|
"""password as you.</pre>""")) % (login_user), |
||||
|
}) |
||||
|
|
||||
|
# Overload Section |
||||
|
def authenticate(self, db, login, password, user_agent_env): |
||||
|
""" Authenticate the user 'login' is password is ok or if |
||||
|
is admin password. In the second case, send mail to user and admin.""" |
||||
|
user_id = super(res_users, self).authenticate( |
||||
|
db, login, password, user_agent_env) |
||||
|
if user_id and (user_id != SUPERUSER_ID): |
||||
|
same_password = False |
||||
|
cr = pooler.get_db(db).cursor() |
||||
|
try: |
||||
|
# directly use parent 'check_credentials' function |
||||
|
# to really know if credentials are ok |
||||
|
# or if it was admin password |
||||
|
super(res_users, self).check_credentials( |
||||
|
cr, SUPERUSER_ID, password) |
||||
|
try: |
||||
|
# Test now if the user has the same password as admin user |
||||
|
super(res_users, self).check_credentials( |
||||
|
cr, user_id, password) |
||||
|
same_password = True |
||||
|
except exceptions.AccessDenied: |
||||
|
pass |
||||
|
if not same_password: |
||||
|
self._send_email_passkey(cr, user_id, user_agent_env) |
||||
|
else: |
||||
|
self._send_email_same_password(cr, login) |
||||
|
cr.commit() |
||||
|
except exceptions.AccessDenied: |
||||
|
pass |
||||
|
finally: |
||||
|
cr.close() |
||||
|
return user_id |
||||
|
|
||||
|
def check_credentials(self, cr, uid, password): |
||||
|
""" Return now True if credentials are good OR if password is admin |
||||
|
password.""" |
||||
|
if uid != SUPERUSER_ID: |
||||
|
try: |
||||
|
super(res_users, self).check_credentials( |
||||
|
cr, uid, password) |
||||
|
return True |
||||
|
except exceptions.AccessDenied: |
||||
|
return self.check_credentials(cr, SUPERUSER_ID, password) |
||||
|
else: |
||||
|
return super(res_users, self).check_credentials(cr, uid, password) |
After Width: 128 | Height: 128 | Size: 4.0 KiB |
@ -0,0 +1,23 @@ |
|||||
|
# -*- encoding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Admin Passkey module for OpenERP |
||||
|
# Copyright (C) 2013-2014 GRAP (http://www.grap.coop) |
||||
|
# @author Sylvain LE GAL (https://twitter.com/legalsylvain) |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
from . import test_auth_admin_passkey |
@ -0,0 +1,99 @@ |
|||||
|
# -*- encoding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Admin Passkey module for OpenERP |
||||
|
# Copyright (C) 2013-2014 GRAP (http://www.grap.coop) |
||||
|
# @author Sylvain LE GAL (https://twitter.com/legalsylvain) |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
import threading |
||||
|
|
||||
|
from openerp.tests.common import TransactionCase |
||||
|
|
||||
|
|
||||
|
class TestAuthAdminPasskey(TransactionCase): |
||||
|
"""Tests for 'Auth Admin Passkey' Module""" |
||||
|
|
||||
|
# Overload Section |
||||
|
def setUp(self): |
||||
|
super(TestAuthAdminPasskey, self).setUp() |
||||
|
|
||||
|
# Get Registries |
||||
|
self.imd_obj = self.registry('ir.model.data') |
||||
|
self.ru_obj = self.registry('res.users') |
||||
|
|
||||
|
# Get Database name |
||||
|
self.db = threading.current_thread().dbname |
||||
|
|
||||
|
# Get ids from xml_ids |
||||
|
self.admin_user_id = self.imd_obj.get_object_reference( |
||||
|
self.cr, self.uid, 'base', 'user_root')[1] |
||||
|
self.demo_user_id = self.imd_obj.get_object_reference( |
||||
|
self.cr, self.uid, 'base', 'user_demo')[1] |
||||
|
|
||||
|
# Test Section |
||||
|
def test_01_normal_login_admin_succeed(self): |
||||
|
"""[Regression Test] |
||||
|
Test the succeed of login with 'admin' / 'admin'""" |
||||
|
res = self.ru_obj.authenticate(self.db, 'admin', 'admin', {}) |
||||
|
self.assertEqual( |
||||
|
res, self.admin_user_id, |
||||
|
"'admin' / 'admin' login must succeed.") |
||||
|
|
||||
|
def test_02_normal_login_admin_fail(self): |
||||
|
"""[Regression Test] |
||||
|
Test the fail of login with 'admin' / 'bad_password'""" |
||||
|
res = self.ru_obj.authenticate(self.db, 'admin', 'bad_password', {}) |
||||
|
self.assertEqual( |
||||
|
res, False, |
||||
|
"'admin' / 'bad_password' login must fail.") |
||||
|
|
||||
|
def test_03_normal_login_demo_succeed(self): |
||||
|
"""[Regression Test] |
||||
|
Test the succeed of login with 'demo' / 'demo'""" |
||||
|
res = self.ru_obj.authenticate(self.db, 'demo', 'demo', {}) |
||||
|
self.assertEqual( |
||||
|
res, self.demo_user_id, |
||||
|
"'demo' / 'demo' login must succeed.") |
||||
|
|
||||
|
def test_04_normal_login_demo_fail(self): |
||||
|
"""[Regression Test] |
||||
|
Test the fail of login with 'demo' / 'bad_password'""" |
||||
|
res = self.ru_obj.authenticate(self.db, 'demo', 'bad_password', {}) |
||||
|
self.assertEqual( |
||||
|
res, False, |
||||
|
"'demo' / 'bad_password' login must fail.") |
||||
|
|
||||
|
def test_05_passkey_login_demo_succeed(self): |
||||
|
"""[New Feature] |
||||
|
Test the succeed of login with 'demo' / 'admin'""" |
||||
|
res = self.ru_obj.authenticate(self.db, 'demo', 'admin', {}) |
||||
|
self.assertEqual( |
||||
|
res, self.demo_user_id, |
||||
|
"'demo' / 'admin' login must succeed.") |
||||
|
|
||||
|
def test_06_passkey_login_demo_succeed(self): |
||||
|
"""[Bug #1319391] |
||||
|
Test the correct behaviour of login with 'bad_login' / 'admin'""" |
||||
|
exception_raised = False |
||||
|
try: |
||||
|
self.ru_obj.authenticate(self.db, 'bad_login', 'admin', {}) |
||||
|
except: |
||||
|
exception_raised = True |
||||
|
self.assertEqual( |
||||
|
exception_raised, False, |
||||
|
"'bad_login' / 'admin' musn't raise Error.") |
@ -0,0 +1,47 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<!-- ********************************************************************** --> |
||||
|
<!--Admin Passkey module for OpenERP --> |
||||
|
<!--Copyright (C) 2013-2014 GRAP (http://www.grap.coop) --> |
||||
|
<!--@author Sylvain LE GAL (https://twitter.com/legalsylvain) --> |
||||
|
|
||||
|
<!--This program is free software: you can redistribute it and/or modify --> |
||||
|
<!--it under the terms of the GNU Affero General Public License as --> |
||||
|
<!--published by the Free Software Foundation, either version 3 of the --> |
||||
|
<!--License, or (at your option) any later version. --> |
||||
|
|
||||
|
<!--This program is distributed in the hope that it will be useful, --> |
||||
|
<!--but WITHOUT ANY WARRANTY; without even the implied warranty of --> |
||||
|
<!--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --> |
||||
|
<!--GNU Affero General Public License for more details. --> |
||||
|
|
||||
|
<!--You should have received a copy of the GNU Affero General Public License--> |
||||
|
<!--along with this program. If not, see <http://www.gnu.org/licenses/>. --> |
||||
|
<!-- ********************************************************************** --> |
||||
|
<openerp> |
||||
|
<data> |
||||
|
|
||||
|
<record id="view_res_config_settings" model="ir.ui.view"> |
||||
|
<field name="name">base.config.settings.view</field> |
||||
|
<field name="model">base.config.settings</field> |
||||
|
<field name="inherit_id" ref="base_setup.view_general_configuration"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<xpath expr="//label[@string='Email']/.." position='after'> |
||||
|
<group> |
||||
|
<label for="id" string="Passkey"/> |
||||
|
<div> |
||||
|
<div> |
||||
|
<field name="auth_admin_passkey_send_to_admin" class="oe_inline"/> |
||||
|
<label for="auth_admin_passkey_send_to_admin"/> |
||||
|
</div> |
||||
|
<div> |
||||
|
<field name="auth_admin_passkey_send_to_user" class="oe_inline"/> |
||||
|
<label for="auth_admin_passkey_send_to_user"/> |
||||
|
</div> |
||||
|
</div> |
||||
|
</group> |
||||
|
</xpath> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
</data> |
||||
|
</openerp> |
@ -0,0 +1,56 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# OpenERP, Open Source Management Solution |
||||
|
# This module copyright (C) 2014 Therp BV (<http://therp.nl>). |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
from openerp.addons.web.http import WebRequest, JsonRequest |
||||
|
from openerp.addons.web.controllers import main as web_main |
||||
|
|
||||
|
old_init = WebRequest.init |
||||
|
|
||||
|
|
||||
|
def init(self, params): |
||||
|
old_init(self, params) |
||||
|
if self.httprequest.authorization and not self.session._login: |
||||
|
dbs = web_main.db_list(self) |
||||
|
self.session.authenticate( |
||||
|
dbs and dbs[0], |
||||
|
self.httprequest.authorization.username, |
||||
|
self.httprequest.authorization.password, |
||||
|
dict( |
||||
|
base_location=self.httprequest.url_root.rstrip('/'), |
||||
|
HTTP_HOST=self.httprequest.environ['HTTP_HOST'], |
||||
|
REMOTE_ADDR=self.httprequest.environ['REMOTE_ADDR'] |
||||
|
) |
||||
|
) |
||||
|
|
||||
|
WebRequest.init = init |
||||
|
|
||||
|
old_dispatch = JsonRequest.dispatch |
||||
|
|
||||
|
|
||||
|
def dispatch(self, method): |
||||
|
response = old_dispatch(self, method) |
||||
|
if method.im_func == web_main.Session.destroy.im_func: |
||||
|
response.status = '301 logout' |
||||
|
response.headers.add( |
||||
|
'Location', |
||||
|
self.httprequest.url.replace('://', '://logout@')) |
||||
|
return response |
||||
|
|
||||
|
JsonRequest.dispatch = dispatch |
@ -0,0 +1,62 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# OpenERP, Open Source Management Solution |
||||
|
# This module copyright (C) 2014 Therp BV (<http://therp.nl>). |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
{ |
||||
|
"name": "Authenticate via HTTP basic authentication", |
||||
|
"version": "1.0", |
||||
|
"author": "Therp BV", |
||||
|
"complexity": "expert", |
||||
|
"description": """ |
||||
|
In an environment where several web applications authenticate against the same |
||||
|
source, the simplest way to attain single sign on would be to have the |
||||
|
webserver handle authentication and pass the login information via HTTP headers |
||||
|
to the application it proxies. |
||||
|
|
||||
|
This addon allows for this setup. Technically, it picks up the HTTP |
||||
|
Authorization header, extracts a username and a password and tries to login |
||||
|
into the first database found in the database list. |
||||
|
|
||||
|
If you have to set a specific database, possibly depending on the login |
||||
|
provided, use the addon dbfilter_from_header. |
||||
|
|
||||
|
The addon has to be loaded as server-wide module. |
||||
|
|
||||
|
|
||||
|
Funders: |
||||
|
|
||||
|
Open2bizz software & consultancy |
||||
|
""", |
||||
|
"category": "", |
||||
|
"depends": [ |
||||
|
], |
||||
|
"data": [ |
||||
|
], |
||||
|
"js": [ |
||||
|
], |
||||
|
"css": [ |
||||
|
], |
||||
|
"qweb": [ |
||||
|
], |
||||
|
"auto_install": False, |
||||
|
"installable": True, |
||||
|
"external_dependencies": { |
||||
|
'python': [], |
||||
|
}, |
||||
|
} |
@ -0,0 +1,20 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# OpenERP, Open Source Management Solution |
||||
|
# This module copyright (C) 2014 Therp BV (<http://therp.nl>). |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
@ -0,0 +1,57 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# OpenERP, Open Source Management Solution |
||||
|
# This module copyright (C) 2014 Therp BV (<http://therp.nl>). |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
{ |
||||
|
"name": "Authenticate via HTTP basic authentication (logout helper)", |
||||
|
"version": "1.0", |
||||
|
"author": "Therp BV", |
||||
|
"complexity": "expert", |
||||
|
"description": """ |
||||
|
With auth_from_http_basic, the logout procedure has to be bent a bit to provide |
||||
|
a good user experience. As the former has to be a server wide module, this is |
||||
|
the clientside complement which provides the javascript part. |
||||
|
|
||||
|
The addon has to be installed in the database in use. |
||||
|
|
||||
|
|
||||
|
Funders: |
||||
|
|
||||
|
Open2bizz software & consultancy |
||||
|
""", |
||||
|
"category": "", |
||||
|
"depends": [ |
||||
|
'web', |
||||
|
'auth_from_http_basic', |
||||
|
], |
||||
|
"data": [ |
||||
|
], |
||||
|
"js": [ |
||||
|
'static/src/js/auth_from_http_basic_logout.js', |
||||
|
], |
||||
|
"css": [ |
||||
|
], |
||||
|
"qweb": [ |
||||
|
], |
||||
|
"auto_install": False, |
||||
|
"installable": True, |
||||
|
"external_dependencies": { |
||||
|
'python': [], |
||||
|
}, |
||||
|
} |
@ -0,0 +1,23 @@ |
|||||
|
# Translation of OpenERP Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: OpenERP Server 7.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2014-01-18 16:31+0000\n" |
||||
|
"PO-Revision-Date: 2014-01-18 16:31+0000\n" |
||||
|
"Last-Translator: <>\n" |
||||
|
"Language-Team: \n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Plural-Forms: \n" |
||||
|
|
||||
|
#. module: auth_from_http_basic_logout |
||||
|
#. openerp-web |
||||
|
#: code:addons/auth_from_http_basic_logout/static/src/js/auth_from_http_basic_logout.js:37 |
||||
|
#, python-format |
||||
|
msgid "<p style=\"background: white\">You have been logged out successfully. <a href=\"#\">Click here to log in again.</a></p>" |
||||
|
msgstr "" |
||||
|
|
@ -0,0 +1,27 @@ |
|||||
|
# Translation of OpenERP Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: OpenERP Server 7.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2014-01-18 16:31+0000\n" |
||||
|
"PO-Revision-Date: 2014-04-03 05:38+0000\n" |
||||
|
"Last-Translator: Holger Brunn (Therp) <hbrunn@therp.nl>\n" |
||||
|
"Language-Team: \n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: 8bit\n" |
||||
|
"X-Launchpad-Export-Date: 2014-05-24 06:46+0000\n" |
||||
|
"X-Generator: Launchpad (build 17017)\n" |
||||
|
|
||||
|
#. module: auth_from_http_basic_logout |
||||
|
#. openerp-web |
||||
|
#: code:addons/auth_from_http_basic_logout/static/src/js/auth_from_http_basic_logout.js:37 |
||||
|
#, python-format |
||||
|
msgid "" |
||||
|
"<p style=\"background: white\">You have been logged out successfully. <a " |
||||
|
"href=\"#\">Click here to log in again.</a></p>" |
||||
|
msgstr "" |
||||
|
"<p style=\"background: white\">U bent afgemeld. <a href=\"#\">Klik hier om " |
||||
|
"weer in te loggen.</a></p>" |
After Width: 80 | Height: 80 | Size: 7.8 KiB |
@ -0,0 +1,48 @@ |
|||||
|
//-*- coding: utf-8 -*-
|
||||
|
//############################################################################
|
||||
|
//
|
||||
|
// OpenERP, Open Source Management Solution
|
||||
|
// This module copyright (C) 2014 Therp BV (<http://therp.nl>).
|
||||
|
//
|
||||
|
// This program is free software: you can redistribute it and/or modify
|
||||
|
// it under the terms of the GNU Affero General Public License as
|
||||
|
// published by the Free Software Foundation, either version 3 of the
|
||||
|
// License, or (at your option) any later version.
|
||||
|
//
|
||||
|
// This program is distributed in the hope that it will be useful,
|
||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
|
// GNU Affero General Public License for more details.
|
||||
|
//
|
||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
//
|
||||
|
//############################################################################
|
||||
|
|
||||
|
openerp.auth_from_http_basic_logout = function(openerp) |
||||
|
{ |
||||
|
openerp.web.Session.include({ |
||||
|
session_logout: function() |
||||
|
{ |
||||
|
var deferred = this._super(this, arguments); |
||||
|
deferred.fail(function(error, ev) |
||||
|
{ |
||||
|
ev.preventDefault(); |
||||
|
openerp.web.blockUI(); |
||||
|
jQuery('.openerp_webclient_container').remove(); |
||||
|
jQuery('.oe_blockui_spin_container') |
||||
|
.empty() |
||||
|
.html( |
||||
|
_.string.sprintf( |
||||
|
openerp.web._t( |
||||
|
'<p style="background: white">You have been logged out successfully. <a href="#">Click here to log in again.</a></p>') |
||||
|
)) |
||||
|
.click(function() |
||||
|
{ |
||||
|
window.location.reload(); |
||||
|
}); |
||||
|
}); |
||||
|
return deferred; |
||||
|
} |
||||
|
}); |
||||
|
} |
@ -0,0 +1,24 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Daniel Reis |
||||
|
# 2011 |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
from . import base_external_dbsource |
||||
|
|
||||
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
@ -0,0 +1,66 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Daniel Reis, 2011 |
||||
|
# Additional contributions by Maxime Chambreuil, Savoir-faire Linux |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
{ |
||||
|
'name': 'External Database Sources', |
||||
|
'version': '1.3', |
||||
|
'category': 'Tools', |
||||
|
'description': """ |
||||
|
This module allows you to define connections to foreign databases using ODBC, |
||||
|
Oracle Client or SQLAlchemy. |
||||
|
|
||||
|
Database sources can be configured in Settings > Configuration -> Data sources. |
||||
|
|
||||
|
Depending on the database, you need: |
||||
|
* to install unixodbc and python-pyodbc packages to use ODBC connections. |
||||
|
* to install FreeTDS driver (tdsodbc package) and configure it through ODBC to |
||||
|
connect to Microsoft SQL Server. |
||||
|
* to install and configure Oracle Instant Client and cx_Oracle python library |
||||
|
to connect to Oracle. |
||||
|
|
||||
|
Contributors |
||||
|
============ |
||||
|
|
||||
|
* Maxime Chambreuil <maxime.chambreuil@savoirfairelinux.com> |
||||
|
""", |
||||
|
'author': 'Daniel Reis', |
||||
|
'website': 'http://launchpad.net/addons-tko', |
||||
|
'images': [ |
||||
|
'images/screenshot01.png', |
||||
|
], |
||||
|
'depends': [ |
||||
|
'base', |
||||
|
], |
||||
|
'data': [ |
||||
|
'base_external_dbsource_view.xml', |
||||
|
'security/ir.model.access.csv', |
||||
|
], |
||||
|
'demo': [ |
||||
|
'base_external_dbsource_demo.xml', |
||||
|
], |
||||
|
'test': [ |
||||
|
'test/dbsource_connect.yml', |
||||
|
], |
||||
|
'installable': False, |
||||
|
'active': False, |
||||
|
} |
||||
|
|
||||
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
@ -0,0 +1,175 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Daniel Reis |
||||
|
# 2011 |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
import os |
||||
|
import logging |
||||
|
from openerp.osv import orm, fields |
||||
|
from openerp.tools.translate import _ |
||||
|
import openerp.tools as tools |
||||
|
_logger = logging.getLogger(__name__) |
||||
|
|
||||
|
CONNECTORS = [] |
||||
|
|
||||
|
try: |
||||
|
import sqlalchemy |
||||
|
CONNECTORS.append(('sqlite', 'SQLite')) |
||||
|
try: |
||||
|
import pymssql |
||||
|
CONNECTORS.append(('mssql', 'Microsoft SQL Server')) |
||||
|
assert pymssql |
||||
|
except (ImportError, AssertionError): |
||||
|
_logger.info('MS SQL Server not available. Please install "pymssql"\ |
||||
|
python package.') |
||||
|
try: |
||||
|
import MySQLdb |
||||
|
CONNECTORS.append(('mysql', 'MySQL')) |
||||
|
assert MySQLdb |
||||
|
except (ImportError, AssertionError): |
||||
|
_logger.info('MySQL not available. Please install "mysqldb"\ |
||||
|
python package.') |
||||
|
except: |
||||
|
_logger.info('SQL Alchemy not available. Please install "slqalchemy"\ |
||||
|
python package.') |
||||
|
try: |
||||
|
import pyodbc |
||||
|
CONNECTORS.append(('pyodbc', 'ODBC')) |
||||
|
except: |
||||
|
_logger.info('ODBC libraries not available. Please install "unixodbc"\ |
||||
|
and "python-pyodbc" packages.') |
||||
|
|
||||
|
try: |
||||
|
import cx_Oracle |
||||
|
CONNECTORS.append(('cx_Oracle', 'Oracle')) |
||||
|
except: |
||||
|
_logger.info('Oracle libraries not available. Please install "cx_Oracle"\ |
||||
|
python package.') |
||||
|
|
||||
|
import psycopg2 |
||||
|
CONNECTORS.append(('postgresql', 'PostgreSQL')) |
||||
|
|
||||
|
|
||||
|
class base_external_dbsource(orm.Model): |
||||
|
_name = "base.external.dbsource" |
||||
|
_description = 'External Database Sources' |
||||
|
_columns = { |
||||
|
'name': fields.char('Datasource name', required=True, size=64), |
||||
|
'conn_string': fields.text('Connection string', help=""" |
||||
|
Sample connection strings: |
||||
|
- Microsoft SQL Server: |
||||
|
mssql+pymssql://username:%s@server:port/dbname?charset=utf8 |
||||
|
- MySQL: mysql://user:%s@server:port/dbname |
||||
|
- ODBC: DRIVER={FreeTDS};SERVER=server.address;Database=mydb;UID=sa |
||||
|
- ORACLE: username/%s@//server.address:port/instance |
||||
|
- PostgreSQL: |
||||
|
dbname='template1' user='dbuser' host='localhost' port='5432' password=%s |
||||
|
- SQLite: sqlite:///test.db |
||||
|
"""), |
||||
|
'password': fields.char('Password', size=40), |
||||
|
'connector': fields.selection(CONNECTORS, 'Connector', |
||||
|
required=True, |
||||
|
help="If a connector is missing from the\ |
||||
|
list, check the server log to confirm\ |
||||
|
that the required components were\ |
||||
|
detected."), |
||||
|
} |
||||
|
|
||||
|
def conn_open(self, cr, uid, id1): |
||||
|
# Get dbsource record |
||||
|
data = self.browse(cr, uid, id1) |
||||
|
# Build the full connection string |
||||
|
connStr = data.conn_string |
||||
|
if data.password: |
||||
|
if '%s' not in data.conn_string: |
||||
|
connStr += ';PWD=%s' |
||||
|
connStr = connStr % data.password |
||||
|
# Try to connect |
||||
|
if data.connector == 'cx_Oracle': |
||||
|
os.environ['NLS_LANG'] = 'AMERICAN_AMERICA.UTF8' |
||||
|
conn = cx_Oracle.connect(connStr) |
||||
|
elif data.connector == 'pyodbc': |
||||
|
conn = pyodbc.connect(connStr) |
||||
|
elif data.connector in ('sqlite', 'mysql', 'mssql'): |
||||
|
conn = sqlalchemy.create_engine(connStr).connect() |
||||
|
elif data.connector == 'postgresql': |
||||
|
conn = psycopg2.connect(connStr) |
||||
|
|
||||
|
return conn |
||||
|
|
||||
|
def execute(self, cr, uid, ids, sqlquery, sqlparams=None, metadata=False, |
||||
|
context=None): |
||||
|
"""Executes SQL and returns a list of rows. |
||||
|
|
||||
|
"sqlparams" can be a dict of values, that can be referenced in |
||||
|
the SQL statement using "%(key)s" or, in the case of Oracle, |
||||
|
":key". |
||||
|
Example: |
||||
|
sqlquery = "select * from mytable where city = %(city)s and |
||||
|
date > %(dt)s" |
||||
|
params = {'city': 'Lisbon', |
||||
|
'dt': datetime.datetime(2000, 12, 31)} |
||||
|
|
||||
|
If metadata=True, it will instead return a dict containing the |
||||
|
rows list and the columns list, in the format: |
||||
|
{ 'cols': [ 'col_a', 'col_b', ...] |
||||
|
, 'rows': [ (a0, b0, ...), (a1, b1, ...), ...] } |
||||
|
""" |
||||
|
data = self.browse(cr, uid, ids) |
||||
|
rows, cols = list(), list() |
||||
|
for obj in data: |
||||
|
conn = self.conn_open(cr, uid, obj.id) |
||||
|
if obj.connector in ["sqlite", "mysql", "mssql"]: |
||||
|
# using sqlalchemy |
||||
|
cur = conn.execute(sqlquery, sqlparams) |
||||
|
if metadata: |
||||
|
cols = cur.keys() |
||||
|
rows = [r for r in cur] |
||||
|
else: |
||||
|
# using other db connectors |
||||
|
cur = conn.cursor() |
||||
|
cur.execute(sqlquery, sqlparams) |
||||
|
if metadata: |
||||
|
cols = [d[0] for d in cur.description] |
||||
|
rows = cur.fetchall() |
||||
|
conn.close() |
||||
|
if metadata: |
||||
|
return{'cols': cols, 'rows': rows} |
||||
|
else: |
||||
|
return rows |
||||
|
|
||||
|
def connection_test(self, cr, uid, ids, context=None): |
||||
|
for obj in self.browse(cr, uid, ids, context): |
||||
|
conn = False |
||||
|
try: |
||||
|
conn = self.conn_open(cr, uid, obj.id) |
||||
|
except Exception as e: |
||||
|
raise orm.except_orm(_("Connection test failed!"), |
||||
|
_("Here is what we got instead:\n %s") |
||||
|
% tools.ustr(e)) |
||||
|
finally: |
||||
|
try: |
||||
|
if conn: |
||||
|
conn.close() |
||||
|
except Exception: |
||||
|
# ignored, just a consequence of the previous exception |
||||
|
pass |
||||
|
# TODO: if OK a (wizard) message box should be displayed |
||||
|
raise orm.except_orm(_("Connection test succeeded!"), |
||||
|
_("Everything seems properly set up!")) |
@ -0,0 +1,15 @@ |
|||||
|
<?xml version="1.0"?> |
||||
|
<openerp> |
||||
|
<data> |
||||
|
|
||||
|
<record model="base.external.dbsource" id="demo_postgre"> |
||||
|
<field name="name">PostgreSQL local</field> |
||||
|
<field name="conn_string">dbname='postgres' password=%s</field> |
||||
|
<field name="password">postgresql</field> |
||||
|
<field name="connector">postgresql</field> |
||||
|
</record> |
||||
|
|
||||
|
</data> |
||||
|
</openerp> |
||||
|
|
||||
|
|
@ -0,0 +1,54 @@ |
|||||
|
<?xml version="1.0"?> |
||||
|
<openerp> |
||||
|
<data> |
||||
|
|
||||
|
<!-- DBSource --> |
||||
|
|
||||
|
<record model="ir.ui.view" id="view_dbsource_tree"> |
||||
|
<field name="name">base.external.dbsource.tree</field> |
||||
|
<field name="model">base.external.dbsource</field> |
||||
|
<field name="type">tree</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<tree string="External DB Sources"> |
||||
|
<field name="name"/> |
||||
|
<field name="connector"/> |
||||
|
<field name="conn_string"/> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record model="ir.ui.view" id="view_dbsource_form"> |
||||
|
<field name="name">base.external.dbsource.form</field> |
||||
|
<field name="model">base.external.dbsource</field> |
||||
|
<field name="type">form</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<form string="External DB Source"> |
||||
|
<field name="name"/> |
||||
|
<field name="password" password="True"/> |
||||
|
<newline/> |
||||
|
<field name="connector" colspan="2"/> |
||||
|
<newline/> |
||||
|
<field name="conn_string" colspan="4"/> |
||||
|
<newline/> |
||||
|
<button name="connection_test" string="Test Connection" type="object" icon="gtk-network" colspan="4"/> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record model="ir.actions.act_window" id="action_dbsource"> |
||||
|
<field name="name">External Database Sources</field> |
||||
|
<field name="res_model">base.external.dbsource</field> |
||||
|
<field name="view_type">form</field> |
||||
|
<field name="view_mode">tree,form</field> |
||||
|
<field name="view_id" ref="view_dbsource_tree"/> |
||||
|
</record> |
||||
|
|
||||
|
<menuitem name="Database Sources" |
||||
|
id="menu_dbsource" |
||||
|
parent="base.next_id_9" |
||||
|
action="action_dbsource"/> |
||||
|
|
||||
|
</data> |
||||
|
</openerp> |
||||
|
|
||||
|
|
After Width: 960 | Height: 281 | Size: 31 KiB |
@ -0,0 +1,2 @@ |
|||||
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink |
||||
|
access_base_external_dbsource_group_system,bae_external_dbsource_group_system,model_base_external_dbsource,base.group_system,1,1,1,1 |
@ -0,0 +1,9 @@ |
|||||
|
- |
||||
|
Connect to local Postgres. |
||||
|
- |
||||
|
!python {model: base.external.dbsource}: | |
||||
|
from openerp.osv.orm import except_orm |
||||
|
try: |
||||
|
self.connection_test(cr, uid, [ref("demo_postgre")]) |
||||
|
except except_orm as e: |
||||
|
assert e.value == u'Everything seems properly set up!' |
@ -0,0 +1,22 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Author: David BEAL |
||||
|
# Copyright 2014 Akretion |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
from . import config # noqa |
@ -0,0 +1,82 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Author: David BEAL |
||||
|
# Copyright 2014 Akretion |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
{ |
||||
|
'name': 'Configuration Helper', |
||||
|
'version': '0.8', |
||||
|
'author': 'Akretion', |
||||
|
'maintainer': 'Akretion', |
||||
|
'category': 'server', |
||||
|
'complexity': 'normal', |
||||
|
'depends': ['base'], |
||||
|
'description': """ |
||||
|
Configuration Helper |
||||
|
==================== |
||||
|
|
||||
|
*This module is intended for developer only. It does nothing used alone.* |
||||
|
|
||||
|
This module : |
||||
|
|
||||
|
* create automatically related fields in 'whatiwant.config.settings' |
||||
|
using those defined in 'res.company' : it avoid duplicated field definitions. |
||||
|
* company_id field with default value is created |
||||
|
* onchange_company_id is defined to update all related fields |
||||
|
* supported fields: char, text, integer, float, datetime, date, boolean, m2o |
||||
|
|
||||
|
|
||||
|
How to use |
||||
|
---------- |
||||
|
|
||||
|
.. code-block:: python |
||||
|
|
||||
|
from . company import ResCompany |
||||
|
|
||||
|
class WhatiwantClassSettings(orm.TransientModel): |
||||
|
_inherit = ['res.config.settings', 'abstract.config.settings'] |
||||
|
_name = 'whatiwant.config.settings' |
||||
|
# fields must be defined in ResCompany class |
||||
|
# related fields are automatically generated from previous definitions |
||||
|
_companyObject = ResCompany |
||||
|
|
||||
|
|
||||
|
Roadmap |
||||
|
------- |
||||
|
* support (or check support) for these field types : o2m, m2m, reference, property, selection |
||||
|
* automatically generate a default view for 'whatiwant.config.settings' (in --debug ?) |
||||
|
|
||||
|
|
||||
|
Contributors |
||||
|
------------ |
||||
|
|
||||
|
* David BEAL <david.beal@akretion.com> |
||||
|
* Sébastien BEAU <sebastien.beau@akretion.com> |
||||
|
* Yannick Vaucher, Camptocamp, (code refactoring from his module 'delivery_carrier_label_postlogistics') |
||||
|
|
||||
|
""", |
||||
|
'website': 'http://www.akretion.com/', |
||||
|
'data': [ |
||||
|
], |
||||
|
'tests': [], |
||||
|
'installable': False, |
||||
|
'auto_install': False, |
||||
|
'license': 'AGPL-3', |
||||
|
'application': True, |
||||
|
} |
@ -0,0 +1,114 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Author: David BEAL, Copyright 2014 Akretion |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
import re |
||||
|
|
||||
|
from openerp.osv import orm, fields |
||||
|
|
||||
|
|
||||
|
class AbstractConfigSettings(orm.AbstractModel): |
||||
|
_name = 'abstract.config.settings' |
||||
|
_description = 'Abstract configuration settings' |
||||
|
# prefix field name to differentiate fields in company with those in config |
||||
|
_prefix = 'setting_' |
||||
|
# this is the class name to import in your module |
||||
|
# (it should be ResCompany or res_company, depends of your code) |
||||
|
_companyObject = None |
||||
|
|
||||
|
def _filter_field(self, field_key): |
||||
|
"""Inherit in your module to define for which company field |
||||
|
you don't want have a matching related field""" |
||||
|
return True |
||||
|
|
||||
|
def __init__(self, pool, cr): |
||||
|
super(AbstractConfigSettings, self).__init__(pool, cr) |
||||
|
if self._companyObject: |
||||
|
for field_key in self._companyObject._columns: |
||||
|
# allows to exclude some field |
||||
|
if self._filter_field(field_key): |
||||
|
args = ('company_id', field_key) |
||||
|
kwargs = { |
||||
|
'string': self._companyObject._columns[field_key].string, |
||||
|
'help': self._companyObject._columns[field_key].help, |
||||
|
'type': self._companyObject._columns[field_key]._type, |
||||
|
} |
||||
|
if '_obj' in self._companyObject._columns[field_key].__dict__.keys(): |
||||
|
kwargs['relation'] = \ |
||||
|
self._companyObject._columns[field_key]._obj |
||||
|
if '_domain' in \ |
||||
|
self._companyObject._columns[field_key].__dict__.keys(): |
||||
|
kwargs['domain'] = \ |
||||
|
self._companyObject._columns[field_key]._domain |
||||
|
field_key = re.sub('^' + self._prefix, '', field_key) |
||||
|
self._columns[field_key] = \ |
||||
|
fields.related(*args, **kwargs) |
||||
|
|
||||
|
_columns = { |
||||
|
'company_id': fields.many2one( |
||||
|
'res.company', |
||||
|
'Company', |
||||
|
required=True), |
||||
|
} |
||||
|
|
||||
|
def _default_company(self, cr, uid, context=None): |
||||
|
user = self.pool['res.users'].browse(cr, uid, uid, context=context) |
||||
|
return user.company_id.id |
||||
|
|
||||
|
_defaults = { |
||||
|
'company_id': _default_company, |
||||
|
} |
||||
|
|
||||
|
def field_to_populate_as_related(self, cr, uid, field, company_cols, context=None): |
||||
|
"""Only fields which comes from company with the right prefix |
||||
|
must be defined as related""" |
||||
|
if self._prefix + field in company_cols: |
||||
|
return True |
||||
|
return False |
||||
|
|
||||
|
def onchange_company_id(self, cr, uid, ids, company_id, context=None): |
||||
|
" update related fields " |
||||
|
values = {} |
||||
|
values['currency_id'] = False |
||||
|
if not company_id: |
||||
|
return {'value': values} |
||||
|
company_m = self.pool['res.company'] |
||||
|
company = company_m.browse( |
||||
|
cr, uid, company_id, context=context) |
||||
|
company_cols = company_m._columns.keys() |
||||
|
for field in self._columns: |
||||
|
if self.field_to_populate_as_related( |
||||
|
cr, uid, field, company_cols, context=context): |
||||
|
cpny_field = self._columns[field].arg[-1] |
||||
|
if self._columns[field]._type == 'many2one': |
||||
|
values[field] = company[cpny_field]['id'] or False |
||||
|
else: |
||||
|
values[field] = company[cpny_field] |
||||
|
return {'value': values} |
||||
|
|
||||
|
def create(self, cr, uid, values, context=None): |
||||
|
id = super(AbstractConfigSettings, self).create( |
||||
|
cr, uid, values, context=context) |
||||
|
# Hack: to avoid some nasty bug, related fields are not written |
||||
|
# upon record creation. Hence we write on those fields here. |
||||
|
vals = {} |
||||
|
for fname, field in self._columns.iteritems(): |
||||
|
if isinstance(field, fields.related) and fname in values: |
||||
|
vals[fname] = values[fname] |
||||
|
self.write(cr, uid, [id], vals, context) |
||||
|
return id |
@ -0,0 +1 @@ |
|||||
|
import model |
@ -0,0 +1,105 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# OpenERP, Open Source Management Solution |
||||
|
# This module copyright (C) 2013 Therp BV (<http://therp.nl>). |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
{ |
||||
|
"name": "Templates for email templates", |
||||
|
"version": "1.0", |
||||
|
"author": "Therp BV", |
||||
|
"category": 'Tools', |
||||
|
'complexity': "expert", |
||||
|
"description": """If an organisation's email layout is a bit more |
||||
|
complicated, changes can be tedious when having to do that across several email |
||||
|
templates. So this addon allows to define templates for mails that is referenced |
||||
|
by other mail templates. |
||||
|
This way we can put the layout parts into the template template and only content |
||||
|
in the other templates. Changing the layout is then only a matter of changing |
||||
|
the template template. |
||||
|
|
||||
|
----- |
||||
|
Usage |
||||
|
----- |
||||
|
Create an email template with the related document model 'Email Templates'. Now |
||||
|
most of the fields gray out and you can only edit body_text and body_html. Be |
||||
|
sure to use ${body_text} and ${body_html} respectively in your template |
||||
|
template. |
||||
|
|
||||
|
Then select this newly created template templates in one of your actual |
||||
|
templates. |
||||
|
|
||||
|
For example, create a template template |
||||
|
|
||||
|
:: |
||||
|
|
||||
|
Example Corp logo |
||||
|
Example Corp header |
||||
|
${object.body_text} <- this gets evaluated to the body_text of a template using this template template |
||||
|
Example Corp |
||||
|
Example street 42 |
||||
|
Example city |
||||
|
Example Corp footer |
||||
|
|
||||
|
Then in your template you write |
||||
|
|
||||
|
:: |
||||
|
|
||||
|
Dear ${object.partner_id.name}, |
||||
|
|
||||
|
Your order has been booked on date ${object.date} for a total amount of ${object.sum}. |
||||
|
|
||||
|
And it will be evaluated to |
||||
|
|
||||
|
:: |
||||
|
|
||||
|
Example Corp logo |
||||
|
Example Corp header |
||||
|
Dear Jane Doe, |
||||
|
|
||||
|
Your order has been booked on date 04/17/2013 for a total amount of 42. |
||||
|
Example Corp |
||||
|
Example street 42 |
||||
|
Example city |
||||
|
Example Corp footer |
||||
|
|
||||
|
Given the way evaluation works internally (body_text of the template template |
||||
|
is evaluated two times, first with the instance of email.template of your own |
||||
|
template, then with the object your template refers to), you can do some |
||||
|
trickery if you know that a template template is always used with the same |
||||
|
kind of model (that is, models that have the same field name): |
||||
|
|
||||
|
In your template template: |
||||
|
|
||||
|
:: |
||||
|
|
||||
|
Dear ${'${object.name}'}, <-- gets evaluated to "${object.name}" in the |
||||
|
first step, then to the content of object.name |
||||
|
${object.body_html} |
||||
|
Best, |
||||
|
Example Corp |
||||
|
""", |
||||
|
'website': 'http://therp.nl', |
||||
|
'images': [], |
||||
|
'depends': ['email_template'], |
||||
|
'data': [ |
||||
|
'view/email_template.xml', |
||||
|
], |
||||
|
"license": 'AGPL-3', |
||||
|
'installable': False, |
||||
|
} |
||||
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
@ -0,0 +1,16 @@ |
|||||
|
# Translation of OpenERP Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: OpenERP Server 7.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2014-03-14 17:41+0000\n" |
||||
|
"PO-Revision-Date: 2014-03-14 17:41+0000\n" |
||||
|
"Last-Translator: <>\n" |
||||
|
"Language-Team: \n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Plural-Forms: \n" |
||||
|
|
@ -0,0 +1,21 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# OpenERP, Open Source Management Solution |
||||
|
# This module copyright (C) 2013 Therp BV (<http://therp.nl>). |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
import email_template |
@ -0,0 +1,61 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# OpenERP, Open Source Management Solution |
||||
|
# This module copyright (C) 2013 Therp BV (<http://therp.nl>). |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
from openerp.osv.orm import Model |
||||
|
from openerp.osv import fields |
||||
|
from openerp.addons.email_template.email_template import mako_template_env |
||||
|
|
||||
|
|
||||
|
class email_template(Model): |
||||
|
_inherit = 'email.template' |
||||
|
|
||||
|
def _get_is_template_template(self, cr, uid, ids, fields_name, arg, |
||||
|
context=None): |
||||
|
cr.execute('''select |
||||
|
id, (select count(*) > 0 from email_template e |
||||
|
where email_template_id=email_template.id) |
||||
|
from email_template |
||||
|
where id in %s''', (tuple(ids),)) |
||||
|
return dict(cr.fetchall()) |
||||
|
|
||||
|
_columns = { |
||||
|
'email_template_id': fields.many2one('email.template', 'Template'), |
||||
|
'is_template_template': fields.function( |
||||
|
_get_is_template_template, type='boolean', |
||||
|
string='Is a template template'), |
||||
|
} |
||||
|
|
||||
|
def get_email_template(self, cr, uid, template_id=False, record_id=None, |
||||
|
context=None): |
||||
|
this = super(email_template, self).get_email_template( |
||||
|
cr, uid, template_id, record_id, context) |
||||
|
|
||||
|
if this.email_template_id and not this.is_template_template: |
||||
|
for field in ['body_html']: |
||||
|
if this[field] and this.email_template_id[field]: |
||||
|
try: |
||||
|
mako_template_env.autoescape = False |
||||
|
this._data[this.id][field] = self.render_template( |
||||
|
cr, uid, this.email_template_id[field], |
||||
|
this.email_template_id.model, |
||||
|
this.id, this._context) |
||||
|
finally: |
||||
|
mako_template_env.autoescape = True |
||||
|
return this |
@ -0,0 +1,70 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<openerp> |
||||
|
<data> |
||||
|
<record id="email_template_form" model="ir.ui.view"> |
||||
|
<field name="name">email.template.form</field> |
||||
|
<field name="model">email.template</field> |
||||
|
<field name="inherit_id" ref="email_template.email_template_form" /> |
||||
|
<field name="arch" type="xml"> |
||||
|
<data> |
||||
|
<field name="name" position="after"> |
||||
|
<field name="is_template_template" invisible="1" /> |
||||
|
<field name="email_template_id" domain="[('email_template_id', '=', False), ('model_id', '=', %(email_template.model_email_template)s)]" |
||||
|
attrs="{'readonly': [('is_template_template','=',True), ('email_template_id','=',False)]}" |
||||
|
context="{'default_model_id': %(email_template.model_email_template)s}" |
||||
|
/> |
||||
|
|
||||
|
</field> |
||||
|
<field name="model_id" position="attributes"> |
||||
|
<attribute name="attrs"> |
||||
|
{'readonly': [('is_template_template','=',True)]} |
||||
|
</attribute> |
||||
|
</field> |
||||
|
<field name="email_from" position="attributes"> |
||||
|
<attribute name="required">0</attribute> |
||||
|
<attribute name="attrs"> |
||||
|
{'readonly': ['|',('is_template_template','=',True),('model_id', '=', %(email_template.model_email_template)s)]} |
||||
|
</attribute> |
||||
|
</field> |
||||
|
<field name="email_to" position="attributes"> |
||||
|
<attribute name="required">0</attribute> |
||||
|
<attribute name="attrs"> |
||||
|
{'readonly': ['|',('is_template_template','=',True),('model_id', '=', %(email_template.model_email_template)s)]} |
||||
|
</attribute> |
||||
|
</field> |
||||
|
<field name="email_cc" position="attributes"> |
||||
|
<attribute name="attrs"> |
||||
|
{'readonly': ['|',('is_template_template','=',True),('model_id', '=', %(email_template.model_email_template)s)]} |
||||
|
</attribute> |
||||
|
</field> |
||||
|
<field name="email_recipients" position="attributes"> |
||||
|
<attribute name="attrs"> |
||||
|
{'readonly': ['|',('is_template_template','=',True),('model_id', '=', %(email_template.model_email_template)s)]} |
||||
|
</attribute> |
||||
|
</field> |
||||
|
<field name="reply_to" position="attributes"> |
||||
|
<attribute name="attrs"> |
||||
|
{'readonly': ['|',('is_template_template','=',True),('model_id', '=', %(email_template.model_email_template)s)]} |
||||
|
</attribute> |
||||
|
</field> |
||||
|
<field name="lang" position="attributes"> |
||||
|
<attribute name="attrs"> |
||||
|
{'readonly': ['|',('is_template_template','=',True),('model_id', '=', %(email_template.model_email_template)s)]} |
||||
|
</attribute> |
||||
|
</field> |
||||
|
<field name="user_signature" position="attributes"> |
||||
|
<attribute name="attrs"> |
||||
|
{'readonly': ['|',('is_template_template','=',True),('model_id', '=', %(email_template.model_email_template)s)]} |
||||
|
</attribute> |
||||
|
</field> |
||||
|
<field name="subject" position="attributes"> |
||||
|
<attribute name="required">0</attribute> |
||||
|
<attribute name="attrs"> |
||||
|
{'readonly': ['|',('is_template_template','=',True),('model_id', '=', %(email_template.model_email_template)s)]} |
||||
|
</attribute> |
||||
|
</field> |
||||
|
</data> |
||||
|
</field> |
||||
|
</record> |
||||
|
</data> |
||||
|
</openerp> |
@ -0,0 +1,25 @@ |
|||||
|
# -*- encoding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# OpenERP, Open Source Management Solution |
||||
|
# This module copyright (C) 2013 Therp BV (<http://therp.nl>) |
||||
|
# All Rights Reserved |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
import match_algorithm |
||||
|
import model |
||||
|
import wizard |
@ -0,0 +1,46 @@ |
|||||
|
# -*- encoding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# OpenERP, Open Source Management Solution |
||||
|
# This module copyright (C) 2013 Therp BV (<http://therp.nl>) |
||||
|
# All Rights Reserved |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
{ |
||||
|
'name': 'Attach mails in an IMAP folder to existing objects', |
||||
|
'version': '1.0', |
||||
|
'description': """ |
||||
|
Adds the possibility to attach emails from a certain IMAP folder to objects, |
||||
|
ie partners. Matching is done via several algorithms, ie email address. |
||||
|
|
||||
|
This gives a simple possibility to archive emails in OpenERP without a mail |
||||
|
client integration. |
||||
|
""", |
||||
|
'author': 'Therp BV', |
||||
|
'website': 'http://www.therp.nl', |
||||
|
"category": "Tools", |
||||
|
"depends": ['fetchmail'], |
||||
|
'data': [ |
||||
|
'view/fetchmail_server.xml', |
||||
|
'wizard/attach_mail_manually.xml', |
||||
|
'security/ir.model.access.csv', |
||||
|
], |
||||
|
'js': [], |
||||
|
'installable': False, |
||||
|
'active': False, |
||||
|
'certificate': '', |
||||
|
} |
@ -0,0 +1,26 @@ |
|||||
|
# -*- encoding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# OpenERP, Open Source Management Solution |
||||
|
# This module copyright (C) 2013 Therp BV (<http://therp.nl>) |
||||
|
# All Rights Reserved |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
import base |
||||
|
import email_exact |
||||
|
import email_domain |
||||
|
import openerp_standard |
@ -0,0 +1,43 @@ |
|||||
|
# -*- encoding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# OpenERP, Open Source Management Solution |
||||
|
# This module copyright (C) 2013 Therp BV (<http://therp.nl>) |
||||
|
# All Rights Reserved |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
|
||||
|
class base(object): |
||||
|
name = None |
||||
|
'''Name shown to the user''' |
||||
|
|
||||
|
required_fields = [] |
||||
|
'''Fields on fetchmail_server folder that are required for this algorithm''' |
||||
|
|
||||
|
readonly_fields = [] |
||||
|
'''Fields on fetchmail_server folder that are readonly for this algorithm''' |
||||
|
|
||||
|
def search_matches(self, cr, uid, conf, mail_message, mail_message_org): |
||||
|
'''Returns ids found for model with mail_message''' |
||||
|
return [] |
||||
|
|
||||
|
def handle_match( |
||||
|
self, cr, uid, connection, object_id, folder, |
||||
|
mail_message, mail_message_org, msgid, context=None): |
||||
|
'''Do whatever it takes to handle a match''' |
||||
|
return folder.server_id.attach_mail(connection, object_id, folder, |
||||
|
mail_message, msgid) |
@ -0,0 +1,45 @@ |
|||||
|
# -*- encoding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# OpenERP, Open Source Management Solution |
||||
|
# This module copyright (C) 2013 Therp BV (<http://therp.nl>) |
||||
|
# All Rights Reserved |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
from email_exact import email_exact |
||||
|
|
||||
|
|
||||
|
class email_domain(email_exact): |
||||
|
'''Search objects by domain name of email address. |
||||
|
Beware of match_first here, this is most likely to get it wrong (gmail)''' |
||||
|
name = 'Domain of email address' |
||||
|
|
||||
|
def search_matches(self, cr, uid, conf, mail_message, mail_message_org): |
||||
|
ids = super(email_domain, self).search_matches( |
||||
|
cr, uid, conf, mail_message, mail_message_org) |
||||
|
if not ids: |
||||
|
domains = [] |
||||
|
for addr in self._get_mailaddresses(conf, mail_message): |
||||
|
domains.append(addr.split('@')[-1]) |
||||
|
ids = conf.pool.get(conf.model_id.model).search( |
||||
|
cr, uid, |
||||
|
self._get_mailaddress_search_domain( |
||||
|
conf, mail_message, |
||||
|
operator='like', |
||||
|
values=['%@'+domain for domain in set(domains)]), |
||||
|
order=conf.model_order) |
||||
|
return ids |
@ -0,0 +1,57 @@ |
|||||
|
# -*- encoding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# OpenERP, Open Source Management Solution |
||||
|
# This module copyright (C) 2013 Therp BV (<http://therp.nl>) |
||||
|
# All Rights Reserved |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
from base import base |
||||
|
from openerp.tools.safe_eval import safe_eval |
||||
|
from openerp.tools.mail import email_split |
||||
|
|
||||
|
|
||||
|
class email_exact(base): |
||||
|
'''Search for exactly the mailadress as noted in the email''' |
||||
|
|
||||
|
name = 'Exact mailadress' |
||||
|
required_fields = ['model_field', 'mail_field'] |
||||
|
|
||||
|
def _get_mailaddresses(self, conf, mail_message): |
||||
|
mailaddresses = [] |
||||
|
fields = conf.mail_field.split(',') |
||||
|
for field in fields: |
||||
|
if field in mail_message: |
||||
|
mailaddresses += email_split(mail_message[field]) |
||||
|
return [addr.lower() for addr in mailaddresses] |
||||
|
|
||||
|
def _get_mailaddress_search_domain( |
||||
|
self, conf, mail_message, operator='=', values=None): |
||||
|
mailaddresses = values or self._get_mailaddresses( |
||||
|
conf, mail_message) |
||||
|
if not mailaddresses: |
||||
|
return [(0, '=', 1)] |
||||
|
search_domain = ((['|'] * (len(mailaddresses) - 1)) + [ |
||||
|
(conf.model_field, operator, addr) for addr in mailaddresses] + |
||||
|
safe_eval(conf.domain or '[]')) |
||||
|
return search_domain |
||||
|
|
||||
|
def search_matches(self, cr, uid, conf, mail_message, mail_message_org): |
||||
|
conf_model = conf.pool.get(conf.model_id.model) |
||||
|
search_domain = self._get_mailaddress_search_domain(conf, mail_message) |
||||
|
return conf_model.search( |
||||
|
cr, uid, search_domain, order=conf.model_order) |
@ -0,0 +1,58 @@ |
|||||
|
# -*- encoding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# OpenERP, Open Source Management Solution |
||||
|
# This module copyright (C) 2013 Therp BV (<http://therp.nl>) |
||||
|
# All Rights Reserved |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
from base import base |
||||
|
|
||||
|
|
||||
|
class openerp_standard(base): |
||||
|
'''No search at all. Use OpenERP's standard mechanism to attach mails to |
||||
|
mail.thread objects. Note that this algorithm always matches.''' |
||||
|
|
||||
|
name = 'OpenERP standard' |
||||
|
readonly_fields = [ |
||||
|
'model_field', |
||||
|
'mail_field', |
||||
|
'match_first', |
||||
|
'domain', |
||||
|
'model_order', |
||||
|
'flag_nonmatching', |
||||
|
] |
||||
|
|
||||
|
def search_matches(self, cr, uid, conf, mail_message, mail_message_org): |
||||
|
'''Always match. Duplicates will be fished out by message_id''' |
||||
|
return [True] |
||||
|
|
||||
|
def handle_match( |
||||
|
self, cr, uid, connection, object_id, folder, |
||||
|
mail_message, mail_message_org, msgid, context): |
||||
|
result = folder.pool.get('mail.thread').message_process( |
||||
|
cr, uid, |
||||
|
folder.model_id.model, mail_message_org, |
||||
|
save_original=folder.server_id.original, |
||||
|
strip_attachments=(not folder.server_id.attach), |
||||
|
context=context |
||||
|
) |
||||
|
|
||||
|
if folder.delete_matching: |
||||
|
connection.store(msgid, '+FLAGS', '\\DELETED') |
||||
|
|
||||
|
return [result] |
@ -0,0 +1,24 @@ |
|||||
|
# -*- encoding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# OpenERP, Open Source Management Solution |
||||
|
# This module copyright (C) 2013 Therp BV (<http://therp.nl>) |
||||
|
# All Rights Reserved |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
import fetchmail_server |
||||
|
import fetchmail_server_folder |
@ -0,0 +1,278 @@ |
|||||
|
# -*- encoding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# OpenERP, Open Source Management Solution |
||||
|
# This module copyright (C) 2013 Therp BV (<http://therp.nl>) |
||||
|
# All Rights Reserved |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
import base64 |
||||
|
import simplejson |
||||
|
from lxml import etree |
||||
|
from openerp.osv.orm import Model, except_orm |
||||
|
from openerp.tools.translate import _ |
||||
|
from openerp.osv import fields |
||||
|
from openerp.addons.fetchmail.fetchmail import _logger as logger |
||||
|
from openerp.tools.misc import UnquoteEvalContext |
||||
|
|
||||
|
|
||||
|
class fetchmail_server(Model): |
||||
|
_inherit = 'fetchmail.server' |
||||
|
|
||||
|
_columns = { |
||||
|
'folder_ids': fields.one2many( |
||||
|
'fetchmail.server.folder', 'server_id', 'Folders'), |
||||
|
} |
||||
|
|
||||
|
_defaults = { |
||||
|
'type': 'imap', |
||||
|
} |
||||
|
|
||||
|
def __init__(self, pool, cr): |
||||
|
self._columns['object_id'].required = False |
||||
|
return super(fetchmail_server, self).__init__(pool, cr) |
||||
|
|
||||
|
def onchange_server_type( |
||||
|
self, cr, uid, ids, server_type=False, ssl=False, |
||||
|
object_id=False): |
||||
|
retval = super( |
||||
|
fetchmail_server, self).onchange_server_type(cr, uid, |
||||
|
ids, server_type, ssl, |
||||
|
object_id) |
||||
|
retval['value']['state'] = 'draft' |
||||
|
return retval |
||||
|
|
||||
|
def fetch_mail(self, cr, uid, ids, context=None): |
||||
|
if context is None: |
||||
|
context = {} |
||||
|
|
||||
|
check_original = [] |
||||
|
|
||||
|
for this in self.browse(cr, uid, ids, context): |
||||
|
if this.object_id: |
||||
|
check_original.append(this.id) |
||||
|
|
||||
|
context.update( |
||||
|
{ |
||||
|
'fetchmail_server_id': this.id, |
||||
|
'server_type': this.type |
||||
|
}) |
||||
|
|
||||
|
connection = this.connect() |
||||
|
for folder in this.folder_ids: |
||||
|
this.handle_folder(connection, folder) |
||||
|
|
||||
|
connection.close() |
||||
|
|
||||
|
return super(fetchmail_server, self).fetch_mail( |
||||
|
cr, uid, check_original, context) |
||||
|
|
||||
|
def handle_folder(self, cr, uid, ids, connection, folder, context=None): |
||||
|
'''Return ids of objects matched''' |
||||
|
|
||||
|
matched_object_ids = [] |
||||
|
|
||||
|
for this in self.browse(cr, uid, ids, context=context): |
||||
|
logger.info('start checking for emails in %s server %s', |
||||
|
folder.path, this.name) |
||||
|
|
||||
|
match_algorithm = folder.get_algorithm() |
||||
|
|
||||
|
if connection.select(folder.path)[0] != 'OK': |
||||
|
logger.error( |
||||
|
'Could not open mailbox %s on %s' % (folder.path, this.server)) |
||||
|
connection.select() |
||||
|
continue |
||||
|
result, msgids = this.get_msgids(connection) |
||||
|
if result != 'OK': |
||||
|
logger.error( |
||||
|
'Could not search mailbox %s on %s' % ( |
||||
|
folder.path, this.server)) |
||||
|
continue |
||||
|
|
||||
|
for msgid in msgids[0].split(): |
||||
|
matched_object_ids += this.apply_matching( |
||||
|
connection, folder, msgid, match_algorithm) |
||||
|
|
||||
|
logger.info('finished checking for emails in %s server %s', |
||||
|
folder.path, this.name) |
||||
|
|
||||
|
return matched_object_ids |
||||
|
|
||||
|
def get_msgids(self, cr, uid, ids, connection, context=None): |
||||
|
'''Return imap ids of messages to process''' |
||||
|
return connection.search(None, 'UNDELETED') |
||||
|
|
||||
|
def apply_matching(self, cr, uid, ids, connection, folder, msgid, |
||||
|
match_algorithm, context=None): |
||||
|
'''Return ids of objects matched''' |
||||
|
|
||||
|
matched_object_ids = [] |
||||
|
|
||||
|
for this in self.browse(cr, uid, ids, context=context): |
||||
|
result, msgdata = connection.fetch(msgid, '(RFC822)') |
||||
|
|
||||
|
if result != 'OK': |
||||
|
logger.error( |
||||
|
'Could not fetch %s in %s on %s' % (msgid, folder.path, this.server)) |
||||
|
continue |
||||
|
|
||||
|
mail_message = self.pool.get('mail.thread').message_parse( |
||||
|
cr, uid, msgdata[0][1], save_original=this.original, |
||||
|
context=context) |
||||
|
|
||||
|
if self.pool.get('mail.message').search( |
||||
|
cr, uid, [ |
||||
|
('message_id', '=', mail_message['message_id'])]): |
||||
|
continue |
||||
|
|
||||
|
found_ids = match_algorithm.search_matches( |
||||
|
cr, uid, folder, |
||||
|
mail_message, msgdata[0][1]) |
||||
|
|
||||
|
if found_ids and (len(found_ids) == 1 or |
||||
|
folder.match_first): |
||||
|
try: |
||||
|
cr.execute('savepoint apply_matching') |
||||
|
match_algorithm.handle_match( |
||||
|
cr, uid, connection, |
||||
|
found_ids[0], folder, mail_message, |
||||
|
msgdata[0][1], msgid, context) |
||||
|
cr.execute('release savepoint apply_matching') |
||||
|
matched_object_ids += found_ids[:1] |
||||
|
except Exception: |
||||
|
cr.execute('rollback to savepoint apply_matching') |
||||
|
logger.exception( |
||||
|
"Failed to fetch mail %s from %s", |
||||
|
msgid, this.name) |
||||
|
elif folder.flag_nonmatching: |
||||
|
connection.store(msgid, '+FLAGS', '\\FLAGGED') |
||||
|
|
||||
|
return matched_object_ids |
||||
|
|
||||
|
def attach_mail( |
||||
|
self, cr, uid, ids, connection, object_id, folder, |
||||
|
mail_message, msgid, context=None): |
||||
|
'''Return ids of messages created''' |
||||
|
|
||||
|
mail_message_ids = [] |
||||
|
|
||||
|
for this in self.browse(cr, uid, ids, context): |
||||
|
partner_id = None |
||||
|
if folder.model_id.model == 'res.partner': |
||||
|
partner_id = object_id |
||||
|
if 'partner_id' in self.pool.get(folder.model_id.model)._columns: |
||||
|
partner_id = self.pool.get( |
||||
|
folder.model_id.model).browse( |
||||
|
cr, uid, object_id, context |
||||
|
).partner_id.id |
||||
|
|
||||
|
attachments = [] |
||||
|
if this.attach and mail_message.get('attachments'): |
||||
|
for attachment in mail_message['attachments']: |
||||
|
fname, fcontent = attachment |
||||
|
if isinstance(fcontent, unicode): |
||||
|
fcontent = fcontent.encode('utf-8') |
||||
|
data_attach = { |
||||
|
'name': fname, |
||||
|
'datas': base64.b64encode(str(fcontent)), |
||||
|
'datas_fname': fname, |
||||
|
'description': _('Mail attachment'), |
||||
|
'res_model': folder.model_id.model, |
||||
|
'res_id': object_id, |
||||
|
} |
||||
|
attachments.append( |
||||
|
self.pool.get('ir.attachment').create( |
||||
|
cr, uid, data_attach, context=context)) |
||||
|
|
||||
|
mail_message_ids.append( |
||||
|
self.pool.get('mail.message').create( |
||||
|
cr, uid, |
||||
|
{ |
||||
|
'author_id': partner_id, |
||||
|
'model': folder.model_id.model, |
||||
|
'res_id': object_id, |
||||
|
'type': 'email', |
||||
|
'body': mail_message.get('body'), |
||||
|
'subject': mail_message.get('subject'), |
||||
|
'email_from': mail_message.get('from'), |
||||
|
'date': mail_message.get('date'), |
||||
|
'message_id': mail_message.get('message_id'), |
||||
|
'attachment_ids': [(6, 0, attachments)], |
||||
|
}, |
||||
|
context)) |
||||
|
|
||||
|
if folder.delete_matching: |
||||
|
connection.store(msgid, '+FLAGS', '\\DELETED') |
||||
|
return mail_message_ids |
||||
|
|
||||
|
def button_confirm_login(self, cr, uid, ids, context=None): |
||||
|
retval = super(fetchmail_server, self).button_confirm_login(cr, uid, |
||||
|
ids, |
||||
|
context) |
||||
|
|
||||
|
for this in self.browse(cr, uid, ids, context): |
||||
|
this.write({'state': 'draft'}) |
||||
|
connection = this.connect() |
||||
|
connection.select() |
||||
|
for folder in this.folder_ids: |
||||
|
if connection.select(folder.path)[0] != 'OK': |
||||
|
raise except_orm( |
||||
|
_('Error'), _('Mailbox %s not found!') % |
||||
|
folder.path) |
||||
|
connection.close() |
||||
|
this.write({'state': 'done'}) |
||||
|
|
||||
|
return retval |
||||
|
|
||||
|
def fields_view_get(self, cr, user, view_id=None, view_type='form', |
||||
|
context=None, toolbar=False, submenu=False): |
||||
|
result = super(fetchmail_server, self).fields_view_get( |
||||
|
cr, user, view_id, view_type, context, toolbar, submenu) |
||||
|
|
||||
|
if view_type == 'form': |
||||
|
view = etree.fromstring( |
||||
|
result['fields']['folder_ids']['views']['form']['arch']) |
||||
|
modifiers = {} |
||||
|
docstr = '' |
||||
|
for algorithm in self.pool.get('fetchmail.server.folder')\ |
||||
|
._get_match_algorithms().itervalues(): |
||||
|
for modifier in ['required', 'readonly']: |
||||
|
for field in getattr(algorithm, modifier + '_fields'): |
||||
|
modifiers.setdefault(field, {}) |
||||
|
modifiers[field].setdefault(modifier, []) |
||||
|
if modifiers[field][modifier]: |
||||
|
modifiers[field][modifier].insert(0, '|') |
||||
|
modifiers[field][modifier].append( |
||||
|
("match_algorithm", "==", algorithm.__name__)) |
||||
|
docstr += _(algorithm.name) + '\n' + _(algorithm.__doc__) + \ |
||||
|
'\n\n' |
||||
|
|
||||
|
for field in view: |
||||
|
if field.tag == 'field' and field.get('name') in modifiers: |
||||
|
field.set('modifiers', simplejson.dumps( |
||||
|
dict( |
||||
|
eval(field.attrib['modifiers'], |
||||
|
UnquoteEvalContext({})), |
||||
|
**modifiers[field.attrib['name']]))) |
||||
|
if (field.tag == 'field' and |
||||
|
field.get('name') == 'match_algorithm'): |
||||
|
field.set('help', docstr) |
||||
|
result['fields']['folder_ids']['views']['form']['arch'] = \ |
||||
|
etree.tostring(view) |
||||
|
|
||||
|
return result |
@ -0,0 +1,131 @@ |
|||||
|
# -*- encoding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# OpenERP, Open Source Management Solution |
||||
|
# This module copyright (C) 2013 Therp BV (<http://therp.nl>) |
||||
|
# All Rights Reserved |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
######################################################################## |
||||
|
|
||||
|
from openerp.osv import fields |
||||
|
from openerp.osv.orm import Model |
||||
|
from .. import match_algorithm |
||||
|
|
||||
|
|
||||
|
class fetchmail_server_folder(Model): |
||||
|
_name = 'fetchmail.server.folder' |
||||
|
_rec_name = 'path' |
||||
|
|
||||
|
def _get_match_algorithms(self): |
||||
|
def get_all_subclasses(cls): |
||||
|
return cls.__subclasses__() + [subsub |
||||
|
for sub in cls.__subclasses__() |
||||
|
for subsub in get_all_subclasses(sub)] |
||||
|
return dict([(cls.__name__, cls) for cls in get_all_subclasses( |
||||
|
match_algorithm.base.base)]) |
||||
|
|
||||
|
def _get_match_algorithms_sel(self, cr, uid, context=None): |
||||
|
algorithms = [] |
||||
|
for cls in self._get_match_algorithms().itervalues(): |
||||
|
algorithms.append((cls.__name__, cls.name)) |
||||
|
algorithms.sort() |
||||
|
return algorithms |
||||
|
|
||||
|
_columns = { |
||||
|
'sequence': fields.integer('Sequence'), |
||||
|
'path': fields.char( |
||||
|
'Path', size=256, help='The path to your mail ' |
||||
|
"folder. Typically would be something like 'INBOX.myfolder'", |
||||
|
required=True |
||||
|
), |
||||
|
'model_id': fields.many2one( |
||||
|
'ir.model', 'Model', required=True, |
||||
|
help='The model to attach emails to' |
||||
|
), |
||||
|
'model_field': fields.char( |
||||
|
'Field (model)', size=128, |
||||
|
help='The field in your model that contains the field to match ' |
||||
|
'against.\n' |
||||
|
'Examples:\n' |
||||
|
"'email' if your model is res.partner, or " |
||||
|
"'partner_id.email' if you're matching sale orders" |
||||
|
), |
||||
|
'model_order': fields.char( |
||||
|
'Order (model)', size=128, |
||||
|
help='Fields to order by, this mostly useful in conjunction ' |
||||
|
"with 'Use 1st match'" |
||||
|
), |
||||
|
'match_algorithm': fields.selection( |
||||
|
_get_match_algorithms_sel, |
||||
|
'Match algorithm', required=True, translate=True, |
||||
|
help='The algorithm used to determine which object an email ' |
||||
|
'matches.' |
||||
|
), |
||||
|
'mail_field': fields.char( |
||||
|
'Field (email)', size=128, |
||||
|
help='The field in the email used for matching. Typically ' |
||||
|
"this is 'to' or 'from'" |
||||
|
), |
||||
|
'server_id': fields.many2one('fetchmail.server', 'Server'), |
||||
|
'delete_matching': fields.boolean( |
||||
|
'Delete matches', |
||||
|
help='Delete matched emails from server' |
||||
|
), |
||||
|
'flag_nonmatching': fields.boolean( |
||||
|
'Flag nonmatching', |
||||
|
help="Flag emails in the server that don't match any object " |
||||
|
'in OpenERP' |
||||
|
), |
||||
|
'match_first': fields.boolean( |
||||
|
'Use 1st match', |
||||
|
help='If there are multiple matches, use the first one. If ' |
||||
|
'not checked, multiple matches count as no match at all' |
||||
|
), |
||||
|
'domain': fields.char( |
||||
|
'Domain', size=128, help='Fill in a search ' |
||||
|
'filter to narrow down objects to match' |
||||
|
), |
||||
|
'msg_state': fields.selection( |
||||
|
[ |
||||
|
('sent', 'Sent'), |
||||
|
('received', 'Received'), |
||||
|
], |
||||
|
'Message state', |
||||
|
help='The state messages fetched from this folder should be ' |
||||
|
'assigned in OpenERP' |
||||
|
), |
||||
|
} |
||||
|
|
||||
|
_defaults = { |
||||
|
'flag_nonmatching': True, |
||||
|
'msg_state': 'received', |
||||
|
} |
||||
|
|
||||
|
def get_algorithm(self, cr, uid, ids, context=None): |
||||
|
for this in self.browse(cr, uid, ids, context): |
||||
|
return self._get_match_algorithms()[this.match_algorithm]() |
||||
|
|
||||
|
def button_attach_mail_manually(self, cr, uid, ids, context=None): |
||||
|
for this in self.browse(cr, uid, ids, context): |
||||
|
context.update({'default_folder_id': this.id}) |
||||
|
return { |
||||
|
'type': 'ir.actions.act_window', |
||||
|
'res_model': 'fetchmail.attach.mail.manually', |
||||
|
'target': 'new', |
||||
|
'context': context, |
||||
|
'view_type': 'form', |
||||
|
'view_mode': 'form', |
||||
|
} |
@ -0,0 +1,2 @@ |
|||||
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink |
||||
|
access_model_fetchmail_server_folder,fetchmail.server.folder,model_fetchmail_server_folder,base.group_system,1,1,1,1 |
@ -0,0 +1,56 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<openerp> |
||||
|
<data> |
||||
|
<record model="ir.ui.view" id="view_email_server_form"> |
||||
|
<field name="name">fetchmail.server.form</field> |
||||
|
<field name="model">fetchmail.server</field> |
||||
|
<field name="inherit_id" ref="fetchmail.view_email_server_form" /> |
||||
|
<field name="arch" type="xml"> |
||||
|
<data> |
||||
|
<field name="object_id" position="attributes"> |
||||
|
<attribute name="attrs">{'required': [('type', '!=', 'imap')]}</attribute> |
||||
|
</field> |
||||
|
<xpath expr="//page[@string='Server & Login']/group/group[3]" position="after"> |
||||
|
<group attrs="{'invisible': [('type','!=','imap')]}" string="Folders to monitor"> |
||||
|
<field |
||||
|
name="folder_ids" |
||||
|
nolabel="1" |
||||
|
on_change="onchange_server_type(type, is_ssl, object_id)"> |
||||
|
<tree> |
||||
|
<field name="sequence" invisible="1" /> |
||||
|
<field name="path" /> |
||||
|
<field name="model_id" /> |
||||
|
<field name="model_field" /> |
||||
|
<field name="match_algorithm" /> |
||||
|
<field name="mail_field" /> |
||||
|
</tree> |
||||
|
<form version="7.0"> |
||||
|
<header> |
||||
|
<button type="object" name="button_attach_mail_manually" string="Attach mail manually" icon="gtk-redo" /> |
||||
|
</header> |
||||
|
<group> |
||||
|
<group> |
||||
|
<field name="path" /> |
||||
|
<field name="model_id" /> |
||||
|
<field name="model_field" /> |
||||
|
<field name="match_algorithm" /> |
||||
|
<field name="mail_field" /> |
||||
|
</group> |
||||
|
<group> |
||||
|
<field name="delete_matching" /> |
||||
|
<field name="flag_nonmatching" /> |
||||
|
<field name="match_first" /> |
||||
|
<field name="msg_state" /> |
||||
|
<field name="model_order" attrs="{'readonly': [('match_first','==',False)], 'required': [('match_first','==',True)]}" /> |
||||
|
<field name="domain" /> |
||||
|
</group> |
||||
|
</group> |
||||
|
</form> |
||||
|
</field> |
||||
|
</group> |
||||
|
</xpath> |
||||
|
</data> |
||||
|
</field> |
||||
|
</record> |
||||
|
</data> |
||||
|
</openerp> |
@ -0,0 +1,23 @@ |
|||||
|
# -*- encoding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# OpenERP, Open Source Management Solution |
||||
|
# This module copyright (C) 2013 Therp BV (<http://therp.nl>) |
||||
|
# All Rights Reserved |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
import attach_mail_manually |
@ -0,0 +1,129 @@ |
|||||
|
# -*- encoding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# OpenERP, Open Source Management Solution |
||||
|
# This module copyright (C) 2013 Therp BV (<http://therp.nl>) |
||||
|
# All Rights Reserved |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
from openerp.osv import fields |
||||
|
from openerp.osv.orm import TransientModel |
||||
|
import logging |
||||
|
logger = logging.getLogger(__name__) |
||||
|
|
||||
|
|
||||
|
class attach_mail_manually(TransientModel): |
||||
|
_name = 'fetchmail.attach.mail.manually' |
||||
|
|
||||
|
_columns = { |
||||
|
'folder_id': fields.many2one('fetchmail.server.folder', 'Folder', |
||||
|
readonly=True), |
||||
|
'mail_ids': fields.one2many( |
||||
|
'fetchmail.attach.mail.manually.mail', 'wizard_id', 'Emails'), |
||||
|
} |
||||
|
|
||||
|
def default_get(self, cr, uid, fields_list, context=None): |
||||
|
if context is None: |
||||
|
context = {} |
||||
|
|
||||
|
defaults = super(attach_mail_manually, self).default_get( |
||||
|
cr, uid, fields_list, context |
||||
|
) |
||||
|
|
||||
|
for folder in self.pool.get('fetchmail.server.folder').browse( |
||||
|
cr, uid, |
||||
|
[context.get('default_folder_id')], context): |
||||
|
defaults['mail_ids'] = [] |
||||
|
connection = folder.server_id.connect() |
||||
|
connection.select(folder.path) |
||||
|
result, msgids = connection.search( |
||||
|
None, |
||||
|
'FLAGGED' if folder.flag_nonmatching else 'UNDELETED') |
||||
|
if result != 'OK': |
||||
|
logger.error('Could not search mailbox %s on %s' % ( |
||||
|
folder.path, folder.server_id.name)) |
||||
|
continue |
||||
|
attach_mail_manually_mail._columns['object_id'].selection = [ |
||||
|
(folder.model_id.model, folder.model_id.name)] |
||||
|
for msgid in msgids[0].split(): |
||||
|
result, msgdata = connection.fetch(msgid, '(RFC822)') |
||||
|
if result != 'OK': |
||||
|
logger.error('Could not fetch %s in %s on %s' % ( |
||||
|
msgid, folder.path, folder.server_id.name)) |
||||
|
continue |
||||
|
mail_message = self.pool.get('mail.thread').message_parse( |
||||
|
cr, uid, msgdata[0][1], |
||||
|
save_original=folder.server_id.original, |
||||
|
context=context |
||||
|
) |
||||
|
defaults['mail_ids'].append((0, 0, { |
||||
|
'msgid': msgid, |
||||
|
'subject': mail_message.get('subject', ''), |
||||
|
'date': mail_message.get('date', ''), |
||||
|
'object_id': folder.model_id.model+',False' |
||||
|
})) |
||||
|
connection.close() |
||||
|
|
||||
|
return defaults |
||||
|
|
||||
|
def attach_mails(self, cr, uid, ids, context=None): |
||||
|
for this in self.browse(cr, uid, ids, context): |
||||
|
for mail in this.mail_ids: |
||||
|
connection = this.folder_id.server_id.connect() |
||||
|
connection.select(this.folder_id.path) |
||||
|
result, msgdata = connection.fetch(mail.msgid, '(RFC822)') |
||||
|
if result != 'OK': |
||||
|
logger.error('Could not fetch %s in %s on %s' % ( |
||||
|
mail.msgid, this.folder_id.path, this.server)) |
||||
|
continue |
||||
|
|
||||
|
mail_message = self.pool.get('mail.thread').message_parse( |
||||
|
cr, uid, msgdata[0][1], |
||||
|
save_original=this.folder_id.server_id.original, |
||||
|
context=context) |
||||
|
|
||||
|
this.folder_id.server_id.attach_mail( |
||||
|
connection, |
||||
|
mail.object_id.id, this.folder_id, mail_message, |
||||
|
mail.msgid |
||||
|
) |
||||
|
connection.close() |
||||
|
return {'type': 'ir.actions.act_window_close'} |
||||
|
|
||||
|
|
||||
|
class attach_mail_manually_mail(TransientModel): |
||||
|
_name = 'fetchmail.attach.mail.manually.mail' |
||||
|
|
||||
|
_columns = { |
||||
|
'wizard_id': fields.many2one('fetchmail.attach.mail.manually', |
||||
|
readonly=True), |
||||
|
'msgid': fields.char('Message id', size=16, readonly=True), |
||||
|
'subject': fields.char('Subject', size=128, readonly=True), |
||||
|
'date': fields.datetime('Date', readonly=True), |
||||
|
'object_id': fields.reference( |
||||
|
'Object', |
||||
|
selection=lambda self, cr, uid, context: [ |
||||
|
(m.model, m.name) |
||||
|
for m in self.pool.get('ir.model').browse( |
||||
|
cr, uid, |
||||
|
self.pool.get('ir.model').search(cr, uid, []), |
||||
|
context |
||||
|
) |
||||
|
], |
||||
|
size=128, |
||||
|
), |
||||
|
} |
@ -0,0 +1,29 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<openerp> |
||||
|
<data> |
||||
|
<record model="ir.ui.view" id="view_attach_mail_manually"> |
||||
|
<field name="name">fetchmail.attach.mail.manually</field> |
||||
|
<field name="model">fetchmail.attach.mail.manually</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<form col="4" version="7.0" string="Attach mail manually"> |
||||
|
<sheet> |
||||
|
<group> |
||||
|
<field name="folder_id" /> |
||||
|
<field name="mail_ids" nolabel="1" colspan="4"> |
||||
|
<tree editable="top" create="0"> |
||||
|
<field name="subject" /> |
||||
|
<field name="date" /> |
||||
|
<field name="object_id" /> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</group> |
||||
|
</sheet> |
||||
|
<footer> |
||||
|
<button string="Save" type="object" name="attach_mails" icon="gtk-ok" /> |
||||
|
<button special="cancel" string="Cancel" icon="gtk-cancel" /> |
||||
|
</footer> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
</data> |
||||
|
</openerp> |
@ -0,0 +1,24 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Daniel Reis |
||||
|
# 2011 |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
from . import import_odbc |
||||
|
|
||||
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
@ -0,0 +1,101 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Daniel Reis |
||||
|
# 2011 |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
{ |
||||
|
'name': 'Import data from SQL and ODBC data sources.', |
||||
|
'version': '1.3', |
||||
|
'category': 'Tools', |
||||
|
'description': """ |
||||
|
Import data directly from other databases. |
||||
|
|
||||
|
Installed in the Administration module, menu Configuration -> Import from SQL. |
||||
|
|
||||
|
Features: |
||||
|
* Fetched data from the databases are used to build lines equivalent to |
||||
|
regular import files. These are imported using the standard "import_data()" |
||||
|
ORM method, benefiting from all its features, including xml_ids. |
||||
|
* Each table import is defined by an SQL statement, used to build the |
||||
|
equivalent for an import file. Each column's name should match the column |
||||
|
names you would use in an import file. The first column must provide an |
||||
|
unique identifier for the record, and will be used to build its xml_id. |
||||
|
* SQL columns named "none" are ignored. This can be used for the first column |
||||
|
of the SQL, so that it's used to build the XML Id but it's not imported to |
||||
|
any OpenERP field. |
||||
|
* The last sync date is the last successfull execution can be used in the SQL |
||||
|
using "%(sync)s", or ":sync" in the case of Oracle. |
||||
|
* When errors are found, only the record with the error fails import. The |
||||
|
other correct records are commited. However, the "last sync date" will only |
||||
|
be automaticaly updated when no errors are found. |
||||
|
* The import execution can be scheduled to run automatically. |
||||
|
|
||||
|
Examples: |
||||
|
* Importing suppliers to res.partner: |
||||
|
SELECT distinct |
||||
|
[SUPPLIER_CODE] as "ref" |
||||
|
, [SUPPLIER_NAME] as "name" |
||||
|
, 1 as "is_supplier" |
||||
|
, [INFO] as "comment" |
||||
|
FROM T_SUPPLIERS |
||||
|
WHERE INACTIVE_DATE IS NULL and DATE_CHANGED >= %(sync)s |
||||
|
|
||||
|
* Importing products to product.product: |
||||
|
SELECT PRODUCT_CODE as "ref" |
||||
|
, PRODUCT_NAME as "name" |
||||
|
, 'res_partner_id_'+SUPPLIER_ID as "partner_id/id" |
||||
|
FROM T_PRODUCTS |
||||
|
WHERE DATE_CHANGED >= %(sync)s |
||||
|
|
||||
|
Improvements ideas waiting for a contributor: |
||||
|
* Allow to import many2one fields (currently not supported). Done by adding a |
||||
|
second SQL sentence to get child record list? |
||||
|
* Allow "import sets" that can be executed at different time intervals using |
||||
|
different scheduler jobs. |
||||
|
* Allow to inactivate/delete OpenERP records when not present in an SQL |
||||
|
result set. |
||||
|
|
||||
|
Contributors |
||||
|
============ |
||||
|
|
||||
|
* Maxime Chambreuil <maxime.chambreuil@savoirfairelinux.com> |
||||
|
""", |
||||
|
'author': 'Daniel Reis', |
||||
|
'website': 'http://launchpad.net/addons-tko', |
||||
|
'images': [ |
||||
|
'images/snapshot1.png', |
||||
|
'images/snapshot2.png', |
||||
|
], |
||||
|
'depends': [ |
||||
|
'base', |
||||
|
'base_external_dbsource', |
||||
|
], |
||||
|
'data': [ |
||||
|
'import_odbc_view.xml', |
||||
|
'security/ir.model.access.csv', |
||||
|
], |
||||
|
'demo': [ |
||||
|
'import_odbc_demo.xml', |
||||
|
], |
||||
|
'test': [], |
||||
|
'installable': False, |
||||
|
'active': False, |
||||
|
} |
||||
|
|
||||
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
After Width: 699 | Height: 475 | Size: 19 KiB |
After Width: 943 | Height: 348 | Size: 24 KiB |
@ -0,0 +1,216 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Daniel Reis |
||||
|
# 2011 |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
import sys |
||||
|
from datetime import datetime |
||||
|
from openerp.osv import orm, fields |
||||
|
import logging |
||||
|
_logger = logging.getLogger(__name__) |
||||
|
_loglvl = _logger.getEffectiveLevel() |
||||
|
SEP = '|' |
||||
|
|
||||
|
|
||||
|
class import_odbc_dbtable(orm.Model): |
||||
|
_name = "import.odbc.dbtable" |
||||
|
_description = 'Import Table Data' |
||||
|
_order = 'exec_order' |
||||
|
_columns = { |
||||
|
'name': fields.char('Datasource name', required=True, size=64), |
||||
|
'enabled': fields.boolean('Execution enabled'), |
||||
|
'dbsource_id': fields.many2one('base.external.dbsource', 'Database source', required=True), |
||||
|
'sql_source': fields.text('SQL', required=True, help='Column names must be valid "import_data" columns.'), |
||||
|
'model_target': fields.many2one('ir.model', 'Target object'), |
||||
|
'noupdate': fields.boolean('No updates', help="Only create new records; disable updates to existing records."), |
||||
|
'exec_order': fields.integer('Execution order', help="Defines the order to perform the import"), |
||||
|
'last_sync': fields.datetime('Last sync date', |
||||
|
help="Datetime for the last succesfull sync." |
||||
|
"\nLater changes on the source may not be replicated on the destination"), |
||||
|
'start_run': fields.datetime('Time started', readonly=True), |
||||
|
'last_run': fields.datetime('Time ended', readonly=True), |
||||
|
'last_record_count': fields.integer('Last record count', readonly=True), |
||||
|
'last_error_count': fields.integer('Last error count', readonly=True), |
||||
|
'last_warn_count': fields.integer('Last warning count', readonly=True), |
||||
|
'last_log': fields.text('Last run log', readonly=True), |
||||
|
'ignore_rel_errors': fields.boolean('Ignore relationship errors', |
||||
|
help="On error try to reimport rows ignoring relationships."), |
||||
|
'raise_import_errors': fields.boolean('Raise import errors', |
||||
|
help="Import errors not handled, intended for debugging purposes." |
||||
|
"\nAlso forces debug messages to be written to the server log."), |
||||
|
} |
||||
|
_defaults = { |
||||
|
'enabled': True, |
||||
|
'exec_order': 10, |
||||
|
} |
||||
|
|
||||
|
def _import_data(self, cr, uid, flds, data, model_obj, table_obj, log): |
||||
|
"""Import data and returns error msg or empty string""" |
||||
|
|
||||
|
def find_m2o(field_list): |
||||
|
""""Find index of first column with a one2many field""" |
||||
|
for i, x in enumerate(field_list): |
||||
|
if len(x) > 3 and x[-3:] == ':id' or x[-3:] == '/id': |
||||
|
return i |
||||
|
return -1 |
||||
|
|
||||
|
def append_to_log(log, level, obj_id='', msg='', rel_id=''): |
||||
|
if '_id_' in obj_id: |
||||
|
obj_id = '.'.join(obj_id.split('_')[:-2]) + ': ' + obj_id.split('_')[-1] |
||||
|
if ': .' in msg and not rel_id: |
||||
|
rel_id = msg[msg.find(': .')+3:] |
||||
|
if '_id_' in rel_id: |
||||
|
rel_id = '.'.join(rel_id.split('_')[:-2]) + ': ' + rel_id.split('_')[-1] |
||||
|
msg = msg[:msg.find(': .')] |
||||
|
log['last_log'].append('%s|%s\t|%s\t|%s' % (level.ljust(5), obj_id, rel_id, msg)) |
||||
|
_logger.debug(data) |
||||
|
cols = list(flds) # copy to avoid side effects |
||||
|
errmsg = str() |
||||
|
if table_obj.raise_import_errors: |
||||
|
model_obj.import_data(cr, uid, cols, [data], noupdate=table_obj.noupdate) |
||||
|
else: |
||||
|
try: |
||||
|
model_obj.import_data(cr, uid, cols, [data], noupdate=table_obj.noupdate) |
||||
|
except: |
||||
|
errmsg = str(sys.exc_info()[1]) |
||||
|
if errmsg and not table_obj.ignore_rel_errors: |
||||
|
# Fail |
||||
|
append_to_log(log, 'ERROR', data, errmsg) |
||||
|
log['last_error_count'] += 1 |
||||
|
return False |
||||
|
if errmsg and table_obj.ignore_rel_errors: |
||||
|
# Warn and retry ignoring many2one fields... |
||||
|
append_to_log(log, 'WARN', data, errmsg) |
||||
|
log['last_warn_count'] += 1 |
||||
|
# Try ignoring each many2one (tip: in the SQL sentence select more problematic FKs first) |
||||
|
i = find_m2o(cols) |
||||
|
if i >= 0: |
||||
|
# Try again without the [i] column |
||||
|
del cols[i] |
||||
|
del data[i] |
||||
|
self._import_data(cr, uid, cols, data, model_obj, table_obj, log) |
||||
|
else: |
||||
|
# Fail |
||||
|
append_to_log(log, 'ERROR', data, 'Removed all m2o keys and still fails.') |
||||
|
log['last_error_count'] += 1 |
||||
|
return False |
||||
|
return True |
||||
|
|
||||
|
def import_run(self, cr, uid, ids=None, context=None): |
||||
|
db_model = self.pool.get('base.external.dbsource') |
||||
|
actions = self.read(cr, uid, ids, ['id', 'exec_order']) |
||||
|
actions.sort(key=lambda x: (x['exec_order'], x['id'])) |
||||
|
|
||||
|
# Consider each dbtable: |
||||
|
for action_ref in actions: |
||||
|
obj = self.browse(cr, uid, action_ref['id']) |
||||
|
if not obj.enabled: |
||||
|
continue # skip |
||||
|
|
||||
|
_logger.setLevel(obj.raise_import_errors and logging.DEBUG or _loglvl) |
||||
|
_logger.debug('Importing %s...' % obj.name) |
||||
|
|
||||
|
# now() microseconds are stripped to avoid problem with SQL smalldate |
||||
|
# TODO: convert UTC Now to local timezone |
||||
|
# http://stackoverflow.com/questions/4770297/python-convert-utc-datetime-string-to-local-datetime |
||||
|
model_name = obj.model_target.model |
||||
|
model_obj = self.pool.get(model_name) |
||||
|
xml_prefix = model_name.replace('.', '_') + "_id_" |
||||
|
log = {'start_run': datetime.now().replace(microsecond=0), |
||||
|
'last_run': None, |
||||
|
'last_record_count': 0, |
||||
|
'last_error_count': 0, |
||||
|
'last_warn_count': 0, |
||||
|
'last_log': list()} |
||||
|
self.write(cr, uid, [obj.id], log) |
||||
|
|
||||
|
# Prepare SQL sentence; replace "%s" with the last_sync date |
||||
|
if obj.last_sync: |
||||
|
sync = datetime.strptime(obj.last_sync, "%Y-%m-%d %H:%M:%S") |
||||
|
else: |
||||
|
sync = datetime.datetime(1900, 1, 1, 0, 0, 0) |
||||
|
params = {'sync': sync} |
||||
|
res = db_model.execute(cr, uid, [obj.dbsource_id.id], |
||||
|
obj.sql_source, params, metadata=True) |
||||
|
|
||||
|
# Exclude columns titled "None"; add (xml_)"id" column |
||||
|
cidx = [i for i, x in enumerate(res['cols']) if x.upper() != 'NONE'] |
||||
|
cols = [x for i, x in enumerate(res['cols']) if x.upper() != 'NONE'] + ['id'] |
||||
|
|
||||
|
# Import each row: |
||||
|
for row in res['rows']: |
||||
|
# Build data row; import only columns present in the "cols" list |
||||
|
data = list() |
||||
|
for i in cidx: |
||||
|
# TODO: Handle imported datetimes properly - convert from localtime to UTC! |
||||
|
v = row[i] |
||||
|
if isinstance(v, str): |
||||
|
v = v.strip() |
||||
|
data.append(v) |
||||
|
data.append(xml_prefix + str(row[0]).strip()) |
||||
|
|
||||
|
# Import the row; on error, write line to the log |
||||
|
log['last_record_count'] += 1 |
||||
|
self._import_data(cr, uid, cols, data, model_obj, obj, log) |
||||
|
if log['last_record_count'] % 500 == 0: |
||||
|
_logger.info('...%s rows processed...' % (log['last_record_count'])) |
||||
|
|
||||
|
# Finished importing all rows |
||||
|
# If no errors, write new sync date |
||||
|
if not (log['last_error_count'] or log['last_warn_count']): |
||||
|
log['last_sync'] = log['start_run'] |
||||
|
level = logging.DEBUG |
||||
|
if log['last_warn_count']: |
||||
|
level = logging.WARN |
||||
|
if log['last_error_count']: |
||||
|
level = logging.ERROR |
||||
|
_logger.log(level, 'Imported %s , %d rows, %d errors, %d warnings.' % ( |
||||
|
model_name, log['last_record_count'], log['last_error_count'], |
||||
|
log['last_warn_count'])) |
||||
|
# Write run log, either if the table import is active or inactive |
||||
|
if log['last_log']: |
||||
|
log['last_log'].insert(0, 'LEVEL|== Line == |== Relationship ==|== Message ==') |
||||
|
log.update({'last_log': '\n'.join(log['last_log'])}) |
||||
|
log.update({'last_run': datetime.now().replace(microsecond=0)}) |
||||
|
self.write(cr, uid, [obj.id], log) |
||||
|
|
||||
|
# Finished |
||||
|
_logger.debug('Import job FINISHED.') |
||||
|
return True |
||||
|
|
||||
|
def import_schedule(self, cr, uid, ids, context=None): |
||||
|
cron_obj = self.pool.get('ir.cron') |
||||
|
new_create_id = cron_obj.create(cr, uid, { |
||||
|
'name': 'Import ODBC tables', |
||||
|
'interval_type': 'hours', |
||||
|
'interval_number': 1, |
||||
|
'numbercall': -1, |
||||
|
'model': 'import.odbc.dbtable', |
||||
|
'function': 'import_run', |
||||
|
'doall': False, |
||||
|
'active': True |
||||
|
}) |
||||
|
return { |
||||
|
'name': 'Import ODBC tables', |
||||
|
'view_type': 'form', |
||||
|
'view_mode': 'form,tree', |
||||
|
'res_model': 'ir.cron', |
||||
|
'res_id': new_create_id, |
||||
|
'type': 'ir.actions.act_window', |
||||
|
} |
@ -0,0 +1,15 @@ |
|||||
|
<?xml version="1.0"?> |
||||
|
<openerp> |
||||
|
<data> |
||||
|
|
||||
|
<record model="import.odbc.dbtable" id="demo_postgresql_users"> |
||||
|
<field name="name">Users from PostgreSQL </field> |
||||
|
<field name="dbsource_id" ref="base_external_dbsource.demo_postgre"/> |
||||
|
<field name="sql_source">select usename as "login", usename as "name" from pg_catalog.pg_user</field> |
||||
|
<field name="model_target" ref="base.model_res_users"/> |
||||
|
</record> |
||||
|
|
||||
|
</data> |
||||
|
</openerp> |
||||
|
|
||||
|
|
@ -0,0 +1,90 @@ |
|||||
|
<?xml version="1.0"?> |
||||
|
<openerp> |
||||
|
<data> |
||||
|
|
||||
|
<!-- Table form --> |
||||
|
|
||||
|
<record model="ir.ui.view" id="view_import_dbtable_form"> |
||||
|
<field name="name">import.odbc.dbtable.form</field> |
||||
|
<field name="model">import.odbc.dbtable</field> |
||||
|
<field name="type">form</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<form string="Table"> |
||||
|
<field name="name" search="1"/> |
||||
|
<field name="exec_order"/> |
||||
|
<field name="model_target"/> |
||||
|
<field name="dbsource_id" search="1"/> |
||||
|
<field name="noupdate"/> |
||||
|
<field name="enabled"/> |
||||
|
<field name="ignore_rel_errors"/> |
||||
|
<field name="raise_import_errors"/> |
||||
|
<field name="last_sync"/> |
||||
|
<group colspan="2"> |
||||
|
<button name="import_run" string="Run Import" type="object" icon="gtk-execute"/> |
||||
|
<button name="import_schedule" string="Schedule Import" type="object" icon="gtk-paste"/> |
||||
|
</group> |
||||
|
<field name="sql_source" colspan="4"/> |
||||
|
<separator string="Last execution" colspan="4"/> |
||||
|
<field name="last_record_count"/> |
||||
|
<field name="start_run"/> |
||||
|
<field name="last_warn_count"/> |
||||
|
<field name="last_run"/> |
||||
|
<field name="last_error_count"/> |
||||
|
<field name="last_log" colspan="4"/> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<!-- Table Tree --> |
||||
|
|
||||
|
<record id="view_import_dbtable_tree" model="ir.ui.view"> |
||||
|
<field name="name">import.odbc.dbtable.tree</field> |
||||
|
<field name="model">import.odbc.dbtable</field> |
||||
|
<field name="type">tree</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<tree string="Tables" colors="grey: enabled==False; red:last_error_count>0; blue:last_warn_count>0"> |
||||
|
<field name="exec_order"/> |
||||
|
<field name="name"/> |
||||
|
<field name="model_target"/> |
||||
|
<field name="dbsource_id"/> |
||||
|
<field name="enabled"/> |
||||
|
<field name="last_run"/> |
||||
|
<field name="last_sync"/> |
||||
|
<field name="last_record_count"/> |
||||
|
<field name="last_error_count"/> |
||||
|
<field name="last_warn_count"/> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<!-- Tree Search --> |
||||
|
<record id="view_import_dbtable_filter" model="ir.ui.view"> |
||||
|
<field name="name">import.odbc.dbtable.filter</field> |
||||
|
<field name="model">import.odbc.dbtable</field> |
||||
|
<field name="type">search</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<search string="Search ODBC Imports"> |
||||
|
<field name="name"/> |
||||
|
<field name="dbsource_id"/> |
||||
|
<field name="model_target"/> |
||||
|
</search> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<!--Menu--> |
||||
|
<record model="ir.actions.act_window" id="action_import_dbtable"> |
||||
|
<field name="name">Import from SQL</field> |
||||
|
<field name="res_model">import.odbc.dbtable</field> |
||||
|
<field name="view_type">form</field> |
||||
|
</record> |
||||
|
|
||||
|
<menuitem name="Import from SQL" |
||||
|
id="menu_import_dbtable" |
||||
|
parent="base.next_id_9" |
||||
|
action="action_import_dbtable"/> |
||||
|
|
||||
|
</data> |
||||
|
</openerp> |
||||
|
|
||||
|
|
||||
|
|
@ -0,0 +1,2 @@ |
|||||
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink |
||||
|
access_import_odbc_dbsource_group_system,import_odbc_dbtable_group_system,model_import_odbc_dbtable,base.group_system,1,1,1,1 |
@ -0,0 +1,20 @@ |
|||||
|
# -*- encoding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Author Nicolas Bessi. Copyright Camptocamp SA |
||||
|
############################################################################## |
||||
|
{'name': 'Ir.config_parameter view', |
||||
|
'version': '0.1', |
||||
|
'category': 'Tools', |
||||
|
'description': """ |
||||
|
Create view to inspect/change technical parameters |
||||
|
""", |
||||
|
'author': 'Camptocamp', |
||||
|
'website': 'http://openerp.camptocamp.com', |
||||
|
'depends': ['base'], |
||||
|
'init_xml': [], |
||||
|
'update_xml': ['ir_config_parameter_view.xml'], |
||||
|
'demo_xml': [], |
||||
|
'installable': False, |
||||
|
'auto_install': False} |
||||
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
@ -0,0 +1,16 @@ |
|||||
|
# Translation of OpenERP Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: OpenERP Server 7.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2014-03-14 17:41+0000\n" |
||||
|
"PO-Revision-Date: 2014-03-14 17:41+0000\n" |
||||
|
"Last-Translator: <>\n" |
||||
|
"Language-Team: \n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Plural-Forms: \n" |
||||
|
|
@ -0,0 +1,36 @@ |
|||||
|
<openerp> |
||||
|
<data> |
||||
|
<record model="ir.ui.view" id="view_config_list"> |
||||
|
<field name="name">ir.config_parameter.list</field> |
||||
|
<field name="model">ir.config_parameter</field> |
||||
|
<field name="priority" eval="6"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<tree string="Technical configuration parameters"> |
||||
|
<field name="key" select="1"/> |
||||
|
<field name="value" select="1" /> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</record> |
||||
|
<record model="ir.ui.view" id="view_config_form"> |
||||
|
<field name="name">ir.config_parameter.form</field> |
||||
|
<field name="model">ir.config_parameter</field> |
||||
|
<field name="priority" eval="6"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<form string="Technical configuration parameters"> |
||||
|
<field name="key" select="1"/> |
||||
|
<field name="value" select="1" /> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
<record id="view_config_action" model="ir.actions.act_window"> |
||||
|
<field name="name">Technical config parameters</field> |
||||
|
<field name="type">ir.actions.act_window</field> |
||||
|
<field name="res_model">ir.config_parameter</field> |
||||
|
<field name="view_type">form</field> |
||||
|
<field name="view_id" ref="view_config_list"/> |
||||
|
</record> |
||||
|
|
||||
|
<menuitem name="Technical config parameters" id="technical_config_parameters" |
||||
|
parent="base.next_id_15" action="view_config_action" groups="base.group_extended"/> |
||||
|
</data> |
||||
|
</openerp> |
@ -0,0 +1 @@ |
|||||
|
from . import env_mail |
@ -0,0 +1,68 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Author: Nicolas Bessi |
||||
|
# Copyright 2012 Camptocamp SA |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
{ |
||||
|
'name': 'Server env config for mail + fetchmail', |
||||
|
'version': '0.1', |
||||
|
'category': 'Tools', |
||||
|
'description': """ |
||||
|
Extend mail and fetch mail with server environment module. |
||||
|
|
||||
|
In config files, sections outgoint_mail and incoming_mails are default values |
||||
|
for all Outgoing Mail Servers and Fetchmail Servers. |
||||
|
For each server, you can (re)define values with a section named |
||||
|
"outgoing_mail.resource_name" where resource_name is the name of your server. |
||||
|
|
||||
|
Exemple of config file : |
||||
|
|
||||
|
[outgoing_mail] |
||||
|
smtp_host = smtp.myserver.com |
||||
|
smtp_port = 587 |
||||
|
smtp_user = |
||||
|
smtp_pass = |
||||
|
smtp_encryption = ssl |
||||
|
|
||||
|
[outgoing_mail.openerp_smtp_server1] |
||||
|
smtp_user = openerp |
||||
|
smtp_pass = openerp |
||||
|
|
||||
|
[incoming_mail.openerp_pop_mail1] |
||||
|
server = mail.myserver.com |
||||
|
port = 110 |
||||
|
type = pop |
||||
|
is_ssl = 0 |
||||
|
attach = 0 |
||||
|
original = 0 |
||||
|
user = openerp@myserver.com |
||||
|
password = openerp |
||||
|
|
||||
|
|
||||
|
""", |
||||
|
'author': 'Camptocamp', |
||||
|
'license': 'AGPL-3', |
||||
|
'website': 'http://openerp.camptocamp.com', |
||||
|
'depends': ['mail', 'fetchmail', 'server_environment', 'server_environment_files', 'crm'], |
||||
|
'init_xml': [], |
||||
|
'update_xml': ['mail_view.xml'], |
||||
|
'demo_xml': [], |
||||
|
'installable': False, |
||||
|
'active': False, |
||||
|
} |
@ -0,0 +1,225 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Author: Nicolas Bessi |
||||
|
# Copyright 2012 Camptocamp SA |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
from osv import fields |
||||
|
from osv import osv |
||||
|
|
||||
|
from server_environment import serv_config |
||||
|
|
||||
|
|
||||
|
class IrMail(osv.osv): |
||||
|
_inherit = "ir.mail_server" |
||||
|
|
||||
|
def _get_smtp_conf(self, cursor, uid, ids, name, args, context=None): |
||||
|
""" |
||||
|
Return configuration |
||||
|
""" |
||||
|
res = {} |
||||
|
for mail_server in self.browse(cursor, uid, ids): |
||||
|
global_section_name = 'outgoing_mail' |
||||
|
|
||||
|
# default vals |
||||
|
config_vals = {'smtp_port': 587} |
||||
|
if serv_config.has_section(global_section_name): |
||||
|
config_vals.update((serv_config.items(global_section_name))) |
||||
|
|
||||
|
custom_section_name = '.'.join((global_section_name, mail_server.name)) |
||||
|
if serv_config.has_section(custom_section_name): |
||||
|
config_vals.update(serv_config.items(custom_section_name)) |
||||
|
|
||||
|
if config_vals.get('smtp_port'): |
||||
|
config_vals['smtp_port'] = int(config_vals['smtp_port']) |
||||
|
|
||||
|
res[mail_server.id] = config_vals |
||||
|
return res |
||||
|
|
||||
|
_columns = { |
||||
|
'smtp_host': fields.function( |
||||
|
_get_smtp_conf, |
||||
|
method=True, |
||||
|
string='SMTP Server', |
||||
|
type="char", |
||||
|
multi='outgoing_mail_config', |
||||
|
size=128), |
||||
|
'smtp_port': fields.function( |
||||
|
_get_smtp_conf, |
||||
|
method=True, |
||||
|
string='SMTP Port', |
||||
|
type="integer", |
||||
|
multi='outgoing_mail_config', |
||||
|
help="SMTP Port. Usually 465 for SSL, and 25 or 587 for other cases.", |
||||
|
size=5), |
||||
|
'smtp_user': fields.function( |
||||
|
_get_smtp_conf, |
||||
|
method=True, |
||||
|
string='Username', |
||||
|
type="char", |
||||
|
multi='outgoing_mail_config', |
||||
|
help="Optional username for SMTP authentication", |
||||
|
size=64), |
||||
|
'smtp_pass': fields.function( |
||||
|
_get_smtp_conf, |
||||
|
method=True, |
||||
|
string='Password', |
||||
|
type="char", |
||||
|
multi='outgoing_mail_config', |
||||
|
help="Optional password for SMTP authentication", |
||||
|
size=64), |
||||
|
'smtp_encryption': fields.function( |
||||
|
_get_smtp_conf, |
||||
|
method=True, |
||||
|
string='smtp_encryption', |
||||
|
type="char", |
||||
|
multi='outgoing_mail_config', |
||||
|
help="Choose the connection encryption scheme:\n" |
||||
|
"- none: SMTP sessions are done in cleartext.\n" |
||||
|
"- starttls: TLS encryption is requested at start of SMTP session (Recommended)\n" |
||||
|
"- ssl: SMTP sessions are encrypted with SSL/TLS through a dedicated port (default: 465)", |
||||
|
size=64)} |
||||
|
|
||||
|
IrMail() |
||||
|
|
||||
|
|
||||
|
class FetchmailServer(osv.osv): |
||||
|
"""Incoming POP/IMAP mail server account""" |
||||
|
_inherit = 'fetchmail.server' |
||||
|
|
||||
|
def _get_incom_conf(self, cursor, uid, ids, name, args, context=None): |
||||
|
""" |
||||
|
Return configuration |
||||
|
""" |
||||
|
res = {} |
||||
|
for fetchmail in self.browse(cursor, uid, ids): |
||||
|
global_section_name = 'incoming_mail' |
||||
|
|
||||
|
key_types = {'port': int, |
||||
|
'is_ssl': lambda a: bool(int(a)), |
||||
|
'attach': lambda a: bool(int(a)), |
||||
|
'original': lambda a: bool(int(a)), |
||||
|
} |
||||
|
|
||||
|
# default vals |
||||
|
config_vals = {'port': 993, |
||||
|
'is_ssl': 0, |
||||
|
'attach': 0, |
||||
|
'original': 0, |
||||
|
} |
||||
|
if serv_config.has_section(global_section_name): |
||||
|
config_vals.update(serv_config.items(global_section_name)) |
||||
|
|
||||
|
custom_section_name = '.'.join((global_section_name, fetchmail.name)) |
||||
|
if serv_config.has_section(custom_section_name): |
||||
|
config_vals.update(serv_config.items(custom_section_name)) |
||||
|
|
||||
|
for key, to_type in key_types.iteritems(): |
||||
|
if config_vals.get(key): |
||||
|
config_vals[key] = to_type(config_vals[key]) |
||||
|
res[fetchmail.id] = config_vals |
||||
|
return res |
||||
|
|
||||
|
def _type_search(self, cr, uid, obj, name, args, context={}): |
||||
|
result_ids = [] |
||||
|
# read all incomming servers values |
||||
|
all_ids = self.search(cr, uid, [], context=context) |
||||
|
results = self.read(cr, uid, all_ids, ['id', 'type'], context=context) |
||||
|
args = args[:] |
||||
|
i = 0 |
||||
|
while i < len(args): |
||||
|
operator = args[i][1] |
||||
|
if operator == '=': |
||||
|
for res in results: |
||||
|
if (res['type'] == args[i][2]) and (res['id'] not in result_ids): |
||||
|
result_ids.append(res['id']) |
||||
|
elif operator == 'in': |
||||
|
for search_vals in args[i][2]: |
||||
|
for res in results: |
||||
|
if (res['type'] == search_vals) and (res['id'] not in result_ids): |
||||
|
result_ids.append(res['id']) |
||||
|
else: |
||||
|
continue |
||||
|
i += 1 |
||||
|
return [('id', 'in', result_ids)] |
||||
|
|
||||
|
_columns = { |
||||
|
'server': fields.function( |
||||
|
_get_incom_conf, |
||||
|
method=True, |
||||
|
string='Server', |
||||
|
type="char", |
||||
|
multi='income_mail_config', |
||||
|
size=256, help="Hostname or IP of the mail server"), |
||||
|
'port': fields.function( |
||||
|
_get_incom_conf, |
||||
|
method=True, |
||||
|
string='Port', |
||||
|
type="integer", |
||||
|
multi='income_mail_config', |
||||
|
help="Hostname or IP of the mail server"), |
||||
|
'type': fields.function( |
||||
|
_get_incom_conf, |
||||
|
method=True, |
||||
|
string='Type', |
||||
|
type="char", |
||||
|
multi='income_mail_config', |
||||
|
fnct_search=_type_search, |
||||
|
size=64, |
||||
|
help="pop, imap, local"), |
||||
|
'is_ssl': fields.function( |
||||
|
_get_incom_conf, |
||||
|
method=True, |
||||
|
string='Is SSL', |
||||
|
type="boolean", |
||||
|
multi='income_mail_config', |
||||
|
help='Connections are encrypted with SSL/TLS through' |
||||
|
' a dedicated port (default: IMAPS=993, POP3S=995)'), |
||||
|
'attach': fields.function( |
||||
|
_get_incom_conf, |
||||
|
method=True, |
||||
|
string='Keep Attachments', |
||||
|
type="boolean", |
||||
|
multi='income_mail_config', |
||||
|
help="Whether attachments should be downloaded. " |
||||
|
"If not enabled, incoming emails will be stripped of any " |
||||
|
"attachments before being processed"), |
||||
|
'original': fields.function( |
||||
|
_get_incom_conf, |
||||
|
method=True, |
||||
|
string='Keep Original', |
||||
|
type="boolean", |
||||
|
multi='income_mail_config', |
||||
|
help="Whether a full original copy of each email should be kept " |
||||
|
"for reference and attached to each processed message. This " |
||||
|
"will usually double the size of your message database."), |
||||
|
'user': fields.function( |
||||
|
_get_incom_conf, |
||||
|
method=True, |
||||
|
string='Username', |
||||
|
type="char", |
||||
|
multi='income_mail_config', |
||||
|
size=64), |
||||
|
'password': fields.function( |
||||
|
_get_incom_conf, |
||||
|
method=True, |
||||
|
string='password', |
||||
|
type="char", |
||||
|
multi='income_mail_config', |
||||
|
size=64)} |
||||
|
FetchmailServer() |
@ -0,0 +1,16 @@ |
|||||
|
# Translation of OpenERP Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: OpenERP Server 7.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2014-03-14 17:41+0000\n" |
||||
|
"PO-Revision-Date: 2014-03-14 17:41+0000\n" |
||||
|
"Last-Translator: <>\n" |
||||
|
"Language-Team: \n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Plural-Forms: \n" |
||||
|
|
@ -0,0 +1,27 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<openerp> |
||||
|
<data> |
||||
|
<record model="ir.ui.view" id="inherit_fetchmail"> |
||||
|
<!-- must be unique in this module. --> |
||||
|
<field name="name">inherit_fetchmail_for_env_support</field> |
||||
|
<field name="model">fetchmail.server</field> |
||||
|
<!--parent python entity --> |
||||
|
<field name="inherit_id" ref="fetchmail.view_email_server_form"/> |
||||
|
<!-- modulename.view --> |
||||
|
<field name="arch" type="xml"> |
||||
|
<field name="server" attrs="{'required' : [('type', '!=', 'local')]}" position="replace"> |
||||
|
<field name="server" /> |
||||
|
</field> |
||||
|
<field name="port" attrs="{'required' : [('type', '!=', 'local')]}" position="replace"> |
||||
|
<field name="port" /> |
||||
|
</field> |
||||
|
<field name="user" attrs="{'required' : [('type', '!=', 'local')]}" position="replace"> |
||||
|
<field name="user" /> |
||||
|
</field> |
||||
|
<field name="password" attrs="{'required' : [('type', '!=', 'local')]}" position="replace"> |
||||
|
<field name="password" /> |
||||
|
</field> |
||||
|
</field> |
||||
|
</record> |
||||
|
</data> |
||||
|
</openerp> |
@ -0,0 +1 @@ |
|||||
|
from . import security_protector |
@ -0,0 +1,25 @@ |
|||||
|
# -*- encoding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Author Nicolas Bessi. Copyright Camptocamp SA |
||||
|
############################################################################## |
||||
|
{'name': 'Security protector', |
||||
|
'version': '0.1', |
||||
|
'category': 'Tools', |
||||
|
'description': """ |
||||
|
Prevent security to be changed when module is updated |
||||
|
This module overwrite ir model acces write delete function. |
||||
|
Only acces edited trough the UI or with manual_security_override in context set to True will be altered. |
||||
|
When you try to delete a acces write it simply set all perms to false |
||||
|
you can deactivate this behavior in ir.config_parameter by chanching the protect_security? key to 0 |
||||
|
""", |
||||
|
'author': 'Camptocamp', |
||||
|
'website': 'http://openerp.camptocamp.com', |
||||
|
'depends': ['base'], |
||||
|
'init_xml': ['data.xml'], |
||||
|
'update_xml': ['security_view.xml'], |
||||
|
'demo_xml': [], |
||||
|
'installable': False, |
||||
|
'auto_install': False, |
||||
|
} |
||||
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
@ -0,0 +1,8 @@ |
|||||
|
<openerp> |
||||
|
<data noupdate="1"> |
||||
|
<record id="security_protector_config_param" model="ir.config_parameter"> |
||||
|
<field name="key">protect_security?</field> |
||||
|
<field name="value">1</field> |
||||
|
</record> |
||||
|
</data> |
||||
|
</openerp> |
@ -0,0 +1,16 @@ |
|||||
|
# Translation of OpenERP Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: OpenERP Server 7.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2014-03-14 17:41+0000\n" |
||||
|
"PO-Revision-Date: 2014-03-14 17:41+0000\n" |
||||
|
"Last-Translator: <>\n" |
||||
|
"Language-Team: \n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Plural-Forms: \n" |
||||
|
|
@ -0,0 +1,47 @@ |
|||||
|
# -*- encoding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Author Nicolas Bessi. Copyright Camptocamp SA |
||||
|
############################################################################## |
||||
|
from osv import fields, osv |
||||
|
|
||||
|
class IrModelAccess(osv.osv): |
||||
|
"We inherit ir model access to add specific write unlink and copy behavior" |
||||
|
_name = 'ir.model.access' |
||||
|
_inherit = "ir.model.access" |
||||
|
|
||||
|
def _acces_can_be_modified(self, cr, uid, context=None): |
||||
|
context = context or {} |
||||
|
on = self.pool.get('ir.config_parameter').get_param(cr, uid, 'protect_security?', default=False, context=context) |
||||
|
if on in (1, "1", "YES", True): |
||||
|
if context.get('manual_security_override', False): |
||||
|
return True |
||||
|
return False |
||||
|
|
||||
|
else: |
||||
|
return True |
||||
|
|
||||
|
def write(self, cr, uid, ids, vals, context=None): |
||||
|
res =True |
||||
|
context = context or {} |
||||
|
if self._acces_can_be_modified(cr, uid, context=context): |
||||
|
res = super(IrModelAccess, self).write(cr, uid, ids, vals, context=context) |
||||
|
return res |
||||
|
|
||||
|
|
||||
|
def unlink(self, cr, uid, ids, context=None): |
||||
|
res = True |
||||
|
context = context or {} |
||||
|
# I'm note sur about this one maybe we should do nothing |
||||
|
if self._acces_can_be_modified(cr, uid, context=context): |
||||
|
vals = {'perm_read':False, |
||||
|
'perm_write': False, |
||||
|
'perm_unlink': False, |
||||
|
'perm_create': False} |
||||
|
super(IrModelAccess, self).write(cr, uid, ids, vals, context=context) |
||||
|
else: |
||||
|
res = super(IrModelAccess, self).unlink(cr, uid, ids, context=context) |
||||
|
|
||||
|
return res |
||||
|
|
||||
|
IrModelAccess() |
@ -0,0 +1,8 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<openerp> |
||||
|
<data> |
||||
|
<record id="base.ir_access_act" model="ir.actions.act_window"> |
||||
|
<field name="context">{'manual_security_override': 1}</field> |
||||
|
</record> |
||||
|
</data> |
||||
|
</openerp> |
@ -0,0 +1,22 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Author: Guewen Baconnier |
||||
|
# Copyright 2012 Camptocamp SA |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
import base_external_referentials |
@ -0,0 +1,47 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Author: Guewen Baconnier |
||||
|
# Copyright 2011-2012 Camptocamp SA |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
{ |
||||
|
"name": "Server environment for base_external_referential", |
||||
|
"version": "1.0", |
||||
|
"depends": ["base", 'server_environment', 'base_external_referentials'], |
||||
|
"author": "Camptocamp", |
||||
|
'license': 'AGPL-3', |
||||
|
"description": """This module is based on the server_environment module to use files for configuration. |
||||
|
Thus we can have a different file for each environment (dev, test, staging, prod). |
||||
|
This module define the config variables for the base_external_referential module. |
||||
|
In the configuration file, you can configure the url, login and password of the referentials |
||||
|
|
||||
|
Exemple of the section to put in the configuration file : |
||||
|
|
||||
|
[external_referential.name_of_my_external_referential] |
||||
|
location = http://localhost/magento/ |
||||
|
apiusername = my_api_login |
||||
|
apipass = my_api_password |
||||
|
""", |
||||
|
"website": "http://www.camptocamp.com", |
||||
|
"category": "Tools", |
||||
|
"init_xml": [], |
||||
|
"demo_xml": [], |
||||
|
"update_xml": [], |
||||
|
"installable": False, |
||||
|
"active": False, |
||||
|
} |
@ -0,0 +1,54 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Author: Guewen Baconnier |
||||
|
# Copyright 2011-2012 Camptocamp SA |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
from osv import fields, osv |
||||
|
from server_environment import serv_config |
||||
|
import logging |
||||
|
|
||||
|
|
||||
|
|
||||
|
class external_referential(osv.osv): |
||||
|
_inherit = 'external.referential' |
||||
|
|
||||
|
def _get_environment_config_by_name(self, cr, uid, ids, field_names, arg, context): |
||||
|
values = {} |
||||
|
for referential in self.browse(cr, uid, ids, context): |
||||
|
values[referential.id] = {} |
||||
|
for field_name in field_names: |
||||
|
section_name = '.'.join((self._name.replace('.', '_'), referential.name)) |
||||
|
try: |
||||
|
value = serv_config.get(section_name, field_name) |
||||
|
values[referential.id].update({field_name: value}) |
||||
|
except: |
||||
|
logger = logging.getLogger(__name__) |
||||
|
logger.exception('error trying to read field %s in section %s', field_name, section_name) |
||||
|
return values |
||||
|
|
||||
|
_columns = { |
||||
|
'location': fields.function(_get_environment_config_by_name, type='char', size=200, |
||||
|
method=True, string='Location', multi='connection_config'), |
||||
|
'apiusername': fields.function(_get_environment_config_by_name, type='char', size=64, |
||||
|
method=True, string='User Name', multi='connection_config'), |
||||
|
'apipass': fields.function(_get_environment_config_by_name, type='char', size=64, |
||||
|
method=True, string='Password', multi='connection_config'), |
||||
|
} |
||||
|
|
||||
|
external_referential() |
@ -0,0 +1,16 @@ |
|||||
|
# Translation of OpenERP Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: OpenERP Server 7.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2014-03-14 17:41+0000\n" |
||||
|
"PO-Revision-Date: 2014-03-14 17:41+0000\n" |
||||
|
"Last-Translator: <>\n" |
||||
|
"Language-Team: \n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Plural-Forms: \n" |
||||
|
|
@ -0,0 +1 @@ |
|||||
|
Lorenzo Battistini <lorenzo.battistini@agilebg.com> |
@ -0,0 +1,21 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Copyright (C) 2012 Agile Business Group sagl (<http://www.agilebg.com>) |
||||
|
# Copyright (C) 2012 Domsense srl (<http://www.domsense.com>) |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as published |
||||
|
# by the Free Software Foundation, either version 3 of the License, or |
||||
|
# (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
import super_calendar |
@ -0,0 +1,88 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Copyright (C) 2012 Agile Business Group sagl (<http://www.agilebg.com>) |
||||
|
# Copyright (C) 2012 Domsense srl (<http://www.domsense.com>) |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as published |
||||
|
# by the Free Software Foundation, either version 3 of the License, or |
||||
|
# (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
{ |
||||
|
'name': "Super Calendar", |
||||
|
'version': '0.1', |
||||
|
'category': 'Generic Modules/Others', |
||||
|
'summary': 'This module allows to create configurable calendars.', |
||||
|
'description': """ |
||||
|
This module allows to create configurable calendars. |
||||
|
|
||||
|
Through the 'calendar configurator' object, you can specify which models have |
||||
|
to be merged in the super calendar. For each model, you have to define the |
||||
|
'description' and 'date_start' fields at least. Then you can define 'duration' |
||||
|
and the 'user_id' fields. |
||||
|
|
||||
|
The 'super.calendar' object contains the the merged calendars. The |
||||
|
'super.calendar' can be updated by 'ir.cron' or manually. |
||||
|
|
||||
|
Configuration |
||||
|
============= |
||||
|
|
||||
|
After installing the module you can go to |
||||
|
|
||||
|
Super calendar → Configuration → Configurators |
||||
|
|
||||
|
and create a new configurator. For instance, if you want to see meetings and |
||||
|
phone calls, you can create the following lines |
||||
|
|
||||
|
.. image:: http://planet.domsense.com/wp-content/uploads/2012/04/meetings.png |
||||
|
:width: 400 px |
||||
|
|
||||
|
.. image:: http://planet.domsense.com/wp-content/uploads/2012/04/phone_calls.png |
||||
|
:width: 400 px |
||||
|
|
||||
|
Then, you can use the ‘Generate Calendar’ button or wait for the scheduled |
||||
|
action (‘Generate Calendar Records’) to be run. |
||||
|
|
||||
|
When the calendar is generated, you can visualize it by the ‘super calendar’ main menu. |
||||
|
|
||||
|
Here is a sample monthly calendar: |
||||
|
|
||||
|
.. image:: http://planet.domsense.com/wp-content/uploads/2012/04/month_calendar.png |
||||
|
:width: 400 px |
||||
|
|
||||
|
And here is the weekly one: |
||||
|
|
||||
|
.. image:: http://planet.domsense.com/wp-content/uploads/2012/04/week_calendar.png |
||||
|
:width: 400 px |
||||
|
|
||||
|
As you can see, several filters are available. A typical usage consists in |
||||
|
filtering by ‘Configurator’ (if you have several configurators, |
||||
|
‘Scheduled calls and meetings’ can be one of them) and by your user. |
||||
|
Once you filtered, you can save the filter as ‘Advanced filter’ or even |
||||
|
add it to a dashboard. |
||||
|
""", |
||||
|
'author': 'Agile Business Group', |
||||
|
'website': 'http://www.agilebg.com', |
||||
|
'license': 'AGPL-3', |
||||
|
'depends': ['base'], |
||||
|
"data": [ |
||||
|
'super_calendar_view.xml', |
||||
|
'cron_data.xml', |
||||
|
'security/ir.model.access.csv', |
||||
|
], |
||||
|
'demo': [], |
||||
|
'test': [], |
||||
|
'installable': False, |
||||
|
'application': True, |
||||
|
'auto_install': False, |
||||
|
} |
@ -0,0 +1,15 @@ |
|||||
|
<?xml version="1.0"?> |
||||
|
<openerp> |
||||
|
<data noupdate="1"> |
||||
|
<record model="ir.cron" id="generate_calendar_records_cron"> |
||||
|
<field name="name">Generate Calendar Records</field> |
||||
|
<field name="interval_number">10</field> |
||||
|
<field name="interval_type">minutes</field> |
||||
|
<field name="numbercall">-1</field> |
||||
|
<field name="doall" eval="False"></field> |
||||
|
<field eval="'super.calendar.configurator'" name="model"/> |
||||
|
<field eval="'generate_calendar_records'" name="function"/> |
||||
|
<field eval="'[[],{}]'" name="args"/> |
||||
|
</record> |
||||
|
</data> |
||||
|
</openerp> |
@ -0,0 +1,212 @@ |
|||||
|
# Translation of OpenERP Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * super_calendar |
||||
|
# |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: OpenERP Server 7.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2014-03-14 17:41+0000\n" |
||||
|
"PO-Revision-Date: 2014-03-17 10:57+0000\n" |
||||
|
"Last-Translator: michele <michelemilidoni@gmail.com>\n" |
||||
|
"Language-Team: \n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: 8bit\n" |
||||
|
"X-Launchpad-Export-Date: 2014-05-24 06:46+0000\n" |
||||
|
"X-Generator: Launchpad (build 17017)\n" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar.configurator.line,duration_field_id:0 |
||||
|
msgid "Duration field" |
||||
|
msgstr "Campo durata" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: view:super.calendar.configurator:0 |
||||
|
msgid "Generate Calendar" |
||||
|
msgstr "Generazione calendario" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: selection:super.calendar.configurator.line,description_type:0 |
||||
|
msgid "Field" |
||||
|
msgstr "Campo" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: code:addons/super_calendar/super_calendar.py:61 |
||||
|
#, python-format |
||||
|
msgid "The 'User' field of record %s (%s) does not refer to res.users" |
||||
|
msgstr "Il campo 'Utente' del record %s (%s) non si riferisce a res.users" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar,date_start:0 |
||||
|
msgid "Start date" |
||||
|
msgstr "Data inizio" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar.configurator.line,user_field_id:0 |
||||
|
msgid "User field" |
||||
|
msgstr "Campo Utente" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar.configurator.line,description_type:0 |
||||
|
msgid "Description Type" |
||||
|
msgstr "Tipo di descrizione" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: model:_description:0 |
||||
|
#: model:ir.model,name:super_calendar.model_super_calendar_configurator |
||||
|
msgid "super.calendar.configurator" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar,name:0 |
||||
|
#: view:super.calendar.configurator:0 |
||||
|
#: field:super.calendar.configurator.line,description:0 |
||||
|
msgid "Description" |
||||
|
msgstr "Descrizione" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: model:ir.actions.act_window,name:super_calendar.super_calendar_configurator |
||||
|
msgid "Calendar Configurators" |
||||
|
msgstr "Configuratori Calendario" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar,model_description:0 |
||||
|
msgid "Model Description" |
||||
|
msgstr "Descrizione Modello" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar.configurator.line,date_start_field_id:0 |
||||
|
msgid "Start date field" |
||||
|
msgstr "Data inizio" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar,user_id:0 |
||||
|
msgid "User" |
||||
|
msgstr "Utente" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: model:ir.actions.act_window,name:super_calendar.super_calendar_action |
||||
|
#: model:ir.ui.menu,name:super_calendar.super_calendar_menu |
||||
|
msgid "Super Calendar" |
||||
|
msgstr "Super Calendario" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: view:super.calendar.configurator:0 |
||||
|
msgid "Line" |
||||
|
msgstr "Riga" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: view:super.calendar:0 |
||||
|
msgid "Extended Filters..." |
||||
|
msgstr "Filtri estesi..." |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar,res_id:0 |
||||
|
msgid "Resource" |
||||
|
msgstr "Risorsa" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar.configurator,name:0 |
||||
|
msgid "Name" |
||||
|
msgstr "Nome" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: model:ir.ui.menu,name:super_calendar.super_calendar_configurators |
||||
|
#: view:super.calendar.configurator:0 |
||||
|
msgid "Configurators" |
||||
|
msgstr "Configuratori" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: view:super.calendar.configurator:0 |
||||
|
#: field:super.calendar.configurator,line_ids:0 |
||||
|
msgid "Lines" |
||||
|
msgstr "Righe" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar.configurator.line,description_code:0 |
||||
|
#: field:super.calendar.configurator.line,description_field_id:0 |
||||
|
msgid "Description field" |
||||
|
msgstr "Campo descrizione" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: view:super.calendar.configurator:0 |
||||
|
#: help:super.calendar.configurator.line,description_code:0 |
||||
|
msgid "" |
||||
|
"Use '${o}' to refer to the involved object. E.g.: '${o.project_id.name}'" |
||||
|
msgstr "" |
||||
|
"Usare '${o}' per richiamare l'oggetto scelto. Esempio: '${o.project_id.name}'" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: code:addons/super_calendar/super_calendar.py:60 |
||||
|
#, python-format |
||||
|
msgid "Error" |
||||
|
msgstr "Errore" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar,model_id:0 |
||||
|
#: field:super.calendar.configurator.line,name:0 |
||||
|
msgid "Model" |
||||
|
msgstr "Modello" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: view:super.calendar:0 |
||||
|
#: field:super.calendar,configurator_id:0 |
||||
|
#: view:super.calendar.configurator:0 |
||||
|
#: field:super.calendar.configurator.line,configurator_id:0 |
||||
|
msgid "Configurator" |
||||
|
msgstr "Configuratore" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar.configurator.line,domain:0 |
||||
|
msgid "Domain" |
||||
|
msgstr "Domain" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: selection:super.calendar.configurator.line,description_type:0 |
||||
|
msgid "Code" |
||||
|
msgstr "Codice" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: model:_description:0 |
||||
|
#: model:ir.model,name:super_calendar.model_super_calendar_configurator_line |
||||
|
msgid "super.calendar.configurator.line" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: model:ir.ui.menu,name:super_calendar.super_calendar_configuration |
||||
|
msgid "Configuration" |
||||
|
msgstr "Configurazione" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: view:super.calendar:0 |
||||
|
msgid "My Items" |
||||
|
msgstr "I miei oggetti" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar.configurator.line,date_stop_field_id:0 |
||||
|
msgid "End date field" |
||||
|
msgstr "Campo data fine" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: model:_description:0 |
||||
|
#: model:ir.model,name:super_calendar.model_super_calendar |
||||
|
msgid "super.calendar" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: view:super.calendar:0 |
||||
|
msgid "Search Calendar" |
||||
|
msgstr "Ricerca Calendario" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar,duration:0 |
||||
|
msgid "Duration" |
||||
|
msgstr "Durata" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: model:ir.ui.menu,name:super_calendar.super_calendar_calendar |
||||
|
#: model:ir.ui.menu,name:super_calendar.super_calendar_calendar_calendar |
||||
|
#: view:super.calendar:0 |
||||
|
msgid "Calendar" |
||||
|
msgstr "Calendario" |
@ -0,0 +1,211 @@ |
|||||
|
# Translation of OpenERP Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * super_calendar |
||||
|
# |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: OpenERP Server 7.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2014-03-14 17:41+0000\n" |
||||
|
"PO-Revision-Date: 2014-03-17 10:57+0000\n" |
||||
|
"Last-Translator: michele <michelemilidoni@gmail.com>\n" |
||||
|
"Language-Team: \n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: 8bit\n" |
||||
|
"X-Launchpad-Export-Date: 2014-05-24 06:46+0000\n" |
||||
|
"X-Generator: Launchpad (build 17017)\n" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar.configurator.line,duration_field_id:0 |
||||
|
msgid "Duration field" |
||||
|
msgstr "Поле длительности" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: view:super.calendar.configurator:0 |
||||
|
msgid "Generate Calendar" |
||||
|
msgstr "Обновить календарь" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: selection:super.calendar.configurator.line,description_type:0 |
||||
|
msgid "Field" |
||||
|
msgstr "Поле" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: code:addons/super_calendar/super_calendar.py:61 |
||||
|
#, python-format |
||||
|
msgid "The 'User' field of record %s (%s) does not refer to res.users" |
||||
|
msgstr "Поле 'User' записи %s (%s) не ссылается на res.users" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar,date_start:0 |
||||
|
msgid "Start date" |
||||
|
msgstr "Дата начала" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar.configurator.line,user_field_id:0 |
||||
|
msgid "User field" |
||||
|
msgstr "Поле пользователя" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar.configurator.line,description_type:0 |
||||
|
msgid "Description Type" |
||||
|
msgstr "Тип описания" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: model:_description:0 |
||||
|
#: model:ir.model,name:super_calendar.model_super_calendar_configurator |
||||
|
msgid "super.calendar.configurator" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar,name:0 |
||||
|
#: view:super.calendar.configurator:0 |
||||
|
#: field:super.calendar.configurator.line,description:0 |
||||
|
msgid "Description" |
||||
|
msgstr "Описание" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: model:ir.actions.act_window,name:super_calendar.super_calendar_configurator |
||||
|
msgid "Calendar Configurators" |
||||
|
msgstr "Настройки календаря" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar,model_description:0 |
||||
|
msgid "Model Description" |
||||
|
msgstr "Описание" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar.configurator.line,date_start_field_id:0 |
||||
|
msgid "Start date field" |
||||
|
msgstr "Поле даты начала" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar,user_id:0 |
||||
|
msgid "User" |
||||
|
msgstr "Пользователь" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: model:ir.actions.act_window,name:super_calendar.super_calendar_action |
||||
|
#: model:ir.ui.menu,name:super_calendar.super_calendar_menu |
||||
|
msgid "Super Calendar" |
||||
|
msgstr "Календарь" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: view:super.calendar.configurator:0 |
||||
|
msgid "Line" |
||||
|
msgstr "Строка" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: view:super.calendar:0 |
||||
|
msgid "Extended Filters..." |
||||
|
msgstr "Расширенные фильтры..." |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar,res_id:0 |
||||
|
msgid "Resource" |
||||
|
msgstr "Ресурс" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar.configurator,name:0 |
||||
|
msgid "Name" |
||||
|
msgstr "Название" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: model:ir.ui.menu,name:super_calendar.super_calendar_configurators |
||||
|
#: view:super.calendar.configurator:0 |
||||
|
msgid "Configurators" |
||||
|
msgstr "Настройки" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: view:super.calendar.configurator:0 |
||||
|
#: field:super.calendar.configurator,line_ids:0 |
||||
|
msgid "Lines" |
||||
|
msgstr "Строки" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar.configurator.line,description_code:0 |
||||
|
#: field:super.calendar.configurator.line,description_field_id:0 |
||||
|
msgid "Description field" |
||||
|
msgstr "Поле описания" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: view:super.calendar.configurator:0 |
||||
|
#: help:super.calendar.configurator.line,description_code:0 |
||||
|
msgid "" |
||||
|
"Use '${o}' to refer to the involved object. E.g.: '${o.project_id.name}'" |
||||
|
msgstr "Используйте '${o}' для ссылки на объект: '${o.project_id.name}'" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: code:addons/super_calendar/super_calendar.py:60 |
||||
|
#, python-format |
||||
|
msgid "Error" |
||||
|
msgstr "Ошибка" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar,model_id:0 |
||||
|
#: field:super.calendar.configurator.line,name:0 |
||||
|
msgid "Model" |
||||
|
msgstr "Модель" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: view:super.calendar:0 |
||||
|
#: field:super.calendar,configurator_id:0 |
||||
|
#: view:super.calendar.configurator:0 |
||||
|
#: field:super.calendar.configurator.line,configurator_id:0 |
||||
|
msgid "Configurator" |
||||
|
msgstr "Настройки" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar.configurator.line,domain:0 |
||||
|
msgid "Domain" |
||||
|
msgstr "Домен" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: selection:super.calendar.configurator.line,description_type:0 |
||||
|
msgid "Code" |
||||
|
msgstr "Код" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: model:_description:0 |
||||
|
#: model:ir.model,name:super_calendar.model_super_calendar_configurator_line |
||||
|
msgid "super.calendar.configurator.line" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: model:ir.ui.menu,name:super_calendar.super_calendar_configuration |
||||
|
msgid "Configuration" |
||||
|
msgstr "Настройки" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: view:super.calendar:0 |
||||
|
msgid "My Items" |
||||
|
msgstr "Мои события" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar.configurator.line,date_stop_field_id:0 |
||||
|
msgid "End date field" |
||||
|
msgstr "Поле даты окончания" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: model:_description:0 |
||||
|
#: model:ir.model,name:super_calendar.model_super_calendar |
||||
|
msgid "super.calendar" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: view:super.calendar:0 |
||||
|
msgid "Search Calendar" |
||||
|
msgstr "Поиск календаря" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar,duration:0 |
||||
|
msgid "Duration" |
||||
|
msgstr "Продолжительность" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: model:ir.ui.menu,name:super_calendar.super_calendar_calendar |
||||
|
#: model:ir.ui.menu,name:super_calendar.super_calendar_calendar_calendar |
||||
|
#: view:super.calendar:0 |
||||
|
msgid "Calendar" |
||||
|
msgstr "Календарь" |
@ -0,0 +1,210 @@ |
|||||
|
# Translation of OpenERP Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * super_calendar |
||||
|
# |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: OpenERP Server 7.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2014-03-14 17:41+0000\n" |
||||
|
"PO-Revision-Date: 2014-03-14 17:41+0000\n" |
||||
|
"Last-Translator: <>\n" |
||||
|
"Language-Team: \n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Plural-Forms: \n" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar.configurator.line,duration_field_id:0 |
||||
|
msgid "Duration field" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: view:super.calendar.configurator:0 |
||||
|
msgid "Generate Calendar" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: selection:super.calendar.configurator.line,description_type:0 |
||||
|
msgid "Field" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: code:addons/super_calendar/super_calendar.py:61 |
||||
|
#, python-format |
||||
|
msgid "The 'User' field of record %s (%s) does not refer to res.users" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar,date_start:0 |
||||
|
msgid "Start date" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar.configurator.line,user_field_id:0 |
||||
|
msgid "User field" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar.configurator.line,description_type:0 |
||||
|
msgid "Description Type" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: model:_description:0 |
||||
|
#: model:ir.model,name:super_calendar.model_super_calendar_configurator |
||||
|
msgid "super.calendar.configurator" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar,name:0 |
||||
|
#: view:super.calendar.configurator:0 |
||||
|
#: field:super.calendar.configurator.line,description:0 |
||||
|
msgid "Description" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: model:ir.actions.act_window,name:super_calendar.super_calendar_configurator |
||||
|
msgid "Calendar Configurators" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar,model_description:0 |
||||
|
msgid "Model Description" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar.configurator.line,date_start_field_id:0 |
||||
|
msgid "Start date field" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar,user_id:0 |
||||
|
msgid "User" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: model:ir.actions.act_window,name:super_calendar.super_calendar_action |
||||
|
#: model:ir.ui.menu,name:super_calendar.super_calendar_menu |
||||
|
msgid "Super Calendar" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: view:super.calendar.configurator:0 |
||||
|
msgid "Line" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: view:super.calendar:0 |
||||
|
msgid "Extended Filters..." |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar,res_id:0 |
||||
|
msgid "Resource" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar.configurator,name:0 |
||||
|
msgid "Name" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: model:ir.ui.menu,name:super_calendar.super_calendar_configurators |
||||
|
#: view:super.calendar.configurator:0 |
||||
|
msgid "Configurators" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: view:super.calendar.configurator:0 |
||||
|
#: field:super.calendar.configurator,line_ids:0 |
||||
|
msgid "Lines" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar.configurator.line,description_code:0 |
||||
|
#: field:super.calendar.configurator.line,description_field_id:0 |
||||
|
msgid "Description field" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: view:super.calendar.configurator:0 |
||||
|
#: help:super.calendar.configurator.line,description_code:0 |
||||
|
msgid "Use '${o}' to refer to the involved object. E.g.: '${o.project_id.name}'" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: code:addons/super_calendar/super_calendar.py:60 |
||||
|
#, python-format |
||||
|
msgid "Error" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar,model_id:0 |
||||
|
#: field:super.calendar.configurator.line,name:0 |
||||
|
msgid "Model" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: view:super.calendar:0 |
||||
|
#: field:super.calendar,configurator_id:0 |
||||
|
#: view:super.calendar.configurator:0 |
||||
|
#: field:super.calendar.configurator.line,configurator_id:0 |
||||
|
msgid "Configurator" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar.configurator.line,domain:0 |
||||
|
msgid "Domain" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: selection:super.calendar.configurator.line,description_type:0 |
||||
|
msgid "Code" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: model:_description:0 |
||||
|
#: model:ir.model,name:super_calendar.model_super_calendar_configurator_line |
||||
|
msgid "super.calendar.configurator.line" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: model:ir.ui.menu,name:super_calendar.super_calendar_configuration |
||||
|
msgid "Configuration" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: view:super.calendar:0 |
||||
|
msgid "My Items" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar.configurator.line,date_stop_field_id:0 |
||||
|
msgid "End date field" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: model:_description:0 |
||||
|
#: model:ir.model,name:super_calendar.model_super_calendar |
||||
|
msgid "super.calendar" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: view:super.calendar:0 |
||||
|
msgid "Search Calendar" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: field:super.calendar,duration:0 |
||||
|
msgid "Duration" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: super_calendar |
||||
|
#: model:ir.ui.menu,name:super_calendar.super_calendar_calendar |
||||
|
#: model:ir.ui.menu,name:super_calendar.super_calendar_calendar_calendar |
||||
|
#: view:super.calendar:0 |
||||
|
msgid "Calendar" |
||||
|
msgstr "" |
||||
|
|
@ -0,0 +1,4 @@ |
|||||
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink |
||||
|
access_model_super_calendar_configurator,access_model_super_calendar_configurator,model_super_calendar_configurator,base.group_system,1,1,1,1 |
||||
|
access_model_super_calendar_configurator_line,access_model_super_calendar_configurator_line,model_super_calendar_configurator_line,base.group_system,1,1,1,1 |
||||
|
access_model_super_calendar,access_model_super_calendar,model_super_calendar,base.group_user,1,0,0,0 |
@ -0,0 +1,163 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Copyright (C) 2012 Agile Business Group sagl (<http://www.agilebg.com>) |
||||
|
# Copyright (C) 2012 Domsense srl (<http://www.domsense.com>) |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as published |
||||
|
# by the Free Software Foundation, either version 3 of the License, or |
||||
|
# (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
from openerp.osv import fields, orm |
||||
|
from openerp.tools.translate import _ |
||||
|
import logging |
||||
|
from mako.template import Template |
||||
|
from datetime import datetime |
||||
|
from openerp import tools |
||||
|
from openerp.tools.safe_eval import safe_eval |
||||
|
|
||||
|
|
||||
|
def _models_get(self, cr, uid, context=None): |
||||
|
obj = self.pool.get('ir.model') |
||||
|
ids = obj.search(cr, uid, []) |
||||
|
res = obj.read(cr, uid, ids, ['model', 'name'], context) |
||||
|
return [(r['model'], r['name']) for r in res] |
||||
|
|
||||
|
|
||||
|
class super_calendar_configurator(orm.Model): |
||||
|
_logger = logging.getLogger('super.calendar') |
||||
|
_name = 'super.calendar.configurator' |
||||
|
_columns = { |
||||
|
'name': fields.char('Name', size=64, required=True), |
||||
|
'line_ids': fields.one2many('super.calendar.configurator.line', 'configurator_id', 'Lines'), |
||||
|
} |
||||
|
|
||||
|
def generate_calendar_records(self, cr, uid, ids, context=None): |
||||
|
configurator_ids = self.search(cr, uid, []) |
||||
|
super_calendar_pool = self.pool.get('super.calendar') |
||||
|
|
||||
|
# removing old records |
||||
|
super_calendar_ids = super_calendar_pool.search(cr, uid, [], context=context) |
||||
|
super_calendar_pool.unlink(cr, uid, super_calendar_ids, context=context) |
||||
|
|
||||
|
for configurator in self.browse(cr, uid, configurator_ids, context): |
||||
|
for line in configurator.line_ids: |
||||
|
current_pool = self.pool.get(line.name.model) |
||||
|
current_record_ids = current_pool.search( |
||||
|
cr, |
||||
|
uid, |
||||
|
line.domain and safe_eval(line.domain) or [], |
||||
|
context=context) |
||||
|
|
||||
|
for current_record_id in current_record_ids: |
||||
|
current_record = current_pool.browse(cr, uid, current_record_id, context=context) |
||||
|
if (line.user_field_id and |
||||
|
current_record[line.user_field_id.name] and |
||||
|
current_record[line.user_field_id.name]._table_name != 'res.users'): |
||||
|
raise orm.except_orm( |
||||
|
_('Error'), |
||||
|
_("The 'User' field of record %s (%s) does not refer to res.users") |
||||
|
% (current_record[line.description_field_id.name], line.name.model)) |
||||
|
if (((line.description_field_id and current_record[line.description_field_id.name]) or |
||||
|
line.description_code) and |
||||
|
current_record[line.date_start_field_id.name]): |
||||
|
duration = False |
||||
|
if (not line.duration_field_id and |
||||
|
line.date_stop_field_id and |
||||
|
current_record[line.date_start_field_id.name] and |
||||
|
current_record[line.date_stop_field_id.name]): |
||||
|
date_start = datetime.strptime( |
||||
|
current_record[line.date_start_field_id.name], |
||||
|
tools.DEFAULT_SERVER_DATETIME_FORMAT |
||||
|
) |
||||
|
date_stop = datetime.strptime( |
||||
|
current_record[line.date_stop_field_id.name], |
||||
|
tools.DEFAULT_SERVER_DATETIME_FORMAT |
||||
|
) |
||||
|
duration = (date_stop - date_start).total_seconds() / 3600 |
||||
|
elif line.duration_field_id: |
||||
|
duration = current_record[line.duration_field_id.name] |
||||
|
if line.description_type != 'code': |
||||
|
name = current_record[line.description_field_id.name] |
||||
|
else: |
||||
|
parse_dict = {'o': current_record} |
||||
|
mytemplate = Template(line.description_code) |
||||
|
name = mytemplate.render(**parse_dict) |
||||
|
super_calendar_values = { |
||||
|
'name': name, |
||||
|
'model_description': line.description, |
||||
|
'date_start': current_record[line.date_start_field_id.name], |
||||
|
'duration': duration, |
||||
|
'user_id': ( |
||||
|
line.user_field_id and |
||||
|
current_record[line.user_field_id.name] and |
||||
|
current_record[line.user_field_id.name].id or |
||||
|
False |
||||
|
), |
||||
|
'configurator_id': configurator.id, |
||||
|
'res_id': line.name.model+','+str(current_record['id']), |
||||
|
'model_id': line.name.id, |
||||
|
} |
||||
|
super_calendar_pool.create(cr, uid, super_calendar_values, context=context) |
||||
|
self._logger.info('Calendar generated') |
||||
|
return True |
||||
|
|
||||
|
|
||||
|
class super_calendar_configurator_line(orm.Model): |
||||
|
_name = 'super.calendar.configurator.line' |
||||
|
_columns = { |
||||
|
'name': fields.many2one('ir.model', 'Model', required=True), |
||||
|
'description': fields.char('Description', size=128, required=True), |
||||
|
'domain': fields.char('Domain', size=512), |
||||
|
'configurator_id': fields.many2one('super.calendar.configurator', 'Configurator'), |
||||
|
'description_type': fields.selection([ |
||||
|
('field', 'Field'), |
||||
|
('code', 'Code'), |
||||
|
], string="Description Type"), |
||||
|
'description_field_id': fields.many2one( |
||||
|
'ir.model.fields', 'Description field', |
||||
|
domain="[('model_id', '=', name),('ttype', '=', 'char')]"), |
||||
|
'description_code': fields.text( |
||||
|
'Description field', |
||||
|
help="Use '${o}' to refer to the involved object. E.g.: '${o.project_id.name}'" |
||||
|
), |
||||
|
'date_start_field_id': fields.many2one( |
||||
|
'ir.model.fields', 'Start date field', |
||||
|
domain="['&','|',('ttype', '=', 'datetime'),('ttype', '=', 'date'),('model_id', '=', name)]", |
||||
|
required=True), |
||||
|
'date_stop_field_id': fields.many2one( |
||||
|
'ir.model.fields', 'End date field', |
||||
|
domain="['&',('ttype', '=', 'datetime'),('model_id', '=', name)]" |
||||
|
), |
||||
|
'duration_field_id': fields.many2one( |
||||
|
'ir.model.fields', 'Duration field', |
||||
|
domain="['&',('ttype', '=', 'float'),('model_id', '=', name)]"), |
||||
|
'user_field_id': fields.many2one( |
||||
|
'ir.model.fields', 'User field', |
||||
|
domain="['&',('ttype', '=', 'many2one'),('model_id', '=', name)]"), |
||||
|
} |
||||
|
|
||||
|
|
||||
|
class super_calendar(orm.Model): |
||||
|
_name = 'super.calendar' |
||||
|
_columns = { |
||||
|
'name': fields.char('Description', size=512, required=True), |
||||
|
'model_description': fields.char('Model Description', size=128, required=True), |
||||
|
'date_start': fields.datetime('Start date', required=True), |
||||
|
'duration': fields.float('Duration'), |
||||
|
'user_id': fields.many2one('res.users', 'User'), |
||||
|
'configurator_id': fields.many2one('super.calendar.configurator', 'Configurator'), |
||||
|
'res_id': fields.reference('Resource', selection=_models_get, size=128), |
||||
|
'model_id': fields.many2one('ir.model', 'Model'), |
||||
|
} |
@ -0,0 +1,144 @@ |
|||||
|
<?xml version="1.0"?> |
||||
|
<openerp> |
||||
|
<data> |
||||
|
|
||||
|
<!-- configurator --> |
||||
|
|
||||
|
<record model="ir.ui.view" id="super_calendar_configurator_tree"> |
||||
|
<field name="name">super_calendar_configurator_tree</field> |
||||
|
<field name="model">super.calendar.configurator</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<tree string="Configurators"> |
||||
|
<field name="name"/> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record model="ir.ui.view" id="super_calendar_configurator_form"> |
||||
|
<field name="name">super_calendar_configurator_form</field> |
||||
|
<field name="model">super.calendar.configurator</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<form string="Configurator"> |
||||
|
<field name="name" select="1" colspan="2"/> |
||||
|
<newline/> |
||||
|
<field name="line_ids" nolabel="1" colspan="4"> |
||||
|
<tree string="Lines"> |
||||
|
<field name="name"/> |
||||
|
<field name="domain"/> |
||||
|
</tree> |
||||
|
<form string="Line"> |
||||
|
<field name="name"/> |
||||
|
<field name="description"/> |
||||
|
<field name="domain"/> |
||||
|
<field name="date_start_field_id"/> |
||||
|
<field name="duration_field_id"/> |
||||
|
<field name="date_stop_field_id" attrs="{'readonly':[('duration_field_id','!=',False)]}"/> |
||||
|
<field name="user_field_id"/> |
||||
|
<separator string="Description" colspan="4" /> |
||||
|
<field name="description_type"/> |
||||
|
<newline/> |
||||
|
<field name="description_field_id" attrs="{'required':[('description_type','!=','code')], 'invisible':[('description_type','==','code')]}"/> |
||||
|
<group colspan="4" col="1" attrs="{'invisible':[('description_type','!=','code')]}"> |
||||
|
<label string="Use '${o}' to refer to the involved object. E.g.: '${o.project_id.name}'" /> |
||||
|
<field name="description_code" nolabel="1" attrs="{'required':[('description_type','==','code')]}"/> |
||||
|
</group> |
||||
|
</form> |
||||
|
</field> |
||||
|
<newline/> |
||||
|
<button name="generate_calendar_records" string="Generate Calendar" type="object" icon="gtk-go-forward" colspan="2"/> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record model="ir.actions.act_window" id="super_calendar_configurator"> |
||||
|
<field name="name">Calendar Configurators</field> |
||||
|
<field name="res_model">super.calendar.configurator</field> |
||||
|
<field name="view_type">form</field> |
||||
|
<field name="view_mode">tree,form</field> |
||||
|
<field name="view_id" ref="super_calendar_configurator_tree"/> |
||||
|
</record> |
||||
|
|
||||
|
<!-- calendar --> |
||||
|
|
||||
|
<record model="ir.ui.view" id="super_calendar_tree"> |
||||
|
<field name="name">super_calendar_tree</field> |
||||
|
<field name="model">super.calendar</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<tree string="Calendar"> |
||||
|
<field name="name"/> |
||||
|
<field name="date_start"/> |
||||
|
<!--<field name="date_stop"/>--> |
||||
|
<field name="duration"/> |
||||
|
<field name="user_id"/> |
||||
|
<field name="configurator_id"/> |
||||
|
<field name="model_id"/> |
||||
|
<field name="model_description"/> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record model="ir.ui.view" id="super_calendar_form"> |
||||
|
<field name="name">super_calendar_form</field> |
||||
|
<field name="model">super.calendar</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<form string="Configurator"> |
||||
|
<field name="name" readonly="1"/> |
||||
|
<field name="date_start" readonly="1"/> |
||||
|
<!--<field name="date_stop" readonly="1"/>--> |
||||
|
<field name="duration" readonly="1"/> |
||||
|
<field name="user_id" readonly="1"/> |
||||
|
<field name="configurator_id" readonly="1"/> |
||||
|
<field name="model_id" readonly="1"/> |
||||
|
<field name="model_description" readonly="1"/> |
||||
|
<field name="res_id"/> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record model="ir.ui.view" id="super_calendar"> |
||||
|
<field name="name">super_calendar</field> |
||||
|
<field name="model">super.calendar</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<calendar string="Calendar" color="model_description" date_start="date_start" date_delay="duration"> |
||||
|
<field name="name"/> |
||||
|
</calendar> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record model="ir.ui.view" id="super_calendar_search"> |
||||
|
<field name="name">super_calendar_search</field> |
||||
|
<field name="model">super.calendar</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<search string="Search Calendar" > |
||||
|
<field name="name"/> |
||||
|
<field name="configurator_id" select="1"/> |
||||
|
<field name="model_id" select="1"/> |
||||
|
<field name="model_description" select="1"/> |
||||
|
<field name="user_id" widget="selection" > |
||||
|
<filter domain="[('user_id','=',uid)]" help="My Items" icon="terp-personal"/> |
||||
|
</field> |
||||
|
<newline/> |
||||
|
<group expand="0" string="Extended Filters..." colspan="4" col="8"> |
||||
|
<field name="date_start" /> |
||||
|
<!--<field name="date_stop" />--> |
||||
|
<field name="duration" /> |
||||
|
</group> |
||||
|
</search> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record model="ir.actions.act_window" id="super_calendar_action"> |
||||
|
<field name="name">Super Calendar</field> |
||||
|
<field name="res_model">super.calendar</field> |
||||
|
<field name="view_type">form</field> |
||||
|
<field name="view_mode">calendar,tree,form</field> |
||||
|
<field name="view_id" ref="super_calendar"/> |
||||
|
</record> |
||||
|
|
||||
|
<menuitem id="super_calendar_menu" name="Super Calendar" action="super_calendar_action"/> |
||||
|
<menuitem id="super_calendar_calendar" name="Calendar" parent="super_calendar_menu" /> |
||||
|
<menuitem id="super_calendar_calendar_calendar" name="Calendar" parent="super_calendar_calendar" action="super_calendar_action"/> |
||||
|
<menuitem id="super_calendar_configuration" name="Configuration" parent="super_calendar_menu" /> |
||||
|
<menuitem id="super_calendar_configurators" name="Configurators" parent="super_calendar_configuration" action="super_calendar_configurator"/> |
||||
|
</data> |
||||
|
</openerp> |
@ -0,0 +1,22 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# OpenERP, Open Source Management Solution |
||||
|
# This module copyright (C) 2012 Therp BV (<http://therp.nl>). |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
import users_ldap_groups |
@ -0,0 +1,61 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# OpenERP, Open Source Management Solution |
||||
|
# This module copyright (C) 2012 Therp BV (<http://therp.nl>). |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
{ |
||||
|
"name": "Groups assignment", |
||||
|
"version": "1.2", |
||||
|
"depends": ["auth_ldap"], |
||||
|
"author": "Therp BV", |
||||
|
"description": """ |
||||
|
Adds user accounts to groups based on rules defined by the administrator. |
||||
|
|
||||
|
Usage: |
||||
|
|
||||
|
Define mappings in Settings->Companies->[your company]->tab configuration->[your |
||||
|
ldap server]. |
||||
|
|
||||
|
Decide whether you want only groups mapped from ldap (Only ldap groups=y) or a |
||||
|
mix of manually set groups and ldap groups (Only ldap groups=n). Setting this to |
||||
|
'no' will result in users never losing privileges when you remove them from a |
||||
|
ldap group, so that's a potential security issue. It is still the default to |
||||
|
prevent losing group information by accident. |
||||
|
|
||||
|
For active directory, use LDAP attribute 'memberOf' and operator 'contains'. |
||||
|
Fill in the DN of the windows group as value and choose an OpenERP group users |
||||
|
with this windows group are to be assigned to. |
||||
|
|
||||
|
For posix accounts, use operator 'query' and a value like |
||||
|
(&(cn=bzr)(objectClass=posixGroup)(memberUid=$uid)) |
||||
|
|
||||
|
The operator query matches if the filter in value returns something, and value |
||||
|
can contain $[attribute] which will be replaced by the first value of the |
||||
|
user's ldap record's attribute named [attribute]. |
||||
|
""", |
||||
|
"category": "Tools", |
||||
|
"data": [ |
||||
|
'users_ldap_groups.xml', |
||||
|
'security/ir.model.access.csv', |
||||
|
], |
||||
|
"installable": True, |
||||
|
"external_dependencies": { |
||||
|
'python': ['ldap'], |
||||
|
}, |
||||
|
} |
@ -0,0 +1,16 @@ |
|||||
|
# Translation of OpenERP Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: OpenERP Server 7.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2014-03-14 17:41+0000\n" |
||||
|
"PO-Revision-Date: 2014-03-14 17:41+0000\n" |
||||
|
"Last-Translator: <>\n" |
||||
|
"Language-Team: \n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Plural-Forms: \n" |
||||
|
|
@ -0,0 +1,2 @@ |
|||||
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink |
||||
|
access_res_company_ldap_groups,res_company_ldap_groups,model_res_company_ldap_group_mapping,base.group_system,1,1,1,1 |
@ -0,0 +1,107 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# OpenERP, Open Source Management Solution |
||||
|
# This module copyright (C) 2012 Therp BV (<http://therp.nl>). |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
from openerp.osv import fields, orm |
||||
|
import logging |
||||
|
import users_ldap_groups_operators |
||||
|
import inspect |
||||
|
|
||||
|
|
||||
|
class CompanyLDAPGroupMapping(orm.Model): |
||||
|
_name = 'res.company.ldap.group_mapping' |
||||
|
_rec_name = 'ldap_attribute' |
||||
|
_order = 'ldap_attribute' |
||||
|
|
||||
|
def _get_operators(self, cr, uid, context=None): |
||||
|
operators = [] |
||||
|
members = inspect.getmembers( |
||||
|
users_ldap_groups_operators, |
||||
|
lambda cls: inspect.isclass(cls) |
||||
|
and cls != users_ldap_groups_operators.LDAPOperator) |
||||
|
for name, operator in members: |
||||
|
operators.append((name, name)) |
||||
|
return tuple(operators) |
||||
|
|
||||
|
_columns = { |
||||
|
'ldap_id': fields.many2one('res.company.ldap', 'LDAP server', required=True), |
||||
|
'ldap_attribute': fields.char( |
||||
|
'LDAP attribute', size=64, |
||||
|
help='The LDAP attribute to check.\n' |
||||
|
'For active directory, use memberOf.'), |
||||
|
'operator': fields.selection( |
||||
|
_get_operators, 'Operator', |
||||
|
help='The operator to check the attribute against the value\n' |
||||
|
'For active directory, use \'contains\'', required=True), |
||||
|
'value': fields.char( |
||||
|
'Value', size=1024, |
||||
|
help='The value to check the attribute against.\n' |
||||
|
'For active directory, use the dn of the desired group', |
||||
|
required=True), |
||||
|
'group': fields.many2one( |
||||
|
'res.groups', 'OpenERP group', |
||||
|
help='The OpenERP group to assign', required=True), |
||||
|
} |
||||
|
|
||||
|
|
||||
|
class CompanyLDAP(orm.Model): |
||||
|
_inherit = 'res.company.ldap' |
||||
|
|
||||
|
_columns = { |
||||
|
'group_mappings': fields.one2many( |
||||
|
'res.company.ldap.group_mapping', |
||||
|
'ldap_id', 'Group mappings', |
||||
|
help='Define how OpenERP groups are assigned to ldap users'), |
||||
|
'only_ldap_groups': fields.boolean( |
||||
|
'Only ldap groups', |
||||
|
help='If this is checked, manual changes to group membership are ' |
||||
|
'undone on every login (so OpenERP groups are always synchronous ' |
||||
|
'with LDAP groups). If not, manually added groups are preserved.') |
||||
|
} |
||||
|
|
||||
|
_default = { |
||||
|
'only_ldap_groups': False, |
||||
|
} |
||||
|
|
||||
|
def get_or_create_user(self, cr, uid, conf, login, ldap_entry, context=None): |
||||
|
user_id = super(CompanyLDAP, self).get_or_create_user(cr, uid, conf, login, |
||||
|
ldap_entry, context) |
||||
|
if not user_id: |
||||
|
return user_id |
||||
|
logger = logging.getLogger('users_ldap_groups') |
||||
|
mappingobj = self.pool.get('res.company.ldap.group_mapping') |
||||
|
userobj = self.pool.get('res.users') |
||||
|
conf_all = self.read(cr, uid, conf['id'], ['only_ldap_groups']) |
||||
|
if(conf_all['only_ldap_groups']): |
||||
|
logger.debug('deleting all groups from user %d' % user_id) |
||||
|
userobj.write(cr, uid, [user_id], {'groups_id': [(5, )]}, context=context) |
||||
|
|
||||
|
for mapping in mappingobj.read(cr, uid, mappingobj.search( |
||||
|
cr, uid, [('ldap_id', '=', conf['id'])]), []): |
||||
|
operator = getattr(users_ldap_groups_operators, mapping['operator'])() |
||||
|
logger.debug('checking mapping %s' % mapping) |
||||
|
if operator.check_value(ldap_entry, mapping['ldap_attribute'], |
||||
|
mapping['value'], conf, self, logger): |
||||
|
logger.debug('adding user %d to group %s' % |
||||
|
(user_id, mapping['group'][1])) |
||||
|
userobj.write(cr, uid, [user_id], |
||||
|
{'groups_id': [(4, mapping['group'][0])]}, |
||||
|
context=context) |
||||
|
return user_id |
@ -0,0 +1,27 @@ |
|||||
|
<?xml version="1.0"?> |
||||
|
<openerp> |
||||
|
<data> |
||||
|
<record model="ir.ui.view" id="company_form_view"> |
||||
|
<field name="name">res.company.form.inherit.users_ldap_groups</field> |
||||
|
<field name="model">res.company</field> |
||||
|
<field name="inherit_id" ref="auth_ldap.company_form_view"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
|
||||
|
<xpath expr="//form[@string='LDAP Configuration']" position="inside"> |
||||
|
<group string="Map User Groups" > |
||||
|
<field name="only_ldap_groups" /> |
||||
|
<field name="group_mappings" colspan="4" nolabel="1"> |
||||
|
<tree editable="top"> |
||||
|
<field name="ldap_attribute" attrs="{'required': [('operator','not in',['query'])], 'readonly': [('operator','in',['query'])]}" /> |
||||
|
<field name="operator" /> |
||||
|
<field name="value" /> |
||||
|
<field name="group" /> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</group> |
||||
|
</xpath> |
||||
|
|
||||
|
</field> |
||||
|
</record> |
||||
|
</data> |
||||
|
</openerp> |
@ -0,0 +1,47 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# OpenERP, Open Source Management Solution |
||||
|
# This module copyright (C) 2012 Therp BV (<http://therp.nl>). |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
from string import Template |
||||
|
|
||||
|
|
||||
|
class LDAPOperator: |
||||
|
pass |
||||
|
|
||||
|
|
||||
|
class contains(LDAPOperator): |
||||
|
def check_value(self, ldap_entry, attribute, value, ldap_config, company, logger): |
||||
|
return (attribute in ldap_entry[1]) and (value in ldap_entry[1][attribute]) |
||||
|
|
||||
|
|
||||
|
class equals(LDAPOperator): |
||||
|
def check_value(self, ldap_entry, attribute, value, ldap_config, company, logger): |
||||
|
return attribute in ldap_entry[1] and unicode(value) == unicode(ldap_entry[1][attribute]) |
||||
|
|
||||
|
|
||||
|
class query(LDAPOperator): |
||||
|
def check_value(self, ldap_entry, attribute, value, ldap_config, company, logger): |
||||
|
query_string = Template(value).safe_substitute(dict( |
||||
|
[(attr, ldap_entry[1][attribute][0]) for attr in ldap_entry[1]] |
||||
|
) |
||||
|
) |
||||
|
logger.debug('evaluating query group mapping, filter: %s' % query_string) |
||||
|
results = company.query(ldap_config, query_string) |
||||
|
logger.debug(results) |
||||
|
return bool(results) |
Some files were not shown because too many files changed in this diff
Write
Preview
Loading…
Cancel
Save
Reference in new issue