Commit 29abf0f533e4824fa0d8075bce9c4cdd7445f32f
0 parents
Exists in
master
Versão Inicial.
Showing
49 changed files
with
2800 additions
and
0 deletions
Show diff stats
1 | +++ a/LICENSE | ||
@@ -0,0 +1,27 @@ | @@ -0,0 +1,27 @@ | ||
1 | + Este arquivo é parte do produto pf.servicos.policy | ||
2 | + | ||
3 | + Copyright © 2014-2015 Departamento de Polícia Federal | ||
4 | + | ||
5 | + Este produto é um Software Livre. Você pode usá-lo, | ||
6 | + modificá-lo e/ou distribuí-lo a terceiros, em sua forma | ||
7 | + original ou modificada, desde que respeite os termos da | ||
8 | + versão 3 (ou posterior) da Licença Pública Geral (GPLv3) | ||
9 | + publicada Free Software Foundation. | ||
10 | + | ||
11 | + Este produto é distribuído na esperança de que possa ser útil, | ||
12 | + mas SEM NENHUMA GARANTIA; sem uma garantia implícita de ADEQUAÇÃO | ||
13 | + a qualquer MERCADO ou APLICAÇÃO EM PARTICULAR. Veja a | ||
14 | + Licença Pública Geral GNU para maiores detalhes. | ||
15 | + | ||
16 | + Você deve ter recebido uma cópia da Licença Pública Geral GNU | ||
17 | + junto com este programa. Caso contrário, escreva para: | ||
18 | + | ||
19 | + Polícia Federal | ||
20 | + Coordenação Geral de Tecnologia Da Informação | ||
21 | + SAIS Quadra 7 Lote 23 - Setor Policial Sul | ||
22 | + Edifício da CGTI - Brasília - DF | ||
23 | + Brasil | ||
24 | + | ||
25 | + Alternativamente, você poderá obter uma cópia da licença | ||
26 | + junto à própria Free Software Foundation. | ||
27 | + |
1 | +++ a/README.md | ||
@@ -0,0 +1,12 @@ | @@ -0,0 +1,12 @@ | ||
1 | +Introdução | ||
2 | +========== | ||
3 | + | ||
4 | +Este produto Plone implanta a Biblioteca de Processos | ||
5 | +no Portal Instituicional Padrão criado pela SECOM/PR. | ||
6 | + | ||
7 | +O referido portal está instalado nas seguintes instâncias: | ||
8 | + | ||
9 | +1. Portal de Serviços da Polícia Federal: | ||
10 | +Produção: http://intranet.dpf.gov.br/servicos | ||
11 | +Homologação: http://intranethom.dpf.gov.br/servicos | ||
12 | + |
1 | +++ a/bootstrap.py | ||
@@ -0,0 +1,121 @@ | @@ -0,0 +1,121 @@ | ||
1 | +############################################################################## | ||
2 | +# | ||
3 | +# Copyright (c) 2006 Zope Foundation and Contributors. | ||
4 | +# All Rights Reserved. | ||
5 | +# | ||
6 | +# This software is subject to the provisions of the Zope Public License, | ||
7 | +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. | ||
8 | +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED | ||
9 | +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
10 | +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS | ||
11 | +# FOR A PARTICULAR PURPOSE. | ||
12 | +# | ||
13 | +############################################################################## | ||
14 | +"""Bootstrap a buildout-based project | ||
15 | + | ||
16 | +Simply run this script in a directory containing a buildout.cfg. | ||
17 | +The script accepts buildout command-line options, so you can | ||
18 | +use the -c option to specify an alternate configuration file. | ||
19 | + | ||
20 | +$Id$ | ||
21 | +""" | ||
22 | + | ||
23 | +import os, shutil, sys, tempfile, urllib2 | ||
24 | +from optparse import OptionParser | ||
25 | + | ||
26 | +tmpeggs = tempfile.mkdtemp() | ||
27 | + | ||
28 | +is_jython = sys.platform.startswith('java') | ||
29 | + | ||
30 | +# parsing arguments | ||
31 | +parser = OptionParser() | ||
32 | +parser.add_option("-v", "--version", dest="version", | ||
33 | + help="use a specific zc.buildout version") | ||
34 | +parser.add_option("-d", "--distribute", | ||
35 | + action="store_true", dest="distribute", default=False, | ||
36 | + help="Use Disribute rather than Setuptools.") | ||
37 | + | ||
38 | +parser.add_option("-c", None, action="store", dest="config_file", | ||
39 | + help=("Specify the path to the buildout configuration " | ||
40 | + "file to be used.")) | ||
41 | + | ||
42 | +options, args = parser.parse_args() | ||
43 | + | ||
44 | +# if -c was provided, we push it back into args for buildout' main function | ||
45 | +if options.config_file is not None: | ||
46 | + args += ['-c', options.config_file] | ||
47 | + | ||
48 | +if options.version is not None: | ||
49 | + VERSION = '==%s' % options.version | ||
50 | +else: | ||
51 | + VERSION = '' | ||
52 | + | ||
53 | +USE_DISTRIBUTE = options.distribute | ||
54 | +args = args + ['bootstrap'] | ||
55 | + | ||
56 | +to_reload = False | ||
57 | +try: | ||
58 | + import pkg_resources | ||
59 | + if not hasattr(pkg_resources, '_distribute'): | ||
60 | + to_reload = True | ||
61 | + raise ImportError | ||
62 | +except ImportError: | ||
63 | + ez = {} | ||
64 | + if USE_DISTRIBUTE: | ||
65 | + exec urllib2.urlopen('http://python-distribute.org/distribute_setup.py' | ||
66 | + ).read() in ez | ||
67 | + ez['use_setuptools'](to_dir=tmpeggs, download_delay=0, no_fake=True) | ||
68 | + else: | ||
69 | + exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py' | ||
70 | + ).read() in ez | ||
71 | + ez['use_setuptools'](to_dir=tmpeggs, download_delay=0) | ||
72 | + | ||
73 | + if to_reload: | ||
74 | + reload(pkg_resources) | ||
75 | + else: | ||
76 | + import pkg_resources | ||
77 | + | ||
78 | +if sys.platform == 'win32': | ||
79 | + def quote(c): | ||
80 | + if ' ' in c: | ||
81 | + return '"%s"' % c # work around spawn lamosity on windows | ||
82 | + else: | ||
83 | + return c | ||
84 | +else: | ||
85 | + def quote (c): | ||
86 | + return c | ||
87 | + | ||
88 | +cmd = 'from setuptools.command.easy_install import main; main()' | ||
89 | +ws = pkg_resources.working_set | ||
90 | + | ||
91 | +if USE_DISTRIBUTE: | ||
92 | + requirement = 'distribute' | ||
93 | +else: | ||
94 | + requirement = 'setuptools' | ||
95 | + | ||
96 | +if is_jython: | ||
97 | + import subprocess | ||
98 | + | ||
99 | + assert subprocess.Popen([sys.executable] + ['-c', quote(cmd), '-mqNxd', | ||
100 | + quote(tmpeggs), 'zc.buildout' + VERSION], | ||
101 | + env=dict(os.environ, | ||
102 | + PYTHONPATH= | ||
103 | + ws.find(pkg_resources.Requirement.parse(requirement)).location | ||
104 | + ), | ||
105 | + ).wait() == 0 | ||
106 | + | ||
107 | +else: | ||
108 | + assert os.spawnle( | ||
109 | + os.P_WAIT, sys.executable, quote (sys.executable), | ||
110 | + '-c', quote (cmd), '-mqNxd', quote (tmpeggs), 'zc.buildout' + VERSION, | ||
111 | + dict(os.environ, | ||
112 | + PYTHONPATH= | ||
113 | + ws.find(pkg_resources.Requirement.parse(requirement)).location | ||
114 | + ), | ||
115 | + ) == 0 | ||
116 | + | ||
117 | +ws.add_entry(tmpeggs) | ||
118 | +ws.require('zc.buildout' + VERSION) | ||
119 | +import zc.buildout.buildout | ||
120 | +zc.buildout.buildout.main(args) | ||
121 | +shutil.rmtree(tmpeggs) |
1 | +++ a/buildout.cfg | ||
@@ -0,0 +1,25 @@ | @@ -0,0 +1,25 @@ | ||
1 | +[buildout] | ||
2 | +develop = . | ||
3 | +parts = scripts test | ||
4 | +versions = versions | ||
5 | +extends = | ||
6 | + http://dist.plone.org/release/4.0.1/versions.cfg | ||
7 | + http://good-py.appspot.com/release/dexterity/1.0b1?plone=4.0.1 | ||
8 | + | ||
9 | +[versions] | ||
10 | + | ||
11 | +[scripts] | ||
12 | +recipe = zc.recipe.egg | ||
13 | +eggs = | ||
14 | + pf.biblioteca | ||
15 | + zest.releaser | ||
16 | + ZopeSkel | ||
17 | + PasteScript | ||
18 | + PasteDeploy | ||
19 | + Paste | ||
20 | + zopeskel.dexterity | ||
21 | + | ||
22 | +[test] | ||
23 | +recipe = zc.recipe.testrunner | ||
24 | +defaults = ['--tests-pattern', '^f?tests$', '-v'] | ||
25 | +eggs = pf.biblioteca |
1 | +++ a/docs/INSTALL.txt | ||
@@ -0,0 +1,53 @@ | @@ -0,0 +1,53 @@ | ||
1 | +pf.servicos.policy Installation | ||
2 | +================================ | ||
3 | + | ||
4 | + Este procedimento de instalação foi gerado automaticamente e não é foi testado. | ||
5 | + Para realizar a instalação deste produto recomenda-se procurar a equipe de desenvolvimento. | ||
6 | + | ||
7 | + | ||
8 | +Intruções Geradas Automaticamente | ||
9 | +================================= | ||
10 | + * When you're reading this you have probably already run | ||
11 | + ``easy_install pf.servicos.policy``. Find out how to install setuptools | ||
12 | + (and EasyInstall) here: | ||
13 | + http://peak.telecommunity.com/DevCenter/EasyInstall | ||
14 | + | ||
15 | + * Get `pythonproducts`_ and install it via:: | ||
16 | + | ||
17 | + python setup.py install --home /path/to/instance | ||
18 | + | ||
19 | + into your Zope instance. | ||
20 | + | ||
21 | + * Create a file called ``pf.servicos.policy-configure.zcml`` in the | ||
22 | + ``/path/to/instance/etc/package-includes`` directory. The file | ||
23 | + should only contain this:: | ||
24 | + | ||
25 | + <include package="pf.servicos.policy" /> | ||
26 | + | ||
27 | +.. _pythonproducts: http://plone.org/products/pythonproducts | ||
28 | + | ||
29 | +Alternatively, if you are using zc.buildout and the plone.recipe.zope2instance | ||
30 | +recipe to manage your project, you can do this: | ||
31 | + | ||
32 | + * Add ``pf.servicos.policy`` to the list of eggs to install, e.g.: | ||
33 | + | ||
34 | + [buildout] | ||
35 | + ... | ||
36 | + eggs = | ||
37 | + ... | ||
38 | + pf.servicos.policy | ||
39 | + | ||
40 | + * Tell the plone.recipe.zope2instance recipe to install a ZCML slug: | ||
41 | + | ||
42 | + [instance] | ||
43 | + recipe = plone.recipe.zope2instance | ||
44 | + ... | ||
45 | + zcml = | ||
46 | + pf.servicos.policy | ||
47 | + | ||
48 | + * Re-run buildout, e.g. with: | ||
49 | + | ||
50 | + $ ./bin/buildout | ||
51 | + | ||
52 | +You can skip the ZCML slug if you are going to explicitly include the package | ||
53 | +from another package's configure.zcml file. |
1 | +++ a/docs/LICENSE.GPL | ||
@@ -0,0 +1,674 @@ | @@ -0,0 +1,674 @@ | ||
1 | + GNU GENERAL PUBLIC LICENSE | ||
2 | + Version 3, 29 June 2007 | ||
3 | + | ||
4 | + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> | ||
5 | + Everyone is permitted to copy and distribute verbatim copies | ||
6 | + of this license document, but changing it is not allowed. | ||
7 | + | ||
8 | + Preamble | ||
9 | + | ||
10 | + The GNU General Public License is a free, copyleft license for | ||
11 | +software and other kinds of works. | ||
12 | + | ||
13 | + The licenses for most software and other practical works are designed | ||
14 | +to take away your freedom to share and change the works. By contrast, | ||
15 | +the GNU General Public License is intended to guarantee your freedom to | ||
16 | +share and change all versions of a program--to make sure it remains free | ||
17 | +software for all its users. We, the Free Software Foundation, use the | ||
18 | +GNU General Public License for most of our software; it applies also to | ||
19 | +any other work released this way by its authors. You can apply it to | ||
20 | +your programs, too. | ||
21 | + | ||
22 | + When we speak of free software, we are referring to freedom, not | ||
23 | +price. Our General Public Licenses are designed to make sure that you | ||
24 | +have the freedom to distribute copies of free software (and charge for | ||
25 | +them if you wish), that you receive source code or can get it if you | ||
26 | +want it, that you can change the software or use pieces of it in new | ||
27 | +free programs, and that you know you can do these things. | ||
28 | + | ||
29 | + To protect your rights, we need to prevent others from denying you | ||
30 | +these rights or asking you to surrender the rights. Therefore, you have | ||
31 | +certain responsibilities if you distribute copies of the software, or if | ||
32 | +you modify it: responsibilities to respect the freedom of others. | ||
33 | + | ||
34 | + For example, if you distribute copies of such a program, whether | ||
35 | +gratis or for a fee, you must pass on to the recipients the same | ||
36 | +freedoms that you received. You must make sure that they, too, receive | ||
37 | +or can get the source code. And you must show them these terms so they | ||
38 | +know their rights. | ||
39 | + | ||
40 | + Developers that use the GNU GPL protect your rights with two steps: | ||
41 | +(1) assert copyright on the software, and (2) offer you this License | ||
42 | +giving you legal permission to copy, distribute and/or modify it. | ||
43 | + | ||
44 | + For the developers' and authors' protection, the GPL clearly explains | ||
45 | +that there is no warranty for this free software. For both users' and | ||
46 | +authors' sake, the GPL requires that modified versions be marked as | ||
47 | +changed, so that their problems will not be attributed erroneously to | ||
48 | +authors of previous versions. | ||
49 | + | ||
50 | + Some devices are designed to deny users access to install or run | ||
51 | +modified versions of the software inside them, although the manufacturer | ||
52 | +can do so. This is fundamentally incompatible with the aim of | ||
53 | +protecting users' freedom to change the software. The systematic | ||
54 | +pattern of such abuse occurs in the area of products for individuals to | ||
55 | +use, which is precisely where it is most unacceptable. Therefore, we | ||
56 | +have designed this version of the GPL to prohibit the practice for those | ||
57 | +products. If such problems arise substantially in other domains, we | ||
58 | +stand ready to extend this provision to those domains in future versions | ||
59 | +of the GPL, as needed to protect the freedom of users. | ||
60 | + | ||
61 | + Finally, every program is threatened constantly by software patents. | ||
62 | +States should not allow patents to restrict development and use of | ||
63 | +software on general-purpose computers, but in those that do, we wish to | ||
64 | +avoid the special danger that patents applied to a free program could | ||
65 | +make it effectively proprietary. To prevent this, the GPL assures that | ||
66 | +patents cannot be used to render the program non-free. | ||
67 | + | ||
68 | + The precise terms and conditions for copying, distribution and | ||
69 | +modification follow. | ||
70 | + | ||
71 | + TERMS AND CONDITIONS | ||
72 | + | ||
73 | + 0. Definitions. | ||
74 | + | ||
75 | + "This License" refers to version 3 of the GNU General Public License. | ||
76 | + | ||
77 | + "Copyright" also means copyright-like laws that apply to other kinds of | ||
78 | +works, such as semiconductor masks. | ||
79 | + | ||
80 | + "The Program" refers to any copyrightable work licensed under this | ||
81 | +License. Each licensee is addressed as "you". "Licensees" and | ||
82 | +"recipients" may be individuals or organizations. | ||
83 | + | ||
84 | + To "modify" a work means to copy from or adapt all or part of the work | ||
85 | +in a fashion requiring copyright permission, other than the making of an | ||
86 | +exact copy. The resulting work is called a "modified version" of the | ||
87 | +earlier work or a work "based on" the earlier work. | ||
88 | + | ||
89 | + A "covered work" means either the unmodified Program or a work based | ||
90 | +on the Program. | ||
91 | + | ||
92 | + To "propagate" a work means to do anything with it that, without | ||
93 | +permission, would make you directly or secondarily liable for | ||
94 | +infringement under applicable copyright law, except executing it on a | ||
95 | +computer or modifying a private copy. Propagation includes copying, | ||
96 | +distribution (with or without modification), making available to the | ||
97 | +public, and in some countries other activities as well. | ||
98 | + | ||
99 | + To "convey" a work means any kind of propagation that enables other | ||
100 | +parties to make or receive copies. Mere interaction with a user through | ||
101 | +a computer network, with no transfer of a copy, is not conveying. | ||
102 | + | ||
103 | + An interactive user interface displays "Appropriate Legal Notices" | ||
104 | +to the extent that it includes a convenient and prominently visible | ||
105 | +feature that (1) displays an appropriate copyright notice, and (2) | ||
106 | +tells the user that there is no warranty for the work (except to the | ||
107 | +extent that warranties are provided), that licensees may convey the | ||
108 | +work under this License, and how to view a copy of this License. If | ||
109 | +the interface presents a list of user commands or options, such as a | ||
110 | +menu, a prominent item in the list meets this criterion. | ||
111 | + | ||
112 | + 1. Source Code. | ||
113 | + | ||
114 | + The "source code" for a work means the preferred form of the work | ||
115 | +for making modifications to it. "Object code" means any non-source | ||
116 | +form of a work. | ||
117 | + | ||
118 | + A "Standard Interface" means an interface that either is an official | ||
119 | +standard defined by a recognized standards body, or, in the case of | ||
120 | +interfaces specified for a particular programming language, one that | ||
121 | +is widely used among developers working in that language. | ||
122 | + | ||
123 | + The "System Libraries" of an executable work include anything, other | ||
124 | +than the work as a whole, that (a) is included in the normal form of | ||
125 | +packaging a Major Component, but which is not part of that Major | ||
126 | +Component, and (b) serves only to enable use of the work with that | ||
127 | +Major Component, or to implement a Standard Interface for which an | ||
128 | +implementation is available to the public in source code form. A | ||
129 | +"Major Component", in this context, means a major essential component | ||
130 | +(kernel, window system, and so on) of the specific operating system | ||
131 | +(if any) on which the executable work runs, or a compiler used to | ||
132 | +produce the work, or an object code interpreter used to run it. | ||
133 | + | ||
134 | + The "Corresponding Source" for a work in object code form means all | ||
135 | +the source code needed to generate, install, and (for an executable | ||
136 | +work) run the object code and to modify the work, including scripts to | ||
137 | +control those activities. However, it does not include the work's | ||
138 | +System Libraries, or general-purpose tools or generally available free | ||
139 | +programs which are used unmodified in performing those activities but | ||
140 | +which are not part of the work. For example, Corresponding Source | ||
141 | +includes interface definition files associated with source files for | ||
142 | +the work, and the source code for shared libraries and dynamically | ||
143 | +linked subprograms that the work is specifically designed to require, | ||
144 | +such as by intimate data communication or control flow between those | ||
145 | +subprograms and other parts of the work. | ||
146 | + | ||
147 | + The Corresponding Source need not include anything that users | ||
148 | +can regenerate automatically from other parts of the Corresponding | ||
149 | +Source. | ||
150 | + | ||
151 | + The Corresponding Source for a work in source code form is that | ||
152 | +same work. | ||
153 | + | ||
154 | + 2. Basic Permissions. | ||
155 | + | ||
156 | + All rights granted under this License are granted for the term of | ||
157 | +copyright on the Program, and are irrevocable provided the stated | ||
158 | +conditions are met. This License explicitly affirms your unlimited | ||
159 | +permission to run the unmodified Program. The output from running a | ||
160 | +covered work is covered by this License only if the output, given its | ||
161 | +content, constitutes a covered work. This License acknowledges your | ||
162 | +rights of fair use or other equivalent, as provided by copyright law. | ||
163 | + | ||
164 | + You may make, run and propagate covered works that you do not | ||
165 | +convey, without conditions so long as your license otherwise remains | ||
166 | +in force. You may convey covered works to others for the sole purpose | ||
167 | +of having them make modifications exclusively for you, or provide you | ||
168 | +with facilities for running those works, provided that you comply with | ||
169 | +the terms of this License in conveying all material for which you do | ||
170 | +not control copyright. Those thus making or running the covered works | ||
171 | +for you must do so exclusively on your behalf, under your direction | ||
172 | +and control, on terms that prohibit them from making any copies of | ||
173 | +your copyrighted material outside their relationship with you. | ||
174 | + | ||
175 | + Conveying under any other circumstances is permitted solely under | ||
176 | +the conditions stated below. Sublicensing is not allowed; section 10 | ||
177 | +makes it unnecessary. | ||
178 | + | ||
179 | + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. | ||
180 | + | ||
181 | + No covered work shall be deemed part of an effective technological | ||
182 | +measure under any applicable law fulfilling obligations under article | ||
183 | +11 of the WIPO copyright treaty adopted on 20 December 1996, or | ||
184 | +similar laws prohibiting or restricting circumvention of such | ||
185 | +measures. | ||
186 | + | ||
187 | + When you convey a covered work, you waive any legal power to forbid | ||
188 | +circumvention of technological measures to the extent such circumvention | ||
189 | +is effected by exercising rights under this License with respect to | ||
190 | +the covered work, and you disclaim any intention to limit operation or | ||
191 | +modification of the work as a means of enforcing, against the work's | ||
192 | +users, your or third parties' legal rights to forbid circumvention of | ||
193 | +technological measures. | ||
194 | + | ||
195 | + 4. Conveying Verbatim Copies. | ||
196 | + | ||
197 | + You may convey verbatim copies of the Program's source code as you | ||
198 | +receive it, in any medium, provided that you conspicuously and | ||
199 | +appropriately publish on each copy an appropriate copyright notice; | ||
200 | +keep intact all notices stating that this License and any | ||
201 | +non-permissive terms added in accord with section 7 apply to the code; | ||
202 | +keep intact all notices of the absence of any warranty; and give all | ||
203 | +recipients a copy of this License along with the Program. | ||
204 | + | ||
205 | + You may charge any price or no price for each copy that you convey, | ||
206 | +and you may offer support or warranty protection for a fee. | ||
207 | + | ||
208 | + 5. Conveying Modified Source Versions. | ||
209 | + | ||
210 | + You may convey a work based on the Program, or the modifications to | ||
211 | +produce it from the Program, in the form of source code under the | ||
212 | +terms of section 4, provided that you also meet all of these conditions: | ||
213 | + | ||
214 | + a) The work must carry prominent notices stating that you modified | ||
215 | + it, and giving a relevant date. | ||
216 | + | ||
217 | + b) The work must carry prominent notices stating that it is | ||
218 | + released under this License and any conditions added under section | ||
219 | + 7. This requirement modifies the requirement in section 4 to | ||
220 | + "keep intact all notices". | ||
221 | + | ||
222 | + c) You must license the entire work, as a whole, under this | ||
223 | + License to anyone who comes into possession of a copy. This | ||
224 | + License will therefore apply, along with any applicable section 7 | ||
225 | + additional terms, to the whole of the work, and all its parts, | ||
226 | + regardless of how they are packaged. This License gives no | ||
227 | + permission to license the work in any other way, but it does not | ||
228 | + invalidate such permission if you have separately received it. | ||
229 | + | ||
230 | + d) If the work has interactive user interfaces, each must display | ||
231 | + Appropriate Legal Notices; however, if the Program has interactive | ||
232 | + interfaces that do not display Appropriate Legal Notices, your | ||
233 | + work need not make them do so. | ||
234 | + | ||
235 | + A compilation of a covered work with other separate and independent | ||
236 | +works, which are not by their nature extensions of the covered work, | ||
237 | +and which are not combined with it such as to form a larger program, | ||
238 | +in or on a volume of a storage or distribution medium, is called an | ||
239 | +"aggregate" if the compilation and its resulting copyright are not | ||
240 | +used to limit the access or legal rights of the compilation's users | ||
241 | +beyond what the individual works permit. Inclusion of a covered work | ||
242 | +in an aggregate does not cause this License to apply to the other | ||
243 | +parts of the aggregate. | ||
244 | + | ||
245 | + 6. Conveying Non-Source Forms. | ||
246 | + | ||
247 | + You may convey a covered work in object code form under the terms | ||
248 | +of sections 4 and 5, provided that you also convey the | ||
249 | +machine-readable Corresponding Source under the terms of this License, | ||
250 | +in one of these ways: | ||
251 | + | ||
252 | + a) Convey the object code in, or embodied in, a physical product | ||
253 | + (including a physical distribution medium), accompanied by the | ||
254 | + Corresponding Source fixed on a durable physical medium | ||
255 | + customarily used for software interchange. | ||
256 | + | ||
257 | + b) Convey the object code in, or embodied in, a physical product | ||
258 | + (including a physical distribution medium), accompanied by a | ||
259 | + written offer, valid for at least three years and valid for as | ||
260 | + long as you offer spare parts or customer support for that product | ||
261 | + model, to give anyone who possesses the object code either (1) a | ||
262 | + copy of the Corresponding Source for all the software in the | ||
263 | + product that is covered by this License, on a durable physical | ||
264 | + medium customarily used for software interchange, for a price no | ||
265 | + more than your reasonable cost of physically performing this | ||
266 | + conveying of source, or (2) access to copy the | ||
267 | + Corresponding Source from a network server at no charge. | ||
268 | + | ||
269 | + c) Convey individual copies of the object code with a copy of the | ||
270 | + written offer to provide the Corresponding Source. This | ||
271 | + alternative is allowed only occasionally and noncommercially, and | ||
272 | + only if you received the object code with such an offer, in accord | ||
273 | + with subsection 6b. | ||
274 | + | ||
275 | + d) Convey the object code by offering access from a designated | ||
276 | + place (gratis or for a charge), and offer equivalent access to the | ||
277 | + Corresponding Source in the same way through the same place at no | ||
278 | + further charge. You need not require recipients to copy the | ||
279 | + Corresponding Source along with the object code. If the place to | ||
280 | + copy the object code is a network server, the Corresponding Source | ||
281 | + may be on a different server (operated by you or a third party) | ||
282 | + that supports equivalent copying facilities, provided you maintain | ||
283 | + clear directions next to the object code saying where to find the | ||
284 | + Corresponding Source. Regardless of what server hosts the | ||
285 | + Corresponding Source, you remain obligated to ensure that it is | ||
286 | + available for as long as needed to satisfy these requirements. | ||
287 | + | ||
288 | + e) Convey the object code using peer-to-peer transmission, provided | ||
289 | + you inform other peers where the object code and Corresponding | ||
290 | + Source of the work are being offered to the general public at no | ||
291 | + charge under subsection 6d. | ||
292 | + | ||
293 | + A separable portion of the object code, whose source code is excluded | ||
294 | +from the Corresponding Source as a System Library, need not be | ||
295 | +included in conveying the object code work. | ||
296 | + | ||
297 | + A "User Product" is either (1) a "consumer product", which means any | ||
298 | +tangible personal property which is normally used for personal, family, | ||
299 | +or household purposes, or (2) anything designed or sold for incorporation | ||
300 | +into a dwelling. In determining whether a product is a consumer product, | ||
301 | +doubtful cases shall be resolved in favor of coverage. For a particular | ||
302 | +product received by a particular user, "normally used" refers to a | ||
303 | +typical or common use of that class of product, regardless of the status | ||
304 | +of the particular user or of the way in which the particular user | ||
305 | +actually uses, or expects or is expected to use, the product. A product | ||
306 | +is a consumer product regardless of whether the product has substantial | ||
307 | +commercial, industrial or non-consumer uses, unless such uses represent | ||
308 | +the only significant mode of use of the product. | ||
309 | + | ||
310 | + "Installation Information" for a User Product means any methods, | ||
311 | +procedures, authorization keys, or other information required to install | ||
312 | +and execute modified versions of a covered work in that User Product from | ||
313 | +a modified version of its Corresponding Source. The information must | ||
314 | +suffice to ensure that the continued functioning of the modified object | ||
315 | +code is in no case prevented or interfered with solely because | ||
316 | +modification has been made. | ||
317 | + | ||
318 | + If you convey an object code work under this section in, or with, or | ||
319 | +specifically for use in, a User Product, and the conveying occurs as | ||
320 | +part of a transaction in which the right of possession and use of the | ||
321 | +User Product is transferred to the recipient in perpetuity or for a | ||
322 | +fixed term (regardless of how the transaction is characterized), the | ||
323 | +Corresponding Source conveyed under this section must be accompanied | ||
324 | +by the Installation Information. But this requirement does not apply | ||
325 | +if neither you nor any third party retains the ability to install | ||
326 | +modified object code on the User Product (for example, the work has | ||
327 | +been installed in ROM). | ||
328 | + | ||
329 | + The requirement to provide Installation Information does not include a | ||
330 | +requirement to continue to provide support service, warranty, or updates | ||
331 | +for a work that has been modified or installed by the recipient, or for | ||
332 | +the User Product in which it has been modified or installed. Access to a | ||
333 | +network may be denied when the modification itself materially and | ||
334 | +adversely affects the operation of the network or violates the rules and | ||
335 | +protocols for communication across the network. | ||
336 | + | ||
337 | + Corresponding Source conveyed, and Installation Information provided, | ||
338 | +in accord with this section must be in a format that is publicly | ||
339 | +documented (and with an implementation available to the public in | ||
340 | +source code form), and must require no special password or key for | ||
341 | +unpacking, reading or copying. | ||
342 | + | ||
343 | + 7. Additional Terms. | ||
344 | + | ||
345 | + "Additional permissions" are terms that supplement the terms of this | ||
346 | +License by making exceptions from one or more of its conditions. | ||
347 | +Additional permissions that are applicable to the entire Program shall | ||
348 | +be treated as though they were included in this License, to the extent | ||
349 | +that they are valid under applicable law. If additional permissions | ||
350 | +apply only to part of the Program, that part may be used separately | ||
351 | +under those permissions, but the entire Program remains governed by | ||
352 | +this License without regard to the additional permissions. | ||
353 | + | ||
354 | + When you convey a copy of a covered work, you may at your option | ||
355 | +remove any additional permissions from that copy, or from any part of | ||
356 | +it. (Additional permissions may be written to require their own | ||
357 | +removal in certain cases when you modify the work.) You may place | ||
358 | +additional permissions on material, added by you to a covered work, | ||
359 | +for which you have or can give appropriate copyright permission. | ||
360 | + | ||
361 | + Notwithstanding any other provision of this License, for material you | ||
362 | +add to a covered work, you may (if authorized by the copyright holders of | ||
363 | +that material) supplement the terms of this License with terms: | ||
364 | + | ||
365 | + a) Disclaiming warranty or limiting liability differently from the | ||
366 | + terms of sections 15 and 16 of this License; or | ||
367 | + | ||
368 | + b) Requiring preservation of specified reasonable legal notices or | ||
369 | + author attributions in that material or in the Appropriate Legal | ||
370 | + Notices displayed by works containing it; or | ||
371 | + | ||
372 | + c) Prohibiting misrepresentation of the origin of that material, or | ||
373 | + requiring that modified versions of such material be marked in | ||
374 | + reasonable ways as different from the original version; or | ||
375 | + | ||
376 | + d) Limiting the use for publicity purposes of names of licensors or | ||
377 | + authors of the material; or | ||
378 | + | ||
379 | + e) Declining to grant rights under trademark law for use of some | ||
380 | + trade names, trademarks, or service marks; or | ||
381 | + | ||
382 | + f) Requiring indemnification of licensors and authors of that | ||
383 | + material by anyone who conveys the material (or modified versions of | ||
384 | + it) with contractual assumptions of liability to the recipient, for | ||
385 | + any liability that these contractual assumptions directly impose on | ||
386 | + those licensors and authors. | ||
387 | + | ||
388 | + All other non-permissive additional terms are considered "further | ||
389 | +restrictions" within the meaning of section 10. If the Program as you | ||
390 | +received it, or any part of it, contains a notice stating that it is | ||
391 | +governed by this License along with a term that is a further | ||
392 | +restriction, you may remove that term. If a license document contains | ||
393 | +a further restriction but permits relicensing or conveying under this | ||
394 | +License, you may add to a covered work material governed by the terms | ||
395 | +of that license document, provided that the further restriction does | ||
396 | +not survive such relicensing or conveying. | ||
397 | + | ||
398 | + If you add terms to a covered work in accord with this section, you | ||
399 | +must place, in the relevant source files, a statement of the | ||
400 | +additional terms that apply to those files, or a notice indicating | ||
401 | +where to find the applicable terms. | ||
402 | + | ||
403 | + Additional terms, permissive or non-permissive, may be stated in the | ||
404 | +form of a separately written license, or stated as exceptions; | ||
405 | +the above requirements apply either way. | ||
406 | + | ||
407 | + 8. Termination. | ||
408 | + | ||
409 | + You may not propagate or modify a covered work except as expressly | ||
410 | +provided under this License. Any attempt otherwise to propagate or | ||
411 | +modify it is void, and will automatically terminate your rights under | ||
412 | +this License (including any patent licenses granted under the third | ||
413 | +paragraph of section 11). | ||
414 | + | ||
415 | + However, if you cease all violation of this License, then your | ||
416 | +license from a particular copyright holder is reinstated (a) | ||
417 | +provisionally, unless and until the copyright holder explicitly and | ||
418 | +finally terminates your license, and (b) permanently, if the copyright | ||
419 | +holder fails to notify you of the violation by some reasonable means | ||
420 | +prior to 60 days after the cessation. | ||
421 | + | ||
422 | + Moreover, your license from a particular copyright holder is | ||
423 | +reinstated permanently if the copyright holder notifies you of the | ||
424 | +violation by some reasonable means, this is the first time you have | ||
425 | +received notice of violation of this License (for any work) from that | ||
426 | +copyright holder, and you cure the violation prior to 30 days after | ||
427 | +your receipt of the notice. | ||
428 | + | ||
429 | + Termination of your rights under this section does not terminate the | ||
430 | +licenses of parties who have received copies or rights from you under | ||
431 | +this License. If your rights have been terminated and not permanently | ||
432 | +reinstated, you do not qualify to receive new licenses for the same | ||
433 | +material under section 10. | ||
434 | + | ||
435 | + 9. Acceptance Not Required for Having Copies. | ||
436 | + | ||
437 | + You are not required to accept this License in order to receive or | ||
438 | +run a copy of the Program. Ancillary propagation of a covered work | ||
439 | +occurring solely as a consequence of using peer-to-peer transmission | ||
440 | +to receive a copy likewise does not require acceptance. However, | ||
441 | +nothing other than this License grants you permission to propagate or | ||
442 | +modify any covered work. These actions infringe copyright if you do | ||
443 | +not accept this License. Therefore, by modifying or propagating a | ||
444 | +covered work, you indicate your acceptance of this License to do so. | ||
445 | + | ||
446 | + 10. Automatic Licensing of Downstream Recipients. | ||
447 | + | ||
448 | + Each time you convey a covered work, the recipient automatically | ||
449 | +receives a license from the original licensors, to run, modify and | ||
450 | +propagate that work, subject to this License. You are not responsible | ||
451 | +for enforcing compliance by third parties with this License. | ||
452 | + | ||
453 | + An "entity transaction" is a transaction transferring control of an | ||
454 | +organization, or substantially all assets of one, or subdividing an | ||
455 | +organization, or merging organizations. If propagation of a covered | ||
456 | +work results from an entity transaction, each party to that | ||
457 | +transaction who receives a copy of the work also receives whatever | ||
458 | +licenses to the work the party's predecessor in interest had or could | ||
459 | +give under the previous paragraph, plus a right to possession of the | ||
460 | +Corresponding Source of the work from the predecessor in interest, if | ||
461 | +the predecessor has it or can get it with reasonable efforts. | ||
462 | + | ||
463 | + You may not impose any further restrictions on the exercise of the | ||
464 | +rights granted or affirmed under this License. For example, you may | ||
465 | +not impose a license fee, royalty, or other charge for exercise of | ||
466 | +rights granted under this License, and you may not initiate litigation | ||
467 | +(including a cross-claim or counterclaim in a lawsuit) alleging that | ||
468 | +any patent claim is infringed by making, using, selling, offering for | ||
469 | +sale, or importing the Program or any portion of it. | ||
470 | + | ||
471 | + 11. Patents. | ||
472 | + | ||
473 | + A "contributor" is a copyright holder who authorizes use under this | ||
474 | +License of the Program or a work on which the Program is based. The | ||
475 | +work thus licensed is called the contributor's "contributor version". | ||
476 | + | ||
477 | + A contributor's "essential patent claims" are all patent claims | ||
478 | +owned or controlled by the contributor, whether already acquired or | ||
479 | +hereafter acquired, that would be infringed by some manner, permitted | ||
480 | +by this License, of making, using, or selling its contributor version, | ||
481 | +but do not include claims that would be infringed only as a | ||
482 | +consequence of further modification of the contributor version. For | ||
483 | +purposes of this definition, "control" includes the right to grant | ||
484 | +patent sublicenses in a manner consistent with the requirements of | ||
485 | +this License. | ||
486 | + | ||
487 | + Each contributor grants you a non-exclusive, worldwide, royalty-free | ||
488 | +patent license under the contributor's essential patent claims, to | ||
489 | +make, use, sell, offer for sale, import and otherwise run, modify and | ||
490 | +propagate the contents of its contributor version. | ||
491 | + | ||
492 | + In the following three paragraphs, a "patent license" is any express | ||
493 | +agreement or commitment, however denominated, not to enforce a patent | ||
494 | +(such as an express permission to practice a patent or covenant not to | ||
495 | +sue for patent infringement). To "grant" such a patent license to a | ||
496 | +party means to make such an agreement or commitment not to enforce a | ||
497 | +patent against the party. | ||
498 | + | ||
499 | + If you convey a covered work, knowingly relying on a patent license, | ||
500 | +and the Corresponding Source of the work is not available for anyone | ||
501 | +to copy, free of charge and under the terms of this License, through a | ||
502 | +publicly available network server or other readily accessible means, | ||
503 | +then you must either (1) cause the Corresponding Source to be so | ||
504 | +available, or (2) arrange to deprive yourself of the benefit of the | ||
505 | +patent license for this particular work, or (3) arrange, in a manner | ||
506 | +consistent with the requirements of this License, to extend the patent | ||
507 | +license to downstream recipients. "Knowingly relying" means you have | ||
508 | +actual knowledge that, but for the patent license, your conveying the | ||
509 | +covered work in a country, or your recipient's use of the covered work | ||
510 | +in a country, would infringe one or more identifiable patents in that | ||
511 | +country that you have reason to believe are valid. | ||
512 | + | ||
513 | + If, pursuant to or in connection with a single transaction or | ||
514 | +arrangement, you convey, or propagate by procuring conveyance of, a | ||
515 | +covered work, and grant a patent license to some of the parties | ||
516 | +receiving the covered work authorizing them to use, propagate, modify | ||
517 | +or convey a specific copy of the covered work, then the patent license | ||
518 | +you grant is automatically extended to all recipients of the covered | ||
519 | +work and works based on it. | ||
520 | + | ||
521 | + A patent license is "discriminatory" if it does not include within | ||
522 | +the scope of its coverage, prohibits the exercise of, or is | ||
523 | +conditioned on the non-exercise of one or more of the rights that are | ||
524 | +specifically granted under this License. You may not convey a covered | ||
525 | +work if you are a party to an arrangement with a third party that is | ||
526 | +in the business of distributing software, under which you make payment | ||
527 | +to the third party based on the extent of your activity of conveying | ||
528 | +the work, and under which the third party grants, to any of the | ||
529 | +parties who would receive the covered work from you, a discriminatory | ||
530 | +patent license (a) in connection with copies of the covered work | ||
531 | +conveyed by you (or copies made from those copies), or (b) primarily | ||
532 | +for and in connection with specific products or compilations that | ||
533 | +contain the covered work, unless you entered into that arrangement, | ||
534 | +or that patent license was granted, prior to 28 March 2007. | ||
535 | + | ||
536 | + Nothing in this License shall be construed as excluding or limiting | ||
537 | +any implied license or other defenses to infringement that may | ||
538 | +otherwise be available to you under applicable patent law. | ||
539 | + | ||
540 | + 12. No Surrender of Others' Freedom. | ||
541 | + | ||
542 | + If conditions are imposed on you (whether by court order, agreement or | ||
543 | +otherwise) that contradict the conditions of this License, they do not | ||
544 | +excuse you from the conditions of this License. If you cannot convey a | ||
545 | +covered work so as to satisfy simultaneously your obligations under this | ||
546 | +License and any other pertinent obligations, then as a consequence you may | ||
547 | +not convey it at all. For example, if you agree to terms that obligate you | ||
548 | +to collect a royalty for further conveying from those to whom you convey | ||
549 | +the Program, the only way you could satisfy both those terms and this | ||
550 | +License would be to refrain entirely from conveying the Program. | ||
551 | + | ||
552 | + 13. Use with the GNU Affero General Public License. | ||
553 | + | ||
554 | + Notwithstanding any other provision of this License, you have | ||
555 | +permission to link or combine any covered work with a work licensed | ||
556 | +under version 3 of the GNU Affero General Public License into a single | ||
557 | +combined work, and to convey the resulting work. The terms of this | ||
558 | +License will continue to apply to the part which is the covered work, | ||
559 | +but the special requirements of the GNU Affero General Public License, | ||
560 | +section 13, concerning interaction through a network will apply to the | ||
561 | +combination as such. | ||
562 | + | ||
563 | + 14. Revised Versions of this License. | ||
564 | + | ||
565 | + The Free Software Foundation may publish revised and/or new versions of | ||
566 | +the GNU General Public License from time to time. Such new versions will | ||
567 | +be similar in spirit to the present version, but may differ in detail to | ||
568 | +address new problems or concerns. | ||
569 | + | ||
570 | + Each version is given a distinguishing version number. If the | ||
571 | +Program specifies that a certain numbered version of the GNU General | ||
572 | +Public License "or any later version" applies to it, you have the | ||
573 | +option of following the terms and conditions either of that numbered | ||
574 | +version or of any later version published by the Free Software | ||
575 | +Foundation. If the Program does not specify a version number of the | ||
576 | +GNU General Public License, you may choose any version ever published | ||
577 | +by the Free Software Foundation. | ||
578 | + | ||
579 | + If the Program specifies that a proxy can decide which future | ||
580 | +versions of the GNU General Public License can be used, that proxy's | ||
581 | +public statement of acceptance of a version permanently authorizes you | ||
582 | +to choose that version for the Program. | ||
583 | + | ||
584 | + Later license versions may give you additional or different | ||
585 | +permissions. However, no additional obligations are imposed on any | ||
586 | +author or copyright holder as a result of your choosing to follow a | ||
587 | +later version. | ||
588 | + | ||
589 | + 15. Disclaimer of Warranty. | ||
590 | + | ||
591 | + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY | ||
592 | +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT | ||
593 | +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY | ||
594 | +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, | ||
595 | +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
596 | +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM | ||
597 | +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF | ||
598 | +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. | ||
599 | + | ||
600 | + 16. Limitation of Liability. | ||
601 | + | ||
602 | + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | ||
603 | +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS | ||
604 | +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY | ||
605 | +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE | ||
606 | +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF | ||
607 | +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD | ||
608 | +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), | ||
609 | +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF | ||
610 | +SUCH DAMAGES. | ||
611 | + | ||
612 | + 17. Interpretation of Sections 15 and 16. | ||
613 | + | ||
614 | + If the disclaimer of warranty and limitation of liability provided | ||
615 | +above cannot be given local legal effect according to their terms, | ||
616 | +reviewing courts shall apply local law that most closely approximates | ||
617 | +an absolute waiver of all civil liability in connection with the | ||
618 | +Program, unless a warranty or assumption of liability accompanies a | ||
619 | +copy of the Program in return for a fee. | ||
620 | + | ||
621 | + END OF TERMS AND CONDITIONS | ||
622 | + | ||
623 | + How to Apply These Terms to Your New Programs | ||
624 | + | ||
625 | + If you develop a new program, and you want it to be of the greatest | ||
626 | +possible use to the public, the best way to achieve this is to make it | ||
627 | +free software which everyone can redistribute and change under these terms. | ||
628 | + | ||
629 | + To do so, attach the following notices to the program. It is safest | ||
630 | +to attach them to the start of each source file to most effectively | ||
631 | +state the exclusion of warranty; and each file should have at least | ||
632 | +the "copyright" line and a pointer to where the full notice is found. | ||
633 | + | ||
634 | + <one line to give the program's name and a brief idea of what it does.> | ||
635 | + Copyright (C) <year> <name of author> | ||
636 | + | ||
637 | + This program is free software: you can redistribute it and/or modify | ||
638 | + it under the terms of the GNU General Public License as published by | ||
639 | + the Free Software Foundation, either version 3 of the License, or | ||
640 | + (at your option) any later version. | ||
641 | + | ||
642 | + This program is distributed in the hope that it will be useful, | ||
643 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
644 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
645 | + GNU General Public License for more details. | ||
646 | + | ||
647 | + You should have received a copy of the GNU General Public License | ||
648 | + along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
649 | + | ||
650 | +Also add information on how to contact you by electronic and paper mail. | ||
651 | + | ||
652 | + If the program does terminal interaction, make it output a short | ||
653 | +notice like this when it starts in an interactive mode: | ||
654 | + | ||
655 | + <program> Copyright (C) <year> <name of author> | ||
656 | + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. | ||
657 | + This is free software, and you are welcome to redistribute it | ||
658 | + under certain conditions; type `show c' for details. | ||
659 | + | ||
660 | +The hypothetical commands `show w' and `show c' should show the appropriate | ||
661 | +parts of the General Public License. Of course, your program's commands | ||
662 | +might be different; for a GUI interface, you would use an "about box". | ||
663 | + | ||
664 | + You should also get your employer (if you work as a programmer) or school, | ||
665 | +if any, to sign a "copyright disclaimer" for the program, if necessary. | ||
666 | +For more information on this, and how to apply and follow the GNU GPL, see | ||
667 | +<http://www.gnu.org/licenses/>. | ||
668 | + | ||
669 | + The GNU General Public License does not permit incorporating your program | ||
670 | +into proprietary programs. If your program is a subroutine library, you | ||
671 | +may consider it more useful to permit linking proprietary applications with | ||
672 | +the library. If this is what you want to do, use the GNU Lesser General | ||
673 | +Public License instead of this License. But first, please read | ||
674 | +<http://www.gnu.org/philosophy/why-not-lgpl.html>. |
1 | +++ a/pf/__init__.py | ||
@@ -0,0 +1,6 @@ | @@ -0,0 +1,6 @@ | ||
1 | +# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages | ||
2 | +try: | ||
3 | + __import__('pkg_resources').declare_namespace(__name__) | ||
4 | +except ImportError: | ||
5 | + from pkgutil import extend_path | ||
6 | + __path__ = extend_path(__path__, __name__) |
1 | +++ a/pf/biblioteca/Extensions/install.py | ||
@@ -0,0 +1,22 @@ | @@ -0,0 +1,22 @@ | ||
1 | +# -*- coding: utf-8 -*- | ||
2 | + | ||
3 | +from plone import api | ||
4 | + | ||
5 | +from pf.biblioteca import logger | ||
6 | + | ||
7 | + | ||
8 | +def uninstall(portal, reinstall=False): | ||
9 | + if not reinstall: | ||
10 | + content = api.content.get(path='/biblioteca-de-processos') | ||
11 | + content_link = api.content.get(path='/servicos-do-portal/biblioteca-de-processos') | ||
12 | + | ||
13 | + if content: | ||
14 | + content.setLayout('folder_listing') | ||
15 | + # obj_state = api.content.get_state(obj=content) | ||
16 | + # if obj_state == 'published': | ||
17 | + # api.content.transition(obj=content, transition='retract') | ||
18 | + | ||
19 | + if content_link: | ||
20 | + api.content.delete(obj=content_link) | ||
21 | + | ||
22 | + logger.info("Desinstalação completa") |
1 | +++ a/pf/biblioteca/INTEGRATION.txt | ||
@@ -0,0 +1,36 @@ | @@ -0,0 +1,36 @@ | ||
1 | +Integration Tests | ||
2 | +----------------- | ||
3 | + | ||
4 | +This is a DocTest file, using the Python doctest format. | ||
5 | + | ||
6 | +In an integration test, here's some of the globals you have to work with:: | ||
7 | + | ||
8 | + >>> portal | ||
9 | + <PloneSite at /plone> | ||
10 | + | ||
11 | + >>> portal_name | ||
12 | + 'plone' | ||
13 | + | ||
14 | + >>> folder | ||
15 | + <ATFolder at /plone/Members/test_user_1_> | ||
16 | + | ||
17 | + >>> user_name | ||
18 | + 'test_user_1_' | ||
19 | + | ||
20 | + >>> user_password | ||
21 | + 'secret' | ||
22 | + | ||
23 | + >>> user_role | ||
24 | + 'test_role_1_' | ||
25 | + | ||
26 | + >>> app.REQUEST | ||
27 | + <HTTPRequest, URL=http://nohost> | ||
28 | + | ||
29 | + >>> app | ||
30 | + <Application at > | ||
31 | + | ||
32 | +Now, let's demonstrate a failing test:: | ||
33 | + | ||
34 | + >>> 1 == 2 # deliberately failing test; fix me! | ||
35 | + True | ||
36 | + |
1 | +++ a/pf/biblioteca/browser/__init__.py |
1 | +++ a/pf/biblioteca/browser/configure.zcml | ||
@@ -0,0 +1,16 @@ | @@ -0,0 +1,16 @@ | ||
1 | +<configure | ||
2 | + xmlns:browser="http://namespaces.zope.org/browser" | ||
3 | + xmlns="http://namespaces.zope.org/browser" | ||
4 | + xmlns:plone="http://namespaces.plone.org/plone" | ||
5 | + i18n_domain="pf.biblioteca"> | ||
6 | + | ||
7 | + | ||
8 | + <browser:page | ||
9 | + name="biblioteca-settings" | ||
10 | + for="Products.CMFPlone.interfaces.IPloneSiteRoot" | ||
11 | + permission="cmf.ManagePortal" | ||
12 | + class=".pages.SettingsEditView" | ||
13 | + /> | ||
14 | + | ||
15 | + | ||
16 | +</configure> | ||
0 | \ No newline at end of file | 17 | \ No newline at end of file |
1 | +++ a/pf/biblioteca/browser/interfaces.py | ||
@@ -0,0 +1,11 @@ | @@ -0,0 +1,11 @@ | ||
1 | +# -*- coding: utf-8 -*- | ||
2 | + | ||
3 | +from zope.interface import Interface | ||
4 | +from zope import schema | ||
5 | + | ||
6 | + | ||
7 | +class IBibliotecaControlPanel(Interface): | ||
8 | + """ | ||
9 | + Blicioteca ContralPanel interface | ||
10 | + """ | ||
11 | + email_cc = schema.TextLine(title=u"Email copia do formulário de contato das páginas de processos") |
1 | +++ a/pf/biblioteca/browser/pages.py | ||
@@ -0,0 +1,17 @@ | @@ -0,0 +1,17 @@ | ||
1 | +# -*- coding: utf-8 -*- | ||
2 | + | ||
3 | +from plone.z3cform import layout | ||
4 | +from plone.app.registry.browser.controlpanel import RegistryEditForm | ||
5 | +from plone.app.registry.browser.controlpanel import ControlPanelFormWrapper | ||
6 | + | ||
7 | +from pf.biblioteca.browser.interfaces import IBibliotecaControlPanel | ||
8 | + | ||
9 | + | ||
10 | +class SettingsEditForm(RegistryEditForm): | ||
11 | + """ | ||
12 | + Define form logic | ||
13 | + """ | ||
14 | + schema = IBibliotecaControlPanel | ||
15 | + | ||
16 | +SettingsEditView = layout.wrap_form(SettingsEditForm, ControlPanelFormWrapper) | ||
17 | +SettingsEditView.label = u"Biblioteca: Settings" |
1 | +++ a/pf/biblioteca/browser/templates/bibliotecaview.pt | ||
@@ -0,0 +1,87 @@ | @@ -0,0 +1,87 @@ | ||
1 | +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" | ||
2 | + xmlns:tal="http://xml.zope.org/namespaces/tal" | ||
3 | + xmlns:metal="http://xml.zope.org/namespaces/metal" | ||
4 | + xmlns:i18n="http://xml.zope.org/namespaces/i18n" | ||
5 | + lang="en" | ||
6 | + metal:use-macro="context/main_template/macros/master" | ||
7 | + i18n:domain="pf.biblioteca"> | ||
8 | + | ||
9 | + | ||
10 | +<tal:head metal:fill-slot="style_slot"> | ||
11 | + <link rel="stylesheet" type="text/css" href="biblioteca.css" media="screen" tal:attributes="href string:${context/portal_url}/++resource++pf.biblioteca/biblioteca.css"> | ||
12 | +</tal:head> | ||
13 | +<body> | ||
14 | + | ||
15 | +<metal:main fill-slot="main"> | ||
16 | + | ||
17 | + <div class="row"> | ||
18 | + <div class="cell width-full position-0 "> | ||
19 | + <div class="tile azul ui-droppable" > | ||
20 | + <div class="outstanding-header"> | ||
21 | + <h2 class="outstanding-title" tal:content="context/Title">Bem vindo ao Portal de Serviços da Intranet</h2> | ||
22 | + </div> | ||
23 | + </div> | ||
24 | + </div> | ||
25 | + </div> | ||
26 | + <div class="row"> | ||
27 | + <div class="cell width-full position-0 "> | ||
28 | + <div tal:content="structure view/get_description"></div> | ||
29 | + </div> | ||
30 | + </div> | ||
31 | + <div class="row"> | ||
32 | + <div class="cell width-full position-0 "> | ||
33 | + | ||
34 | + <metal:block metal:use-macro="context/biblioteca_busca_view/macros/busca" /> | ||
35 | + | ||
36 | + </div> | ||
37 | + </div> | ||
38 | + <div class="row"> | ||
39 | + <div class="cell width-full position-0 "> | ||
40 | + <div class="tile azul ui-droppable" > | ||
41 | + <div class="outstanding-header"> | ||
42 | + <h2 class="outstanding-title">Macroprocessos</h2> | ||
43 | + </div> | ||
44 | + </div> | ||
45 | + </div> | ||
46 | + </div> | ||
47 | + | ||
48 | + <tal:rep repeat="brains view/get_itens|python:[]"> | ||
49 | + <div class="row" > | ||
50 | + <tal:rep repeat="obj brains"> | ||
51 | + <div tal:define="index repeat/obj/index" | ||
52 | + class="cell width-5 position-0" tal:attributes="class python:'cell width-5 position-%s' %(view.position[index])" | ||
53 | + tal:condition="obj"> | ||
54 | + <div class="tile azul ui-droppable"> | ||
55 | + <div class="cover-richtext-tile tile-content"> | ||
56 | + <div id="titulo-macroprocesso"> | ||
57 | + <h4> | ||
58 | + <a tal:attributes="href obj/url; | ||
59 | + title obj/title" | ||
60 | + tal:content="obj/title">Investigação Criminal</a> | ||
61 | + </h4> | ||
62 | + </div> | ||
63 | + <a href="" | ||
64 | + tal:attributes="href obj/url; | ||
65 | + title obj/description"> | ||
66 | + <img src="" | ||
67 | + tal:define="scales obj/object/@@images; | ||
68 | + thumbnail python: scales.scale('imagem', width=250, height=250)" | ||
69 | + tal:condition="thumbnail" | ||
70 | + tal:attributes="src thumbnail/url; | ||
71 | + alt obj/title" /> | ||
72 | + </a> | ||
73 | + <hr /> | ||
74 | + </div> | ||
75 | + | ||
76 | + </div> | ||
77 | + </div> | ||
78 | + </tal:rep> | ||
79 | + </div> | ||
80 | + </tal:rep> | ||
81 | + | ||
82 | + | ||
83 | + | ||
84 | + | ||
85 | +</metal:main> | ||
86 | +</body> | ||
87 | +</html> |
1 | +++ a/pf/biblioteca/browser/templates/macroprocessoview.pt | ||
@@ -0,0 +1,42 @@ | @@ -0,0 +1,42 @@ | ||
1 | +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" | ||
2 | + xmlns:tal="http://xml.zope.org/namespaces/tal" | ||
3 | + xmlns:metal="http://xml.zope.org/namespaces/metal" | ||
4 | + xmlns:i18n="http://xml.zope.org/namespaces/i18n" | ||
5 | + lang="en" | ||
6 | + metal:use-macro="context/main_template/macros/master" | ||
7 | + i18n:domain="pf.biblioteca"> | ||
8 | + <body> | ||
9 | + | ||
10 | + <metal:main fill-slot="main"> | ||
11 | + <div class="row"> | ||
12 | + <div class="cell width-full position-0 "> | ||
13 | + <div class=" azul" > | ||
14 | + <div class="outstanding-header"> | ||
15 | + <h2 class="outstanding-title" tal:content="context/Title">Titulo</h2> | ||
16 | + </div> | ||
17 | + </div> | ||
18 | + </div> | ||
19 | + </div> | ||
20 | + <div class="row"> | ||
21 | + <div class="cell width-full position-0 "> | ||
22 | + <div> | ||
23 | + <p tal:content="structure context/Description">Descricao </p> | ||
24 | + <p tal:condition="view/get_itens">Veja abaixo o(s) processo(s) desse macroprocesso:</p> | ||
25 | + <p tal:condition="not: view/get_itens" class="discreet">Ainda não há processos cadastrados neste macroprocesso.</p> | ||
26 | + <ul> | ||
27 | + <tal:rep repeat="item view/get_itens"> | ||
28 | + <li> | ||
29 | + <strong> | ||
30 | + <a tal:attributes="href item/url" | ||
31 | + tal:content="item/title">Gerenciamento do Relató de Inteligêia Financeira da COAF | ||
32 | + </a> | ||
33 | + </strong> | ||
34 | + </li> | ||
35 | + </tal:rep> | ||
36 | + <ul> | ||
37 | + </div> | ||
38 | + </div> | ||
39 | + </div> | ||
40 | + </metal:main> | ||
41 | + </body> | ||
42 | +</html> |
1 | +++ a/pf/biblioteca/browser/templates/processoview.pt | ||
@@ -0,0 +1,111 @@ | @@ -0,0 +1,111 @@ | ||
1 | +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" | ||
2 | + xmlns:tal="http://xml.zope.org/namespaces/tal" | ||
3 | + xmlns:metal="http://xml.zope.org/namespaces/metal" | ||
4 | + xmlns:i18n="http://xml.zope.org/namespaces/i18n" | ||
5 | + lang="en" | ||
6 | + metal:use-macro="context/main_template/macros/master" | ||
7 | + i18n:domain="pf.biblioteca"> | ||
8 | +<body> | ||
9 | + | ||
10 | +<tal:head metal:fill-slot="style_slot"> | ||
11 | + <link rel="stylesheet" type="text/css" href="biblioteca.css" media="screen" tal:attributes="href string:${context/portal_url}/++resource++pf.biblioteca/biblioteca.css"> | ||
12 | +</tal:head> | ||
13 | + | ||
14 | +<metal:main fill-slot="main"> | ||
15 | + <metal:macro define-macro="page"> | ||
16 | + <div id="processo"> | ||
17 | + <h2 tal:content="context/Title"></h2> | ||
18 | + | ||
19 | + <div id="imagem-processo" tal:define="imagem_processo nocall:context/imagem_processo" | ||
20 | + tal:condition="nocall:imagem_processo"> | ||
21 | + <img align="left" width="250" height="250" style="margin: 0 10px 0 15px" tal:attributes="src string:${context/absolute_url}/@@download/imagem_processo/${imagem_processo/filename};"/> | ||
22 | + </div> | ||
23 | + | ||
24 | + <div> | ||
25 | + <p tal:content="structure context/Description">Descricao </p> | ||
26 | + </div> | ||
27 | + </div> | ||
28 | + <div class="row"> | ||
29 | + <div class="cell width-10 position-0"> | ||
30 | + <hr /> | ||
31 | + <h2>Informações</h2> | ||
32 | + <p> | ||
33 | + <label>Diretoria Responsável (Dono):</label><br> | ||
34 | + <span tal:content="context/diretoria_responsavel">DICORD/DPF</span> | ||
35 | + </p> | ||
36 | + <p> | ||
37 | + <label>Unidade Responsável (Gestor):</label><br> | ||
38 | + <span tal:content="context/unidade_responsavel">DICOR</span> | ||
39 | + </p> | ||
40 | + <p> | ||
41 | + <label>E-mail da Unidade Responsável:</label><br> | ||
42 | + <span tal:content="context/email_unidade">dicor@dpf.gov.br</span> | ||
43 | + </p> | ||
44 | + <p> | ||
45 | + <label>Telefone da Unidade Responsável:</label><br> | ||
46 | + <span tal:content="context/telefone_unidade">(xx)xxxx-xxxx</span> | ||
47 | + </p> | ||
48 | + <p tal:condition="context/responsavel_fluxo"> | ||
49 | + <label>Responsável pela Publicação do Fluxo na CIGE/DPF:</label><br> | ||
50 | + <span tal:content="context/responsavel_fluxo">João da Silva</span> | ||
51 | + </p> | ||
52 | + <p tal:condition="context/email_responsavel_fluxo"> | ||
53 | + <label>E-mail do Responsável pela Publicação do Fluxo na CIGE/DPF:</label><br> | ||
54 | + <span tal:content="context/email_responsavel_fluxo">joao@dpf.gov.br</span> | ||
55 | + </p> | ||
56 | + </div> | ||
57 | + | ||
58 | + <div class="cell width-5 position-10"> | ||
59 | + <hr /> | ||
60 | + <h2>Fluxo do Processo</h2> | ||
61 | + <a href="" tal:attributes="href context/link_bizagi" target="_blank"> | ||
62 | + <p>Clique no ícone abaixo para ter acesso ao fluxo e a toda documentação do processo, incluindo normas, manuais e formulários padronizados.</p></a> | ||
63 | + <div id="icone-processo"><a href="" tal:attributes="href context/link_bizagi" target="_blank"><img tal:attributes="src string:${context/portal_url}/++resource++pf.biblioteca/imagens/imagem-fluxo-processo.png" width="225" ></a></div> | ||
64 | + </div> | ||
65 | + | ||
66 | + | ||
67 | + </div> | ||
68 | + | ||
69 | + <div class="row"> | ||
70 | + <div class="cell width-full position-0"> | ||
71 | + <div class="tile azul ui-droppable" > | ||
72 | + <div class="outstanding-header"> | ||
73 | + <h2 class="outstanding-title">Fale com o Gestor do Processo</h2> | ||
74 | + </div> | ||
75 | + </div> | ||
76 | + | ||
77 | + | ||
78 | + <div tal:condition="context/portal_membership/isAnonymousUser" class="mensagem-login"> | ||
79 | + <p>É necessário estar logado ao sistema para enviar uma mensagem.</p> | ||
80 | + <a href="" tal:attributes="href string:${context/portal_url}/login_form?came_from=${context/absolute_url}"> | ||
81 | + <h4>Clique aqui para efetuar Login</h4> | ||
82 | + Utilize usuário e senha de e-mail</a> | ||
83 | + </div> | ||
84 | + | ||
85 | + <div tal:condition="not: context/portal_membership/isAnonymousUser"> | ||
86 | + | ||
87 | + <script type="text/javascript"> | ||
88 | + $(document).ready(function(){ | ||
89 | + $('#open_contact').click(function(event) { | ||
90 | + event.preventDefault(); | ||
91 | + $('#contact').toggle(); | ||
92 | + }); | ||
93 | + }); | ||
94 | + </script> | ||
95 | + | ||
96 | + <h4><a vertical-align="top" id="open_contact" href='#' ><img tal:attributes="src string:${context/portal_url}/++resource++pf.biblioteca/imagens/fale-conosco.png" width="35"> Clique aqui e envie sua dúvida, sugestão, reclamação, etc.</a></h4> | ||
97 | + | ||
98 | + <div id="contact" tal:attributes="style python: not request.form.get('submited') and 'display:none' or '' "> | ||
99 | + | ||
100 | + <metal:block metal:use-macro="context/contact_info/macros/contato" /> | ||
101 | + | ||
102 | + </div> | ||
103 | + | ||
104 | + </div> | ||
105 | + </div> | ||
106 | + </div> | ||
107 | + | ||
108 | + </metal:macro> | ||
109 | +</metal:main> | ||
110 | +</body> | ||
111 | +</html> |
1 | +++ a/pf/biblioteca/browser/views.py | ||
@@ -0,0 +1,97 @@ | @@ -0,0 +1,97 @@ | ||
1 | +# -*- coding: utf-8 -*- | ||
2 | + | ||
3 | +from five import grok | ||
4 | +from zope.interface import Interface | ||
5 | +from Products.CMFCore.utils import getToolByName | ||
6 | +from plone import api | ||
7 | + | ||
8 | +from pf.biblioteca.processo import IProcesso | ||
9 | + | ||
10 | +from itertools import izip_longest | ||
11 | + | ||
12 | + | ||
13 | +grok.templatedir('templates') | ||
14 | + | ||
15 | + | ||
16 | +class BibliotecaView(grok.View): | ||
17 | + grok.context(Interface) | ||
18 | + grok.require('zope2.View') | ||
19 | + grok.name('biblioteca_view') | ||
20 | + | ||
21 | + position = {0: '0', 1: '5', 2: '10'} | ||
22 | + | ||
23 | + def grouper(self, n, iterable, fillvalue=None): | ||
24 | + "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx" | ||
25 | + args = [iter(iterable)] * n | ||
26 | + return izip_longest(fillvalue=fillvalue, *args) | ||
27 | + | ||
28 | + def result2dict(self, brains): | ||
29 | + results = [] | ||
30 | + for brain in brains: | ||
31 | + obj = brain.getObject() | ||
32 | + results.append({ | ||
33 | + 'title': brain.Title, | ||
34 | + 'description': brain.Description, | ||
35 | + 'object': obj, | ||
36 | + 'url': obj.absolute_url() | ||
37 | + }) | ||
38 | + sorted_results = sorted(results, key=lambda k: k['title'].lower()) | ||
39 | + return self.grouper(3, sorted_results) | ||
40 | + | ||
41 | + def get_itens(self): | ||
42 | + pcatalog = getToolByName(self.context, 'portal_catalog') | ||
43 | + query = {'portal_type': ['pf.biblioteca.macroprocesso'], | ||
44 | + 'path': {'query': '/'.join(self.context.getPhysicalPath()), | ||
45 | + 'depth': 1}, | ||
46 | + } | ||
47 | + results = pcatalog(**query) | ||
48 | + return self.result2dict(results) | ||
49 | + | ||
50 | + def get_description(self): | ||
51 | + """ Verifica se existe um objeto do tipo 'Página' com o mesmo ID do diretório que se encontra | ||
52 | + Se houver, retorna o corpo do texto deste objeto como descrição da Home. """ | ||
53 | + folder_path = '/'.join(self.context.getPhysicalPath()) | ||
54 | + catalog = api.portal.get_tool(name='portal_catalog') | ||
55 | + brains = catalog(portal_type="Document", | ||
56 | + id=self.context.id, | ||
57 | + review_state='published', | ||
58 | + path={'query': folder_path, 'depth': 1}, | ||
59 | + sort_limit=1)[:1] | ||
60 | + if brains: | ||
61 | + obj = brains[0].getObject() | ||
62 | + return obj.text.output | ||
63 | + | ||
64 | + return self.context.Description() | ||
65 | + | ||
66 | + | ||
67 | +class MacroProcessoView(grok.View): | ||
68 | + grok.context(Interface) | ||
69 | + grok.require('zope2.View') | ||
70 | + grok.name('macroprocesso_view') | ||
71 | + grok.title(u'Visão padrão: Macroprocesso') | ||
72 | + | ||
73 | + def results2dict(self, brains): | ||
74 | + results = [] | ||
75 | + for brain in brains: | ||
76 | + obj = brain.getObject() | ||
77 | + results.append({ | ||
78 | + 'title': brain.Title, | ||
79 | + 'url': obj.absolute_url() | ||
80 | + }) | ||
81 | + sorted_results = sorted(results, key=lambda k: k['title'].lower()) | ||
82 | + return sorted_results | ||
83 | + | ||
84 | + def get_itens(self): | ||
85 | + pcatalog = getToolByName(self.context, 'portal_catalog') | ||
86 | + query = {'portal_type': ['pf.biblioteca.processo', 'pf.biblioteca.macroprocesso'], | ||
87 | + 'path': {'query': '/'.join(self.context.getPhysicalPath()), | ||
88 | + 'depth': 1}, | ||
89 | + } | ||
90 | + results = pcatalog(**query) | ||
91 | + return self.results2dict(results) | ||
92 | + | ||
93 | + | ||
94 | +class ProcessoView(grok.View): | ||
95 | + grok.context(IProcesso) | ||
96 | + grok.require('zope2.View') | ||
97 | + grok.name('view') |
1 | +++ a/pf/biblioteca/configure.zcml | ||
@@ -0,0 +1,39 @@ | @@ -0,0 +1,39 @@ | ||
1 | +<configure | ||
2 | + xmlns="http://namespaces.zope.org/zope" | ||
3 | + xmlns:five="http://namespaces.zope.org/five" | ||
4 | + xmlns:browser="http://namespaces.zope.org/browser" | ||
5 | + xmlns:i18n="http://namespaces.zope.org/i18n" | ||
6 | + xmlns:genericsetup="http://namespaces.zope.org/genericsetup" | ||
7 | + xmlns:grok="http://namespaces.zope.org/grok" | ||
8 | + xmlns:plone="http://namespaces.plone.org/plone" | ||
9 | + i18n_domain="pf.biblioteca"> | ||
10 | + | ||
11 | + <!-- Include configuration for dependencies listed in setup.py --> | ||
12 | + <includeDependencies package="." /> | ||
13 | + <include package=".browser" /> | ||
14 | + | ||
15 | + <!-- Grok the package to initialize schema interfaces and content classes --> | ||
16 | + <grok:grok package="." /> | ||
17 | + | ||
18 | + <!-- Needed for perform uninstall handler --> | ||
19 | + <five:registerPackage package="." /> | ||
20 | + | ||
21 | + <!-- Register a resource directory from which we can deploy static | ||
22 | + resource files. --> | ||
23 | + <browser:resourceDirectory | ||
24 | + name="pf.biblioteca" | ||
25 | + directory="resources" /> | ||
26 | + | ||
27 | + <i18n:registerTranslations directory="locales" /> | ||
28 | + | ||
29 | + <!-- Register an extension profile to make the product installable | ||
30 | + in Plone --> | ||
31 | + <genericsetup:registerProfile | ||
32 | + name="default" | ||
33 | + title="pf.biblioteca" | ||
34 | + directory="profiles/default" | ||
35 | + description="Extension profile for pf.biblioteca" | ||
36 | + provides="Products.GenericSetup.interfaces.EXTENSION" | ||
37 | + /> | ||
38 | + | ||
39 | +</configure> |
1 | +++ a/pf/biblioteca/macroprocesso.py | ||
@@ -0,0 +1,52 @@ | @@ -0,0 +1,52 @@ | ||
1 | +# -*- coding: utf-8 -*- | ||
2 | + | ||
3 | +from zope import schema | ||
4 | +from plone.dexterity.content import Container | ||
5 | +from plone.supermodel import model | ||
6 | +from plone.autoform import directives as form | ||
7 | +from z3c.form.browser.text import TextWidget | ||
8 | +from plone.app.z3cform.wysiwyg import WysiwygFieldWidget | ||
9 | + | ||
10 | +from five import grok | ||
11 | + | ||
12 | +from plone.namedfile.field import NamedBlobImage | ||
13 | +from pf.biblioteca import MessageFactory as _ | ||
14 | + | ||
15 | + | ||
16 | +class IMacroProcesso(model.Schema): | ||
17 | + """ | ||
18 | + Macroprocesso | ||
19 | + """ | ||
20 | + # http://docs.plone.org/external/plone.app.dexterity/docs/reference/fields.html | ||
21 | + # http://docs.plone.org/external/plone.app.dexterity/docs/reference/widgets.html | ||
22 | + # https://pythonhosted.org/z3c.form/browser/README.html | ||
23 | + # http://docs.plone.org/develop/addons/schema-driven-forms/customising-form-behaviour/widgets.html | ||
24 | + # https://pypi.python.org/pypi/plone.autoform | ||
25 | + form.widget('title', TextWidget, klass="macroprocesso-title") | ||
26 | + title = schema.TextLine( | ||
27 | + title=_(u"Título"), | ||
28 | + description=u'', | ||
29 | + required=True, | ||
30 | + max_length=55 | ||
31 | + ) | ||
32 | + | ||
33 | + description = schema.Text( | ||
34 | + title=_(u"Descrição"), | ||
35 | + description=u"", | ||
36 | + required=False, | ||
37 | + ) | ||
38 | + form.widget(description=WysiwygFieldWidget) | ||
39 | + | ||
40 | + imagem = NamedBlobImage( | ||
41 | + title=_(u"Imagem do Macroprocesso"), | ||
42 | + description=_(u"Selecione uma imagem representativa do Macroprocesso"), | ||
43 | + required=True, | ||
44 | + ) | ||
45 | + | ||
46 | + | ||
47 | +class MacroProcesso(Container): | ||
48 | + grok.implements(IMacroProcesso) | ||
49 | + | ||
50 | + def canSetDefaultPage(self): | ||
51 | + """ User don't can set default page """ | ||
52 | + return False |
1 | +++ a/pf/biblioteca/macros/__init__.py |
1 | +++ a/pf/biblioteca/macros/templates/bibliotecabuscaview.pt | ||
@@ -0,0 +1,193 @@ | @@ -0,0 +1,193 @@ | ||
1 | +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" | ||
2 | + xmlns:tal="http://xml.zope.org/namespaces/tal" | ||
3 | + xmlns:metal="http://xml.zope.org/namespaces/metal" | ||
4 | + xmlns:i18n="http://xml.zope.org/namespaces/i18n" | ||
5 | + lang="en" | ||
6 | + metal:use-macro="context/main_template/macros/master" | ||
7 | + i18n:domain="pf.biblioteca"> | ||
8 | + | ||
9 | + | ||
10 | + <tal:head metal:fill-slot="style_slot"> | ||
11 | + | ||
12 | + <link rel="stylesheet" type="text/css" href="biblioteca.css" media="screen" tal:attributes="href string:${context/portal_url}/++resource++pf.biblioteca/biblioteca.css"> | ||
13 | + </tal:head> | ||
14 | +<body> | ||
15 | + | ||
16 | +<metal:main fill-slot="main"> | ||
17 | + | ||
18 | + <div class="row"> | ||
19 | + <div class="cell width-full position-0 "> | ||
20 | + <div class="tile azul ui-droppable" > | ||
21 | + <div class="outstanding-header"> | ||
22 | + <h2 class="outstanding-title" tal:content="context/Title">Bem vindo ao Portal de Serviços da Intranet</h2> | ||
23 | + </div> | ||
24 | + </div> | ||
25 | + </div> | ||
26 | + </div> | ||
27 | + <div class="row"> | ||
28 | + <div class="cell width-full position-0 "> | ||
29 | + <div tal:content="context/Description"></div> | ||
30 | + </div> | ||
31 | + </div> | ||
32 | + | ||
33 | + <metal:macro metal:define-macro="busca"> | ||
34 | + | ||
35 | + <div class="row" id="form-busca"> | ||
36 | + <div class="cell width-full position-2 " > | ||
37 | + | ||
38 | + <script type="text/javascript"> | ||
39 | + | ||
40 | + $(document).ready(function(){ | ||
41 | + $('#open_busca_avancada span').click(function() { | ||
42 | + $('#busca_avancada').toggle(); | ||
43 | + $('#open_busca_avancada span').toggle(); | ||
44 | + }); | ||
45 | + }); | ||
46 | + </script> | ||
47 | + | ||
48 | + <form method="POST" action="" tal:attributes="action string:${context/absolute_url}/biblioteca_busca_view"> | ||
49 | + | ||
50 | + <div class="field ArchetypesStringWidget no-marging "> | ||
51 | + <input type="text" value="" placeholder="Buscar na Biblioteca de Processos" name="title" | ||
52 | + tal:attributes="value request/title|string:"/> | ||
53 | + <input type="submit" name="submited" value="OK"/> | ||
54 | + </div> | ||
55 | + | ||
56 | + <div id="busca_avancada" style="display:none"> | ||
57 | + <div class="field ArchetypesStringWidget "> | ||
58 | + <label class="formQuestion" for="nome">Nome do processo: | ||
59 | + <span class="formHelp"></span></label> | ||
60 | + <input type="text" size="80" value="" placeholder="ex: Processos" name="nome" tal:attributes="value request/nome|string:" /> | ||
61 | + </div> | ||
62 | + <div class="field ArchetypesStringWidget "> | ||
63 | + <label class="formQuestion" for="description">Descrição: | ||
64 | + <span class="formHelp"></span></label> | ||
65 | + <input type="text" size="80" value="" placeholder="ex: Descrição" name="description" tal:attributes="value request/description|string:"/> | ||
66 | + </div> | ||
67 | + <div class="field ArchetypesStringWidget "> | ||
68 | + <label class="formQuestion" for="diretoria_responsavel">Diretoria: | ||
69 | + <span class="formHelp"></span></label> | ||
70 | + <input type="text" size="80" value="" placeholder="ex: Diretoria" name="diretoria_responsavel" tal:attributes="value request/diretoria_responsavel|string:"/> | ||
71 | + </div> | ||
72 | + <div class="field ArchetypesStringWidget "> | ||
73 | + <label class="formQuestion" for="unidade_responsavel">Unidade: | ||
74 | + <span class="formHelp"></span></label> | ||
75 | + <input type="text" size="80" value="" placeholder="ex: Unidade" name="unidade_responsavel" tal:attributes="value request/unidade_responsavel|string:"/> | ||
76 | + </div> | ||
77 | + <div class="field ArchetypesStringWidget "> | ||
78 | + <label class="formQuestion" for="email_unidade">E-mail: | ||
79 | + <span class="formHelp"></span></label> | ||
80 | + <input type="text" size="80" value="" placeholder="ex.: lorem.ipsum@dpf.gov.br" name="email_unidade" tal:attributes="value request/email_unidade|string:"/> | ||
81 | + </div> | ||
82 | + | ||
83 | + </div> | ||
84 | + | ||
85 | + <div id="open_busca_avancada"> | ||
86 | + <span id="more">+ Busca Avançada</span> | ||
87 | + <span id="simple" style="display:none">+ Busca Simples</span> | ||
88 | + | ||
89 | + </div> | ||
90 | + | ||
91 | + </form> | ||
92 | + <br /> | ||
93 | + </div> | ||
94 | + </div> | ||
95 | + | ||
96 | + </metal:macro> | ||
97 | + | ||
98 | + <div id="content-itens"> | ||
99 | + <metal:macro metal:define-macro="page-view"> | ||
100 | + <tal:def tal:define="Batch python:modules['Products.CMFPlone'].Batch; | ||
101 | + mq python:modules['ZTUtils'].make_query; | ||
102 | + url context/@@seopack_batch_url | request/ACTUAL_URL; | ||
103 | + batchformkeys batchformkeys|nothing; | ||
104 | + batchlinkparams python:batchformkeys and dict([(key, request.form[key]) for key in batchformkeys if key in request]) or request.form; | ||
105 | + | ||
106 | + b_size request/b_size|string:10; | ||
107 | + b_start python:0; | ||
108 | + b_start request/b_start | b_start; | ||
109 | + itens view/results|python:[]; | ||
110 | + batch python:Batch(itens, int(b_size), int(b_start), pagerange=len(itens));"> | ||
111 | + | ||
112 | + <input type="hidden" id="b_size" tal:attributes="value b_size" /> | ||
113 | + <input type="hidden" id="b_start" tal:attributes="value b_start" /> | ||
114 | + | ||
115 | + <metal:macro metal:define-macro="navegacao-macro"> | ||
116 | + <div id="paginacao" | ||
117 | + tal:condition="python:len(itens) > 10"> | ||
118 | + | ||
119 | + <div class="row"> | ||
120 | + <div id="size-nav" class="cell width-8 position-0"> | ||
121 | + <p> | ||
122 | + <span tal:content="python:'Total: ('+str(len(itens))+')'">Total (XX)</span> | ||
123 | + | | ||
124 | + <span tal:define="css python:'font-weight:bolder;;'">Itens por pagina: | ||
125 | + <a class="c-pointer" id="itenspage" | ||
126 | + tal:attributes="style python:b_size == '10' and css or ''; | ||
127 | + href python: '%s?%s' % (url , mq( batchlinkparams, {'b_size':'10'} ))">10</a>, | ||
128 | + <a class="c-pointer" id="itenspage" | ||
129 | + tal:attributes="style python:b_size == '20' and css or ''; | ||
130 | + href python: '%s?%s' % (url , mq( batchlinkparams, {'b_size':'20'} ))">20</a>, | ||
131 | + <a class="c-pointer" id="itenspage" | ||
132 | + tal:attributes="style python:b_size == '30' and css or ''; | ||
133 | + href python: '%s?%s' % (url , mq( batchlinkparams, {'b_size':'30'} ))">30</a>, | ||
134 | + <a class="c-pointer" id="itenspage" | ||
135 | + tal:attributes="style python:b_size == '40' and css or ''; | ||
136 | + href python: '%s?%s' % (url , mq( batchlinkparams, {'b_size':'40'} ))">40</a> | ||
137 | + </span> | ||
138 | + </p> | ||
139 | + </div> | ||
140 | + <div id="pag-nav" class="cell width-8 position-8 "> | ||
141 | + <metal:block metal:use-macro="context/list_news_batch/macros/navigation" /> | ||
142 | + </div> | ||
143 | + </div> | ||
144 | + | ||
145 | + </div> | ||
146 | + <div class="visualClear"></div> | ||
147 | + </metal:macro> | ||
148 | + <div class="visualClear"></div> | ||
149 | + | ||
150 | + <div class="row" | ||
151 | + tal:condition="not: itens"> | ||
152 | + <div id="size-nav" class="cell width-8 position-0"> | ||
153 | + <p class="discreet">Nenhum resultado encontrado.</p> | ||
154 | + </div> | ||
155 | + </div> | ||
156 | + | ||
157 | + <metal:macro define-macro="news-list"> | ||
158 | + <div id="news"> | ||
159 | + <tal:rep repeat="item batch"> | ||
160 | + <div class="contBoxDestaque" | ||
161 | + tal:define="item_object item/getObject"> | ||
162 | + | ||
163 | + <div tal:define="is_end repeat/item/end;" | ||
164 | + tal:attributes="class python: is_end and 'info' or 'info borderDif'"> | ||
165 | + | ||
166 | + <h4> | ||
167 | + <a tal:content="item_object/Title" | ||
168 | + tal:attributes="href string: ${item_object/absolute_url|nothing}/view; | ||
169 | + alt item_object/Title|nothing">New title</a> | ||
170 | + </h4> | ||
171 | + <p tal:content="structure item_object/Description|nothing">Summary</p> | ||
172 | + <b>Diretoria: </b><span tal:content="item_object/diretoria_responsavel">DICORD/DPF</span><br /> | ||
173 | + <b>Unidade: </b><span tal:content="item_object/unidade_responsavel">DICOR</span><br /> | ||
174 | + <b>E-mail: </b><span tal:content="item_object/email_unidade">dicor@dpf.gov.br</span><br /> | ||
175 | + | ||
176 | + <hr /> | ||
177 | + </div> | ||
178 | + | ||
179 | + </div> | ||
180 | + </tal:rep> | ||
181 | + <div class="visualClear"></div> | ||
182 | + </div> | ||
183 | + </metal:macro> | ||
184 | + | ||
185 | + <metal:block metal:use-macro="context/biblioteca_busca_view/macros/navegacao-macro" /> | ||
186 | + | ||
187 | + </tal:def> | ||
188 | + </metal:macro> | ||
189 | + </div> | ||
190 | + | ||
191 | +</metal:main> | ||
192 | +</body> | ||
193 | +</html> |
1 | +++ a/pf/biblioteca/macros/templates/contactinfoview.pt | ||
@@ -0,0 +1,84 @@ | @@ -0,0 +1,84 @@ | ||
1 | +<metal:macro define-macro="contato"> | ||
2 | + | ||
3 | + <div class="row" tal:define="view_contact python:context.restrictedTraverse('@@contact_info'); | ||
4 | + dummy view_contact/update"> | ||
5 | + <div class="cell width-full position-0 " > | ||
6 | + | ||
7 | + <form method="post" tal:define="dados_user view_contact/get_info_user|python:{}"> | ||
8 | + <div> | ||
9 | + <span>1- Preencha todos os campos.</span> | ||
10 | + </div> | ||
11 | + <div> | ||
12 | + <span>2- Clique no botão "Submeter"</span> | ||
13 | + </div> | ||
14 | + <p/> | ||
15 | + | ||
16 | + <div tal:condition="view_contact/error"> | ||
17 | + <dl class="portalMessage error"><dt>Atenção</dt> | ||
18 | + <dd tal:content="view_contact/msg_erro">Voce deve preencher todos os campos abaixo.</dd> | ||
19 | + </dl> | ||
20 | + </div> | ||
21 | + <div tal:condition="view_contact/msg_ok"> | ||
22 | + <dl class="portalMessage info"><dt>Informação</dt> | ||
23 | + <dd>Seu contato foi realizado com sucesso.</dd> | ||
24 | + </dl> | ||
25 | + </div> | ||
26 | + | ||
27 | + <div> | ||
28 | + <div class="field ArchetypesStringWidget "> | ||
29 | + <label class="formQuestion">Nome <span title="Obrigatório" class="required horizontal"> </span> | ||
30 | + <span class="formHelp"></span> | ||
31 | + </label> | ||
32 | + <input type="text" size="80" value="" name='nome' placeholder="Nome Completo" tal:attributes="value dados_user/nome|string:"/> | ||
33 | + </div> | ||
34 | + <div class="field ArchetypesStringWidget "> | ||
35 | + <label>Email</label> | ||
36 | + <input type="hidden" name='email' tal:attributes="value dados_user/email|string:"/> | ||
37 | + <p tal:content="dados_user/email|string:">email@dpf.gov.br</p> | ||
38 | + </div> | ||
39 | + <div class="field ArchetypesStringWidget "> | ||
40 | + <label class="formQuestion">Telefone <span title="Obrigatório" class="required horizontal"> </span> | ||
41 | + <span class="formHelp"></span> | ||
42 | + </label> | ||
43 | + <input type="text" size="30" value="" name="telefone" id="pf-biblioteca-telefone" | ||
44 | + placeholder="Digite seu número com DDD" | ||
45 | + tal:attributes="value request/telefone|string:"/> | ||
46 | + </div> | ||
47 | + <div class="field ArchetypesStringWidget "> | ||
48 | + <label class="formQuestion">Tipo de Assunto <span title="Obrigatório" class="required horizontal"> </span> | ||
49 | + <span class="formHelp"></span> | ||
50 | + </label> | ||
51 | + | ||
52 | + <select name="assunto" tal:define="valor_r request/assunto|string:default"> | ||
53 | + <option value="" | ||
54 | + tal:attributes="selected python: valor_r=='default' and 'selected' or ''">Selecione</option> | ||
55 | + <option value="Dúvida" | ||
56 | + tal:attributes="selected python: valor_r=='Dúvida' and 'selected' or ''">Dúvida</option> | ||
57 | + <option value="Elogio" | ||
58 | + tal:attributes="selected python: valor_r=='Elogio' and 'selected' or ''">Elogio</option> | ||
59 | + <option value="Reclamação" | ||
60 | + tal:attributes="selected python: valor_r=='Reclamação' and 'selected' or ''">Reclamação</option> | ||
61 | + <option value="Risco de Processo" | ||
62 | + tal:attributes="selected python: valor_r=='Risco de Processo' and 'selected' or ''">Risco de Processo</option> | ||
63 | + <option value="Sugestão de Melhoria" | ||
64 | + tal:attributes="selected python: valor_r=='Sugestão de Melhoria' and 'selected' or ''">Sugestão de Melhoria</option> | ||
65 | + <option value="Outros" | ||
66 | + tal:attributes="selected python: valor_r=='Outros' and 'selected' or ''" >Outros</option> | ||
67 | + </select> | ||
68 | + </div> | ||
69 | + <div class="field ArchetypesStringWidget "> | ||
70 | + <label class="formQuestion">Mensagem <span title="Obrigatório" class="required horizontal"> </span> | ||
71 | + <span class="formHelp"></span> | ||
72 | + </label> | ||
73 | + <textarea type="text" name='mensagem' size="80" rows="10" value="" tal:content="request/mensagem|string:"/> | ||
74 | + </div> | ||
75 | + | ||
76 | + <div> | ||
77 | + <input type="submit" value="Submeter" name="submited"/> | ||
78 | + </div> | ||
79 | + </div> | ||
80 | + </form> | ||
81 | + </div> | ||
82 | + </div> | ||
83 | + | ||
84 | +</metal:macro> |
1 | +++ a/pf/biblioteca/macros/templates/listnewsbatch.pt | ||
@@ -0,0 +1,69 @@ | @@ -0,0 +1,69 @@ | ||
1 | +<html xmlns="http://www.w3.org/1999/xhtml" | ||
2 | + xmlns:tal="http://xml.zope.org/namespaces/tal" | ||
3 | + xmlns:metal="http://xml.zope.org/namespaces/metal" | ||
4 | + xmlns:i18n="http://xml.zope.org/namespaces/i18n" | ||
5 | + i18n:domain="plone"> | ||
6 | +<body> | ||
7 | + | ||
8 | +<tal:comment condition="nothing">You can feed in batch_base_url by enclosing | ||
9 | +the metal:use-macro="context/batch_macros/macros/navigation" statement in your | ||
10 | +template with a tal:define="batch_base_url YOUR_BASE_URL" tales expression. | ||
11 | +</tal:comment> | ||
12 | +<div align="right" | ||
13 | + metal:define-macro="navigation" | ||
14 | + tal:define="request request|context/request|container/request|nothing; | ||
15 | + batch batch|nothing; | ||
16 | + batchformkeys batchformkeys|nothing; | ||
17 | + batchlinkparams python:batchformkeys and dict([(key, request.form[key]) for key in batchformkeys if key in request]) or request.form; | ||
18 | + mq python:modules['ZTUtils'].make_query; | ||
19 | + url batch_base_url | context/@@seopack_batch_url | request/ACTUAL_URL; | ||
20 | + currentpage batch/pagenumber;" | ||
21 | + tal:condition="python: batch.next or batch.previous"> | ||
22 | + | ||
23 | + <div class="numeros left"> | ||
24 | + <tal:comment tal:replace="nothing"> | ||
25 | + Current page | ||
26 | + </tal:comment> | ||
27 | + <span tal:condition="batch/navlist" class="current" | ||
28 | + tal:content="batch/pagenumber">Current page number</span> | ||
29 | + | ||
30 | + <tal:comment tal:replace="nothing"> | ||
31 | + Link to last | ||
32 | + </tal:comment>de | ||
33 | + <span tal:content="batch/numpages">3457</span> | ||
34 | + </div> | ||
35 | + | ||
36 | + | ||
37 | + <div class="setas right"> | ||
38 | + | ||
39 | + <span class="previous left" | ||
40 | + tal:define="p batch/previous | nothing" | ||
41 | + tal:condition="p"> | ||
42 | + <a href="" id="previous" | ||
43 | + tal:attributes="href python: '%s?%s' % (url , mq( batchlinkparams, {batch.b_start_str:p.first} ))"> | ||
44 | + <span i18n:translate="batch_previous_x_items" tal:omit-tag=""></span> | ||
45 | + </a> | ||
46 | + </span> | ||
47 | + | ||
48 | + <span class="next right" | ||
49 | + tal:define="n batch/next | nothing" | ||
50 | + tal:condition="n"> | ||
51 | + <a href="" id="next" | ||
52 | + tal:attributes="href python: '%s?%s' % (url , mq( batchlinkparams, {batch.b_start_str:n.first} ))"> | ||
53 | + <span i18n:translate="batch_next_x_items" tal:omit-tag=""></span> | ||
54 | + </a> | ||
55 | + </span> | ||
56 | + </div> | ||
57 | + | ||
58 | + | ||
59 | +</div> | ||
60 | + | ||
61 | +</body> | ||
62 | +</html> | ||
63 | + | ||
64 | + | ||
65 | + | ||
66 | + | ||
67 | + | ||
68 | + | ||
69 | + |
1 | +++ a/pf/biblioteca/macros/views.py | ||
@@ -0,0 +1,204 @@ | @@ -0,0 +1,204 @@ | ||
1 | +# -*- coding: utf-8 -*- | ||
2 | + | ||
3 | +from plone import api | ||
4 | +from five import grok | ||
5 | +from zope.interface import Interface | ||
6 | +from Products.CMFCore.utils import getToolByName | ||
7 | +from zope.component import getUtility | ||
8 | +from plone.registry.interfaces import IRegistry | ||
9 | +from Products import AdvancedQuery | ||
10 | + | ||
11 | +import smtplib | ||
12 | +from email.MIMEMultipart import MIMEMultipart | ||
13 | +from email.MIMEText import MIMEText | ||
14 | + | ||
15 | +from pf.biblioteca.processo import IProcesso | ||
16 | + | ||
17 | + | ||
18 | +grok.templatedir('templates') | ||
19 | + | ||
20 | + | ||
21 | +class ListNewsBatch(grok.View): | ||
22 | + grok.context(Interface) | ||
23 | + grok.require('zope2.View') | ||
24 | + grok.name('list_news_batch') | ||
25 | + | ||
26 | + | ||
27 | +class BibliotecaBuscaView(grok.View): | ||
28 | + grok.context(Interface) | ||
29 | + grok.require('zope2.View') | ||
30 | + grok.name('biblioteca_busca_view') | ||
31 | + | ||
32 | + results = [] | ||
33 | + | ||
34 | + def __parse_query_string(self, string): | ||
35 | + return string.replace("(", "").replace(")", "") | ||
36 | + | ||
37 | + def advanced_search(self, form, fields=[]): | ||
38 | + """ """ | ||
39 | + if not fields: | ||
40 | + return | ||
41 | + | ||
42 | + path = '/'.join(self.context.getPhysicalPath()) | ||
43 | + query = AdvancedQuery.Eq('portal_type', 'pf.biblioteca.processo') & \ | ||
44 | + AdvancedQuery.Eq('path', path) | ||
45 | + | ||
46 | + for f in fields: | ||
47 | + val = self.__parse_query_string(form.get(f)) | ||
48 | + if val: | ||
49 | + if f == 'nome': | ||
50 | + query = query & AdvancedQuery.Eq('title', val) | ||
51 | + continue | ||
52 | + | ||
53 | + query = query & AdvancedQuery.Eq(f, val) | ||
54 | + return query | ||
55 | + | ||
56 | + def update(self): | ||
57 | + form = self.request.form | ||
58 | + pcatalog = api.portal.get_tool(name='portal_catalog') | ||
59 | + | ||
60 | + if 'submited' in form.keys(): | ||
61 | + # Simple search | ||
62 | + title = self.__parse_query_string(form.get('title', '')) | ||
63 | + if title: | ||
64 | + path = '/'.join(self.context.getPhysicalPath()) | ||
65 | + query = { | ||
66 | + 'portal_type': ['pf.biblioteca.processo', ], | ||
67 | + 'path': {'query': path, 'depth': 99}, | ||
68 | + 'SearchableText': "*{0}*".format(title), | ||
69 | + 'sort_on': 'id', | ||
70 | + 'sort_order': 'ascending', | ||
71 | + } | ||
72 | + results = pcatalog(**query) | ||
73 | + | ||
74 | + # Advanced search | ||
75 | + else: | ||
76 | + fields = ['title', 'description', 'diretoria_responsavel', | ||
77 | + 'unidade_responsavel'] | ||
78 | + query = self.advanced_search(form, fields) | ||
79 | + sort_order = (('id', 'ascending'), ) | ||
80 | + results = pcatalog.evalAdvancedQuery(query, sort_order) | ||
81 | + | ||
82 | + self.results = results | ||
83 | + | ||
84 | + | ||
85 | +class ContactInfoView(grok.View): | ||
86 | + grok.context(IProcesso) | ||
87 | + grok.require('zope2.View') | ||
88 | + grok.name('contact_info') | ||
89 | + | ||
90 | + error = False | ||
91 | + msg_ok = False | ||
92 | + msg_erro = '' | ||
93 | + | ||
94 | + def envia_email(self, msg, assunto, mail_para, from_email=None, cc_email=None): | ||
95 | + """ | ||
96 | + Parte do codigo retirado de: | ||
97 | + - http://dev.plone.org/collective/browser/ATContentTypes/branches/release-1_0-branch/lib/imagetransform.py?rev=10162 | ||
98 | + - http://www.thescripts.com/forum/thread22918.html | ||
99 | + - http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/473810 | ||
100 | + """ | ||
101 | + portal = self.context.portal_url.getPortalObject() | ||
102 | + | ||
103 | + # Cria a mensagem raiz, configurando os campos necessarios para envio da mensagem. | ||
104 | + mensagem = MIMEMultipart('related') | ||
105 | + mensagem['Subject'] = assunto | ||
106 | + # Pega os remetentes do email pelas configurações do zope @@mail-controlpanel | ||
107 | + if from_email: | ||
108 | + mensagem['From'] = '%s <%s>' % (from_email, from_email) | ||
109 | + else: | ||
110 | + mensagem['From'] = '%s <%s>' % (portal.getProperty('email_from_name'), | ||
111 | + portal.getProperty('email_from_address')) | ||
112 | + | ||
113 | + mensagem['To'] = mail_para | ||
114 | + | ||
115 | + send_to = [mail_para, ] | ||
116 | + if cc_email: | ||
117 | + mensagem['Cc'] = cc_email | ||
118 | + send_to.append(cc_email) | ||
119 | + | ||
120 | + mensagem.preamble = 'This is a multi-part message in MIME format.' | ||
121 | + mensagem.attach(MIMEText(msg, 'html', 'utf-8')) | ||
122 | + mail_de = mensagem['From'] | ||
123 | + | ||
124 | + # Pegando SmtpHost Padrão do Plone | ||
125 | + smtp_host = portal.MailHost.smtp_host | ||
126 | + smtp_port = portal.MailHost.smtp_port | ||
127 | + smtp_userid = portal.MailHost.smtp_uid | ||
128 | + smtp_pass = portal.MailHost.smtp_pwd | ||
129 | + server_all = '%s:%s' % (smtp_host, smtp_port) | ||
130 | + | ||
131 | + smtp = smtplib.SMTP() | ||
132 | + | ||
133 | + try: | ||
134 | + smtp.connect(server_all) | ||
135 | + # Caso o Usuario e Senha estejam preenchdos faz o login | ||
136 | + if smtp_userid and smtp_pass: | ||
137 | + try: | ||
138 | + smtp.ehlo() | ||
139 | + smtp.starttls() | ||
140 | + smtp.login(smtp_userid, smtp_pass) | ||
141 | + except: | ||
142 | + smtp.login(smtp_userid, smtp_pass) | ||
143 | + smtp.sendmail(mail_de, send_to, mensagem.as_string()) | ||
144 | + smtp.quit() | ||
145 | + except: | ||
146 | + return False | ||
147 | + | ||
148 | + return True | ||
149 | + | ||
150 | + def email_global(self): | ||
151 | + registry = getUtility(IRegistry) | ||
152 | + confg = registry.records['pf.biblioteca.browser.interfaces.IBibliotecaControlPanel.email_cc'] | ||
153 | + return confg.value | ||
154 | + | ||
155 | + def send_email(self, dados): | ||
156 | + email_to = self.context.email_unidade | ||
157 | + assunto = 'Gestão Diária - %s - %s' % (self.context.Title(), dados.get('assunto', '')) | ||
158 | + | ||
159 | + texto = ''' ** Dados do usuario ** <br /> | ||
160 | + Nome: %(nome)s <br /> | ||
161 | + E-mail: %(email)s <br /> | ||
162 | + Telefone: %(telefone)s <br /> | ||
163 | + Mensagem: %(mensagem)s | ||
164 | + ''' % (dados) | ||
165 | + | ||
166 | + return self.envia_email( | ||
167 | + mail_para=email_to, | ||
168 | + from_email="no-reply@dpf.gov.br", | ||
169 | + cc_email=self.email_global(), | ||
170 | + assunto=assunto, | ||
171 | + msg=texto | ||
172 | + ) | ||
173 | + | ||
174 | + def get_info_user(self): | ||
175 | + pmembership = getToolByName(self.context, 'portal_membership') | ||
176 | + user_login = pmembership.getAuthenticatedMember() | ||
177 | + | ||
178 | + D = {} | ||
179 | + username = user_login.getUserName() | ||
180 | + D['username'] = username | ||
181 | + D['nome'] = user_login.getProperty('fullname') | ||
182 | + D['email'] = "{0}@dpf.gov.br".format(username) | ||
183 | + return D | ||
184 | + | ||
185 | + def update(self): | ||
186 | + form = self.request.form | ||
187 | + if 'submited' in form.keys(): | ||
188 | + | ||
189 | + fields = ['nome', 'email', 'telefone', 'assunto', 'mensagem'] | ||
190 | + for f in fields: | ||
191 | + val = form.get(f) | ||
192 | + | ||
193 | + if not val: | ||
194 | + self.error = True | ||
195 | + self.msg_erro = 'Voce deve preencher todos os campos abaixo.' | ||
196 | + return | ||
197 | + | ||
198 | + if self.send_email(form): | ||
199 | + self.request.form = {} | ||
200 | + self.msg_ok = True | ||
201 | + return | ||
202 | + else: | ||
203 | + self.error = True | ||
204 | + self.msg_erro = 'Erro ao enviar o formulario, Contate o suporte.' |
1 | +++ a/pf/biblioteca/processo.py | ||
@@ -0,0 +1,87 @@ | @@ -0,0 +1,87 @@ | ||
1 | +# -*- coding: utf-8 -*- | ||
2 | + | ||
3 | +from zope import schema | ||
4 | +from five import grok | ||
5 | + | ||
6 | +from plone.dexterity.content import Item | ||
7 | +from plone.supermodel import model | ||
8 | +from plone.namedfile.field import NamedBlobImage | ||
9 | +from plone.directives import form | ||
10 | +from plone.app.z3cform.wysiwyg import WysiwygFieldWidget | ||
11 | + | ||
12 | +from collective import dexteritytextindexer | ||
13 | + | ||
14 | +from pf.biblioteca import MessageFactory as _ | ||
15 | + | ||
16 | + | ||
17 | +class IProcesso(model.Schema): | ||
18 | + """ | ||
19 | + Página de Processo | ||
20 | + """ | ||
21 | + dexteritytextindexer.searchable('title') | ||
22 | + title = schema.TextLine( | ||
23 | + title=u"Nome do processo", | ||
24 | + description=u'', | ||
25 | + required=True | ||
26 | + ) | ||
27 | + | ||
28 | + dexteritytextindexer.searchable('description') | ||
29 | + description = schema.Text( | ||
30 | + title=u"Descrição", | ||
31 | + description=u"", | ||
32 | + required=False, | ||
33 | + ) | ||
34 | + form.widget(description=WysiwygFieldWidget) | ||
35 | + | ||
36 | + imagem_processo = NamedBlobImage( | ||
37 | + title=_(u"Imagem do Processo"), | ||
38 | + required=False, | ||
39 | + ) | ||
40 | + | ||
41 | + dexteritytextindexer.searchable('diretoria_responsavel') | ||
42 | + diretoria_responsavel = schema.TextLine( | ||
43 | + title=u"Diretoria Responsavel (Dono)", | ||
44 | + description=u"", | ||
45 | + required=True | ||
46 | + ) | ||
47 | + | ||
48 | + dexteritytextindexer.searchable('unidade_responsavel') | ||
49 | + unidade_responsavel = schema.TextLine( | ||
50 | + title=u"Unidade Responsavel (Gestor)", | ||
51 | + description=u"", | ||
52 | + required=True | ||
53 | + ) | ||
54 | + | ||
55 | + email_unidade = schema.TextLine( | ||
56 | + title=u"E-mail da Unidade Responsavel", | ||
57 | + description=u"", | ||
58 | + required=True | ||
59 | + ) | ||
60 | + | ||
61 | + telefone_unidade = schema.TextLine( | ||
62 | + title=u"Telefone da Unidade Responsavel", | ||
63 | + description=u"", | ||
64 | + required=True | ||
65 | + ) | ||
66 | + | ||
67 | + link_bizagi = schema.TextLine( | ||
68 | + title=u"Fluxo do Processo", | ||
69 | + description=u"Informe o link para o fluxo do processo.", | ||
70 | + required=True | ||
71 | + ) | ||
72 | + | ||
73 | + responsavel_fluxo = schema.TextLine( | ||
74 | + title=u"Responsavel pela Publicacao do Fluxo na CIGE/DPF", | ||
75 | + description=u"", | ||
76 | + required=True | ||
77 | + ) | ||
78 | + | ||
79 | + email_responsavel_fluxo = schema.TextLine( | ||
80 | + title=u"E-mail do Responsavel pela Publicacao do Fluxo na CIGE/DPF", | ||
81 | + description=u"", | ||
82 | + required=True | ||
83 | + ) | ||
84 | + | ||
85 | + | ||
86 | +class Processo(Item): | ||
87 | + grok.implements(IProcesso) |
1 | +++ a/pf/biblioteca/profiles/default/controlpanel.xml | ||
@@ -0,0 +1,20 @@ | @@ -0,0 +1,20 @@ | ||
1 | +<?xml version="1.0"?> | ||
2 | +<object | ||
3 | + name="portal_controlpanel" | ||
4 | + xmlns:i18n="http://xml.zope.org/namespaces/i18n" | ||
5 | + i18n:domain="pf.biblioteca"> | ||
6 | + | ||
7 | + <configlet | ||
8 | + title="Biblioteca Settings" | ||
9 | + action_id="pf.biblioteca.settings" | ||
10 | + appId="settings" | ||
11 | + category="Products" | ||
12 | + condition_expr="" | ||
13 | + url_expr="string:${portal_url}/@@biblioteca-settings" | ||
14 | + icon_expr="" | ||
15 | + visible="True" | ||
16 | + i18n:attributes="title"> | ||
17 | + <permission>Manage portal</permission> | ||
18 | + </configlet> | ||
19 | + | ||
20 | +</object> | ||
0 | \ No newline at end of file | 21 | \ No newline at end of file |
1 | +++ a/pf/biblioteca/profiles/default/import_steps.xml | ||
@@ -0,0 +1,15 @@ | @@ -0,0 +1,15 @@ | ||
1 | +<?xml version="1.0"?> | ||
2 | +<import-steps> | ||
3 | + <import-step id="pf.biblioteca.install_index" | ||
4 | + version="1.0" | ||
5 | + handler="pf.biblioteca.setuphandlers.install_index" | ||
6 | + title="Create Index Catalog"> | ||
7 | + | ||
8 | + </import-step> | ||
9 | + <import-step id="pf.biblioteca.create_initial_content" | ||
10 | + version="1.0" | ||
11 | + handler="pf.biblioteca.setuphandlers.create_initial_content" | ||
12 | + title="Create Initial Content"> | ||
13 | + | ||
14 | + </import-step> | ||
15 | +</import-steps> |
1 | +++ a/pf/biblioteca/profiles/default/jsregistry.xml | ||
@@ -0,0 +1,40 @@ | @@ -0,0 +1,40 @@ | ||
1 | +<?xml version="1.0"?> | ||
2 | +<object name="portal_javascripts"> | ||
3 | + | ||
4 | + <!-- jQuery Mask --> | ||
5 | + <javascript | ||
6 | + id="++resource++pf.biblioteca/jquery.mask.min.js" | ||
7 | + authenticated="False" | ||
8 | + cacheable="True" compression="safe" cookable="True" | ||
9 | + enabled="True" expression="" | ||
10 | + inline="False" | ||
11 | + /> | ||
12 | + | ||
13 | + <!-- Max Length --> | ||
14 | + <javascript | ||
15 | + id="++resource++pf.biblioteca/jquery.maxlength.js" | ||
16 | + authenticated="False" | ||
17 | + cacheable="True" compression="safe" cookable="True" | ||
18 | + enabled="True" expression="" | ||
19 | + inline="False" | ||
20 | + /> | ||
21 | + | ||
22 | + <!-- masks --> | ||
23 | + <javascript | ||
24 | + id="++resource++pf.biblioteca/pf.biblioteca.masks.js" | ||
25 | + authenticated="False" | ||
26 | + cacheable="True" compression="safe" cookable="True" | ||
27 | + enabled="True" expression="" | ||
28 | + inline="False" | ||
29 | + /> | ||
30 | + | ||
31 | + <!-- macroprocesso form --> | ||
32 | + <javascript | ||
33 | + id="++resource++pf.biblioteca/pf.biblioteca.macroprocesso.js" | ||
34 | + authenticated="True" | ||
35 | + cacheable="True" compression="safe" cookable="True" | ||
36 | + enabled="True" expression="" | ||
37 | + inline="False" | ||
38 | + /> | ||
39 | + | ||
40 | +</object> |
1 | +++ a/pf/biblioteca/profiles/default/registry.xml | ||
@@ -0,0 +1,4 @@ | @@ -0,0 +1,4 @@ | ||
1 | +<?xml version="1.0"?> | ||
2 | +<registry> | ||
3 | + <records interface="pf.biblioteca.browser.interfaces.IBibliotecaControlPanel" name="settingsBiblioteca"/> | ||
4 | +</registry> | ||
0 | \ No newline at end of file | 5 | \ No newline at end of file |
1 | +++ a/pf/biblioteca/profiles/default/types.xml | ||
@@ -0,0 +1,13 @@ | @@ -0,0 +1,13 @@ | ||
1 | +<?xml version="1.0"?> | ||
2 | +<!-- This file registers new types with portal_types. The types are | ||
3 | + then configured with the corresponding files in types/*.xml. Note | ||
4 | + that spaces are allowed in type names, but the corresponding XML file | ||
5 | + uses an underscore instead. The "Factory-based Type Information with | ||
6 | + dynamic views" refers to an FTI from Products.CMFDynamicViewFTI, | ||
7 | + which supports Plone's "display" menu. | ||
8 | + --> | ||
9 | +<object name="portal_types" meta_type="Plone Types Tool"> | ||
10 | + <!-- -*- extra stuff goes here -*- --> | ||
11 | + <object name="pf.biblioteca.processo" meta_type="Dexterity FTI" /> | ||
12 | + <object name="pf.biblioteca.macroprocesso" meta_type="Dexterity FTI" /> | ||
13 | +</object> |
pf/biblioteca/profiles/default/types/pf.biblioteca.macroprocesso.xml
0 → 100644
1 | +++ a/pf/biblioteca/profiles/default/types/pf.biblioteca.macroprocesso.xml | ||
@@ -0,0 +1,60 @@ | @@ -0,0 +1,60 @@ | ||
1 | +<?xml version="1.0"?> | ||
2 | +<object name="pf.biblioteca.macroprocesso" | ||
3 | + meta_type="Dexterity FTI" | ||
4 | + i18n:domain="pf.biblioteca" xmlns:i18n="http://xml.zope.org/namespaces/i18n"> | ||
5 | + | ||
6 | + <!-- Basic metadata --> | ||
7 | + <property name="title" i18n:translate="">Macroprocesso</property> | ||
8 | + <property name="description" | ||
9 | + i18n:translate="">Macroprocesso</property> | ||
10 | + <property name="icon_expr">string:${portal_url}/Form.gif</property> | ||
11 | + <property name="factory">pf.biblioteca.macroprocesso</property> | ||
12 | + <property name="global_allow">True</property> | ||
13 | + <property name="filter_content_types">True</property> | ||
14 | + <property name="allowed_content_types"> | ||
15 | + <element value="pf.biblioteca.processo" /> | ||
16 | + <element value="pf.biblioteca.macroprocesso" /> | ||
17 | + </property> | ||
18 | + <property name="allow_discussion">False</property> | ||
19 | + | ||
20 | + <!-- schema and class used for content items --> | ||
21 | + <property name="schema">pf.biblioteca.macroprocesso.IMacroProcesso</property> | ||
22 | + <property name="klass">pf.biblioteca.macroprocesso.MacroProcesso</property> | ||
23 | + | ||
24 | + <property name="behaviors"> | ||
25 | + <element value="plone.app.content.interfaces.INameFromTitle" /> | ||
26 | + <!-- <element value="plone.app.dexterity.behaviors.metadata.IBasic" /> --> | ||
27 | + </property> | ||
28 | + | ||
29 | + <!-- View information --> | ||
30 | + <property name="link_target"></property> | ||
31 | + <property name="immediate_view">macroprocesso_view</property> | ||
32 | + <property name="default_view">macroprocesso_view</property> | ||
33 | + <property name="view_methods"> | ||
34 | + <!-- | ||
35 | + <element value="macroprocesso_view"/> | ||
36 | + --> | ||
37 | + </property> | ||
38 | + <property name="default_view_fallback">False</property> | ||
39 | + <property name="add_permission">cmf.AddPortalContent</property> | ||
40 | + | ||
41 | + | ||
42 | + <!-- Method aliases --> | ||
43 | + <alias from="(Default)" to="(dynamic view)" /> | ||
44 | + <alias from="view" to="(selected layout)" /> | ||
45 | + <alias from="edit" to="@@edit" /> | ||
46 | + | ||
47 | + <alias from="sharing" to="@@sharing" /> | ||
48 | + | ||
49 | + <!-- Actions --> | ||
50 | + <action title="View" action_id="view" category="object" condition_expr="" | ||
51 | + url_expr="string:${object_url}/" visible="True"> | ||
52 | + <permission value="View" /> | ||
53 | +</action> | ||
54 | + | ||
55 | + <action title="Edit" action_id="edit" category="object" condition_expr="" | ||
56 | + url_expr="string:${object_url}/edit" visible="True"> | ||
57 | + <permission value="Modify portal content" /> | ||
58 | + </action> | ||
59 | + | ||
60 | +</object> |
pf/biblioteca/profiles/default/types/pf.biblioteca.processo.xml
0 → 100755
1 | +++ a/pf/biblioteca/profiles/default/types/pf.biblioteca.processo.xml | ||
@@ -0,0 +1,55 @@ | @@ -0,0 +1,55 @@ | ||
1 | +<?xml version="1.0"?> | ||
2 | +<object name="pf.biblioteca.processo" | ||
3 | + meta_type="Dexterity FTI" | ||
4 | + i18n:domain="pf.biblioteca" xmlns:i18n="http://xml.zope.org/namespaces/i18n"> | ||
5 | + | ||
6 | + <!-- Basic metadata --> | ||
7 | + <property name="title" i18n:translate="">Processo</property> | ||
8 | + <property name="description" | ||
9 | + i18n:translate="">Pagina de Processo</property> | ||
10 | + <property name="icon_expr">string:${portal_url}/Form.gif</property> | ||
11 | + <property name="factory">pf.biblioteca.processo</property> | ||
12 | + <property name="global_allow">True</property> | ||
13 | + <property name="filter_content_types">False</property> | ||
14 | + <property name="allowed_content_types" /> | ||
15 | + <property name="allow_discussion">False</property> | ||
16 | + | ||
17 | + <!-- schema and class used for content items --> | ||
18 | + <property name="schema">pf.biblioteca.processo.IProcesso</property> | ||
19 | + <property name="klass">pf.biblioteca.processo.Processo</property> | ||
20 | + | ||
21 | + <property name="behaviors"> | ||
22 | + <element value="plone.app.content.interfaces.INameFromTitle" /> | ||
23 | + <!-- <element value="plone.app.dexterity.behaviors.metadata.IBasic" /> --> | ||
24 | + </property> | ||
25 | + | ||
26 | + <!-- View information --> | ||
27 | + <property name="link_target"></property> | ||
28 | + <property name="immediate_view">view</property> | ||
29 | + <property name="default_view">view</property> | ||
30 | + <property name="view_methods"> | ||
31 | + <element value="view"/> | ||
32 | + </property> | ||
33 | + <property name="default_view_fallback">False</property> | ||
34 | + <property name="add_permission">cmf.AddPortalContent</property> | ||
35 | + | ||
36 | + | ||
37 | + <!-- Method aliases --> | ||
38 | + <alias from="(Default)" to="(dynamic view)" /> | ||
39 | + <alias from="view" to="(selected layout)" /> | ||
40 | + <alias from="edit" to="@@edit" /> | ||
41 | + | ||
42 | + <alias from="sharing" to="@@sharing" /> | ||
43 | + | ||
44 | + <!-- Actions --> | ||
45 | + <action title="View" action_id="view" category="object" condition_expr="" | ||
46 | + url_expr="string:${object_url}/" visible="True"> | ||
47 | + <permission value="View" /> | ||
48 | +</action> | ||
49 | + | ||
50 | + <action title="Edit" action_id="edit" category="object" condition_expr="" | ||
51 | + url_expr="string:${object_url}/edit" visible="True"> | ||
52 | + <permission value="Modify portal content" /> | ||
53 | + </action> | ||
54 | + | ||
55 | +</object> |
1 | +++ a/pf/biblioteca/resources/README.txt | ||
@@ -0,0 +1,13 @@ | @@ -0,0 +1,13 @@ | ||
1 | +Use the resources directory for non-template browser resources like images, | ||
2 | +stylesheets and JavaScript. | ||
3 | + | ||
4 | +Contents of this folder may be addressed in templates via TAL. For | ||
5 | +example, if you placed at test.js resource in this folder, you could insert it | ||
6 | +via template code like: | ||
7 | + | ||
8 | +<script type="text/javascript" src="test.js" | ||
9 | + tal:attributes="src string:${context/@@plone_portal_state/portal_url}/++resource++pf.biblioteca/test.js"></script> | ||
10 | + | ||
11 | +It's more likely you'd add it the portal_javascript registry with an id of ++resource++dexterity.test/test.js. | ||
12 | + | ||
13 | +Static folder resources are public. | ||
0 | \ No newline at end of file | 14 | \ No newline at end of file |
1 | +++ a/pf/biblioteca/resources/biblioteca.css | ||
@@ -0,0 +1,16 @@ | @@ -0,0 +1,16 @@ | ||
1 | +#titulo-macroprocesso h4 { | ||
2 | + min-height: 30px; | ||
3 | +} | ||
4 | + | ||
5 | +#processo { | ||
6 | + margin-bottom: 15px; | ||
7 | +} | ||
8 | + | ||
9 | +.mensagem-login h4{ | ||
10 | + color:#2c67cd; | ||
11 | +} | ||
12 | + | ||
13 | +.mensagem-login h4:hover{ | ||
14 | + color:#000; | ||
15 | +} | ||
16 | + |
46 KB
37.2 KB
1 | +++ a/pf/biblioteca/resources/jquery.mask.min.js | ||
@@ -0,0 +1,12 @@ | @@ -0,0 +1,12 @@ | ||
1 | +// jQuery Mask Plugin v1.7.7 | ||
2 | +// github.com/igorescobar/jQuery-Mask-Plugin | ||
3 | +(function(f){"function"===typeof define&&define.amd?define(["jquery"],f):f(window.jQuery||window.Zepto)})(function(f){var A=function(a,d,b){var h=this,m,p;a=f(a);d="function"===typeof d?d(a.val(),void 0,a,b):d;var c={getCaret:function(){try{var e,l=0,c=a.get(0),g=document.selection,d=c.selectionStart;if(g&&!~navigator.appVersion.indexOf("MSIE 10"))e=g.createRange(),e.moveStart("character",a.is("input")?-a.val().length:-a.text().length),l=e.text.length;else if(d||"0"===d)l=d;return l}catch(b){}},setCaret:function(e){try{if(a.is(":focus")){var l, | ||
4 | +c=a.get(0);c.setSelectionRange?c.setSelectionRange(e,e):c.createTextRange&&(l=c.createTextRange(),l.collapse(!0),l.moveEnd("character",e),l.moveStart("character",e),l.select())}}catch(g){}},events:function(){a.on("keydown.mask",function(){m=c.val()}).on("keyup.mask",c.behaviour).on("paste.mask drop.mask",function(){setTimeout(function(){a.keydown().keyup()},100)}).on("change.mask",function(){a.data("changed",!0)}).on("blur.mask",function(){m===a.val()||a.data("changed")||a.trigger("change");a.data("changed", | ||
5 | +!1)}).on("focusout.mask",function(){b.clearIfNotMatch&&!p.test(c.val())&&c.val("")})},getRegexMask:function(){for(var e=[],a,c,g,b,k=0;k<d.length;k++)(a=h.translation[d[k]])?(c=a.pattern.toString().replace(/.{1}$|^.{1}/g,""),g=a.optional,(a=a.recursive)?(e.push(d[k]),b={digit:d[k],pattern:c}):e.push(g||a?c+"?":c)):e.push(d[k].replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&"));e=e.join("");b&&(e=e.replace(new RegExp("("+b.digit+"(.*"+b.digit+")?)"),"($1)?").replace(new RegExp(b.digit,"g"),b.pattern));return new RegExp(e)}, | ||
6 | +destroyEvents:function(){a.off("keydown keyup paste drop change blur focusout DOMNodeInserted ".split(" ").join(".mask ")).removeData("changeCalled")},val:function(e){var c=a.is("input");return 0<arguments.length?c?a.val(e):a.text(e):c?a.val():a.text()},getMCharsBeforeCount:function(e,a){for(var c=0,b=0,f=d.length;b<f&&b<e;b++)h.translation[d.charAt(b)]||(e=a?e+1:e,c++);return c},caretPos:function(e,a,b,g){return h.translation[d.charAt(Math.min(e-1,d.length-1))]?Math.min(e+b-a-g,b):c.caretPos(e+1, | ||
7 | +a,b,g)},behaviour:function(a){a=a||window.event;var b=a.keyCode||a.which;if(-1===f.inArray(b,h.byPassKeys)){var d=c.getCaret(),g=c.val(),t=g.length,k=d<t,m=c.getMasked(),n=m.length,p=c.getMCharsBeforeCount(n-1)-c.getMCharsBeforeCount(t-1);m!==g&&c.val(m);!k||65===b&&a.ctrlKey||(8!==b&&46!==b&&(d=c.caretPos(d,t,n,p)),c.setCaret(d));return c.callbacks(a)}},getMasked:function(a){var l=[],f=c.val(),g=0,m=d.length,k=0,p=f.length,n=1,u="push",r=-1,q,v;b.reverse?(u="unshift",n=-1,q=0,g=m-1,k=p-1,v=function(){return-1< | ||
8 | +g&&-1<k}):(q=m-1,v=function(){return g<m&&k<p});for(;v();){var w=d.charAt(g),x=f.charAt(k),s=h.translation[w];if(s)x.match(s.pattern)?(l[u](x),s.recursive&&(-1===r?r=g:g===q&&(g=r-n),q===r&&(g-=n)),g+=n):s.optional&&(g+=n,k-=n),k+=n;else{if(!a)l[u](w);x===w&&(k+=n);g+=n}}a=d.charAt(q);m!==p+1||h.translation[a]||l.push(a);return l.join("")},callbacks:function(e){var f=c.val(),h=f!==m;if(!0===h&&"function"===typeof b.onChange)b.onChange(f,e,a,b);if(!0===h&&"function"===typeof b.onKeyPress)b.onKeyPress(f, | ||
9 | +e,a,b);if("function"===typeof b.onComplete&&f.length===d.length)b.onComplete(f,e,a,b)}};h.mask=d;h.options=b;h.remove=function(){var b;c.destroyEvents();c.val(h.getCleanVal()).removeAttr("maxlength");b=c.getCaret();c.setCaret(b-c.getMCharsBeforeCount(b));return a};h.getCleanVal=function(){return c.getMasked(!0)};h.init=function(){b=b||{};h.byPassKeys=[9,16,17,18,36,37,38,39,40,91];h.translation={0:{pattern:/\d/},9:{pattern:/\d/,optional:!0},"#":{pattern:/\d/,recursive:!0},A:{pattern:/[a-zA-Z0-9]/}, | ||
10 | +S:{pattern:/[a-zA-Z]/}};h.translation=f.extend({},h.translation,b.translation);h=f.extend(!0,{},h,b);p=c.getRegexMask();!1!==b.maxlength&&a.attr("maxlength",d.length);b.placeholder&&a.attr("placeholder",b.placeholder);a.attr("autocomplete","off");c.destroyEvents();c.events();var e=c.getCaret();c.val(c.getMasked());c.setCaret(e+c.getMCharsBeforeCount(e,!0))}()},y={},z=function(){var a=f(this),d={};a.attr("data-mask-reverse")&&(d.reverse=!0);"false"===a.attr("data-mask-maxlength")&&(d.maxlength=!1); | ||
11 | +a.attr("data-mask-clearifnotmatch")&&(d.clearIfNotMatch=!0);a.mask(a.attr("data-mask"),d)};f.fn.mask=function(a,d){var b=this.selector,h=function(){var b=f(this).data("mask"),h=JSON.stringify;if("object"!==typeof b||h(b.options)!==h(d)||b.mask!==a)return f(this).data("mask",new A(this,a,d))};this.each(h);b&&!y[b]&&(y[b]=!0,setTimeout(function(){f(document).on("DOMNodeInserted.mask",b,h)},500))};f.fn.unmask=function(){try{return this.each(function(){f(this).data("mask").remove().removeData("mask")})}catch(a){}}; | ||
12 | +f.fn.cleanVal=function(){return this.data("mask").getCleanVal()};f("*[data-mask]").each(z);f(document).on("DOMNodeInserted.mask","*[data-mask]",z)}); |
1 | +++ a/pf/biblioteca/resources/jquery.maxlength.js | ||
@@ -0,0 +1,152 @@ | @@ -0,0 +1,152 @@ | ||
1 | +/** | ||
2 | + * jQuery Maxlength plugin | ||
3 | + * @version $Id: jquery.maxlength.js 18 2009-05-16 15:37:08Z emil@anon-design.se $ | ||
4 | + * @package jQuery maxlength 1.0.5 | ||
5 | + * @copyright Copyright (C) 2009 Emil Stjerneman / http://www.anon-design.se | ||
6 | + * @license GNU/GPL, see LICENSE.txt | ||
7 | + * @documentation https://stjerneman.com/portfolio/maxlength-jquery | ||
8 | + */ | ||
9 | + | ||
10 | +(function($) | ||
11 | +{ | ||
12 | + | ||
13 | + $.fn.maxlength = function(options) | ||
14 | + { | ||
15 | + var settings = jQuery.extend( | ||
16 | + { | ||
17 | + events: [], // Array of events to be triggerd | ||
18 | + maxCharacters: 10, // Characters limit | ||
19 | + status: true, // True to show status indicator bewlow the element | ||
20 | + statusClass: "status", // The class on the status div | ||
21 | + statusText: "character left", // The status text | ||
22 | + notificationClass: "notification", // Will be added to the emement when maxlength is reached | ||
23 | + showAlert: false, // True to show a regular alert message | ||
24 | + alertText: "You have typed too many characters.", // Text in the alert message | ||
25 | + slider: false // Use counter slider | ||
26 | + }, options ); | ||
27 | + | ||
28 | + // Add the default event | ||
29 | + $.merge(settings.events, ['keyup']); | ||
30 | + | ||
31 | + return this.each(function() | ||
32 | + { | ||
33 | + var item = $(this); | ||
34 | + var charactersLength = $(this).val().length; | ||
35 | + | ||
36 | + // Update the status text | ||
37 | + function updateStatus() | ||
38 | + { | ||
39 | + var charactersLeft = settings.maxCharacters - charactersLength; | ||
40 | + | ||
41 | + if(charactersLeft < 0) | ||
42 | + { | ||
43 | + charactersLeft = 0; | ||
44 | + } | ||
45 | + | ||
46 | + item.next("div").html(charactersLeft + " " + settings.statusText); | ||
47 | + } | ||
48 | + | ||
49 | + function checkChars() | ||
50 | + { | ||
51 | + var valid = true; | ||
52 | + | ||
53 | + // Too many chars? | ||
54 | + if(charactersLength >= settings.maxCharacters) | ||
55 | + { | ||
56 | + // Too may chars, set the valid boolean to false | ||
57 | + valid = false; | ||
58 | + // Add the notifycation class when we have too many chars | ||
59 | + item.addClass(settings.notificationClass); | ||
60 | + // Cut down the string | ||
61 | + item.val(item.val().substr(0,settings.maxCharacters)); | ||
62 | + // Show the alert dialog box, if its set to true | ||
63 | + showAlert(); | ||
64 | + } | ||
65 | + else | ||
66 | + { | ||
67 | + // Remove the notification class | ||
68 | + if(item.hasClass(settings.notificationClass)) | ||
69 | + { | ||
70 | + item.removeClass(settings.notificationClass); | ||
71 | + } | ||
72 | + } | ||
73 | + | ||
74 | + if(settings.status) | ||
75 | + { | ||
76 | + updateStatus(); | ||
77 | + } | ||
78 | + } | ||
79 | + | ||
80 | + // Shows an alert msg | ||
81 | + function showAlert() | ||
82 | + { | ||
83 | + if(settings.showAlert) | ||
84 | + { | ||
85 | + alert(settings.alertText); | ||
86 | + } | ||
87 | + } | ||
88 | + | ||
89 | + // Check if the element is valid. | ||
90 | + function validateElement() | ||
91 | + { | ||
92 | + var ret = false; | ||
93 | + | ||
94 | + if(item.is('textarea')) { | ||
95 | + ret = true; | ||
96 | + } else if(item.filter("input[type=text]")) { | ||
97 | + ret = true; | ||
98 | + } else if(item.filter("input[type=password]")) { | ||
99 | + ret = true; | ||
100 | + } | ||
101 | + | ||
102 | + return ret; | ||
103 | + } | ||
104 | + | ||
105 | + // Validate | ||
106 | + if(!validateElement()) | ||
107 | + { | ||
108 | + return false; | ||
109 | + } | ||
110 | + | ||
111 | + // Loop through the events and bind them to the element | ||
112 | + $.each(settings.events, function (i, n) { | ||
113 | + item.bind(n, function(e) { | ||
114 | + charactersLength = item.val().length; | ||
115 | + checkChars(); | ||
116 | + }); | ||
117 | + }); | ||
118 | + | ||
119 | + // Insert the status div | ||
120 | + if(settings.status) | ||
121 | + { | ||
122 | + item.after($("<div/>").addClass(settings.statusClass).html('-')); | ||
123 | + updateStatus(); | ||
124 | + } | ||
125 | + | ||
126 | + // Remove the status div | ||
127 | + if(!settings.status) | ||
128 | + { | ||
129 | + var removeThisDiv = item.next("div."+settings.statusClass); | ||
130 | + | ||
131 | + if(removeThisDiv) { | ||
132 | + removeThisDiv.remove(); | ||
133 | + } | ||
134 | + | ||
135 | + } | ||
136 | + | ||
137 | + // Slide counter | ||
138 | + if(settings.slider) { | ||
139 | + item.next().hide(); | ||
140 | + | ||
141 | + item.focus(function(){ | ||
142 | + item.next().slideDown('fast'); | ||
143 | + }); | ||
144 | + | ||
145 | + item.blur(function(){ | ||
146 | + item.next().slideUp('fast'); | ||
147 | + }); | ||
148 | + } | ||
149 | + | ||
150 | + }); | ||
151 | + }; | ||
152 | +})(jQuery); |
1 | +++ a/pf/biblioteca/resources/pf.biblioteca.macroprocesso.js | ||
@@ -0,0 +1,14 @@ | @@ -0,0 +1,14 @@ | ||
1 | +$(document).ready(function(){ | ||
2 | + $('.macroprocesso-title').maxlength({ | ||
3 | + // https://stjerneman.com/portfolio/maxlength-jquery | ||
4 | + events: [], | ||
5 | + maxCharacters: 55, | ||
6 | + status: true, | ||
7 | + statusClass: "status", | ||
8 | + statusText: "Caracteres restantes", | ||
9 | + notificationClass: "notification", | ||
10 | + showAlert: false, | ||
11 | + alertText: "O número máximo de caracteres para o título do Macroprocesso é 55", | ||
12 | + slider: true | ||
13 | + }) | ||
14 | +}); |
1 | +++ a/pf/biblioteca/resources/pf.biblioteca.masks.js | ||
@@ -0,0 +1,13 @@ | @@ -0,0 +1,13 @@ | ||
1 | +$(document).ready(function(){ | ||
2 | + | ||
3 | + var maskBehavior = function (val) { | ||
4 | + return val.replace(/\D/g, '').length === 11 ? '(00) 00000-0000' : '(00) 0000-00009'; | ||
5 | + }, | ||
6 | + options = { | ||
7 | + onKeyPress: function(val, e, field, options) { | ||
8 | + field.mask(maskBehavior.apply({}, arguments), options); | ||
9 | + } | ||
10 | + }; | ||
11 | + | ||
12 | + $('#pf-biblioteca-telefone').mask(maskBehavior, options); | ||
13 | +}); |
1 | +++ a/pf/biblioteca/setuphandlers.py | ||
@@ -0,0 +1,123 @@ | @@ -0,0 +1,123 @@ | ||
1 | +# -*- coding: utf-8 -*- | ||
2 | + | ||
3 | +from Products.CMFCore.utils import getToolByName | ||
4 | + | ||
5 | +from plone import api | ||
6 | +from plone.app.textfield.value import RichTextValue | ||
7 | + | ||
8 | + | ||
9 | +class Empty(object): | ||
10 | + """ """ | ||
11 | + | ||
12 | + | ||
13 | +def install_index(context): | ||
14 | + portal = context.getSite() | ||
15 | + | ||
16 | + # Adding catalog indexes | ||
17 | + catalog = getToolByName(portal, 'portal_catalog') | ||
18 | + indexes = catalog.indexes() | ||
19 | + # Specify the indexes you want, with ('index_name', 'index_type') | ||
20 | + wanted = ( | ||
21 | + ('diretoria_responsavel', 'ZCTextIndex'), | ||
22 | + ('unidade_responsavel', 'ZCTextIndex'), | ||
23 | + ('email_unidade', 'FieldIndex'), | ||
24 | + ) | ||
25 | + indexables = [] | ||
26 | + for name, meta_type in wanted: | ||
27 | + if name not in indexes: | ||
28 | + # Required for ZCTextIndex indexes | ||
29 | + title_extras = Empty() | ||
30 | + title_extras.index_type = 'Okapi BM25 Rank' | ||
31 | + title_extras.lexicon_id = 'plone_lexicon' | ||
32 | + | ||
33 | + catalog.addIndex(name, meta_type, title_extras) | ||
34 | + indexables.append(name) | ||
35 | + | ||
36 | + if len(indexables) > 0: | ||
37 | + catalog.manage_reindexIndex(ids=indexables) | ||
38 | + | ||
39 | + | ||
40 | +def container_has_content(container, content_id): | ||
41 | + try: | ||
42 | + container[content_id] | ||
43 | + return True | ||
44 | + except KeyError: | ||
45 | + return False | ||
46 | + | ||
47 | + | ||
48 | +def get_or_create_content(container, type, id, title, **kwargs): | ||
49 | + try: | ||
50 | + content = container[id] | ||
51 | + except KeyError: | ||
52 | + content = api.content.create( | ||
53 | + container=container, | ||
54 | + type=type, | ||
55 | + id=id, | ||
56 | + title=title, | ||
57 | + **kwargs) | ||
58 | + return content | ||
59 | + | ||
60 | + | ||
61 | +def create_initial_content(context): | ||
62 | + portal = api.portal.get() | ||
63 | + | ||
64 | + # Biblioteca de Servicos page | ||
65 | + biblioteca = get_or_create_content( | ||
66 | + container=portal, | ||
67 | + type='Folder', | ||
68 | + id='biblioteca-de-processos', | ||
69 | + title='Biblioteca de Processos', | ||
70 | + description='Esse serviço está temporariamente indisponível' | ||
71 | + ) | ||
72 | + biblioteca.setLayout('biblioteca_view') | ||
73 | + | ||
74 | + # Biblioteca de Servicos description page | ||
75 | + if not container_has_content(biblioteca, 'biblioteca-de-processos'): | ||
76 | + description_text = u"""\ | ||
77 | + <p>A Biblioteca de Processos destina-se à publicação de fluxos, | ||
78 | + informações e toda a documentação dos processos de trabalho da | ||
79 | + Instituição que foram mapeados pelas áreas Gestoras, com apoio da | ||
80 | + Coordenação do Centro Integrado de Gestão Estratégica (CIGE/DPF).</p> | ||
81 | + <p>Na página de cada processo você vai encontrar, também, um canal de | ||
82 | + comunicação direto com o respectivo Gestor, para esclarecimento de | ||
83 | + dúvidas e apresentação de críticas e sugestões, entre outros itens.</p> | ||
84 | + <p>Os processos estão publicados de acordo com os 25 macroprocessos | ||
85 | + constates na Arquitetura de Processos da Polícia Federal. | ||
86 | + Confira abaixo, no macroprocesso de seu interesse, os processos | ||
87 | + que já foram documentados. </p> | ||
88 | + """ | ||
89 | + obj_desc = get_or_create_content( | ||
90 | + container=biblioteca, | ||
91 | + type='Document', | ||
92 | + id='biblioteca-de-processos', | ||
93 | + title='Descrição do serviço', | ||
94 | + text=RichTextValue( | ||
95 | + description_text, | ||
96 | + 'text/html', | ||
97 | + 'text/plain' | ||
98 | + ) | ||
99 | + ) | ||
100 | + if api.content.get_state(obj=obj_desc) != 'published': | ||
101 | + api.content.transition(obj=obj_desc, transition='publish') | ||
102 | + | ||
103 | + if api.content.get_state(obj=biblioteca) != 'published': | ||
104 | + api.content.transition(obj=biblioteca, transition='publish') | ||
105 | + | ||
106 | + # Folder Serviços do Portal: used to include links to portal services | ||
107 | + sp = get_or_create_content( | ||
108 | + container=portal, | ||
109 | + type='Folder', | ||
110 | + id='servicos-do-portal', | ||
111 | + title='Serviços do Portal', | ||
112 | + exclude_from_nav=True, | ||
113 | + ) | ||
114 | + if api.content.get_state(obj=sp) != 'published': | ||
115 | + api.content.transition(obj=sp, transition='publish') | ||
116 | + | ||
117 | + biblioteca_link = get_or_create_content( | ||
118 | + container=sp, | ||
119 | + type='Link', | ||
120 | + id='biblioteca-de-processos', | ||
121 | + title='Biblioteca de Processos', | ||
122 | + remoteUrl='${portal_url}/biblioteca-de-processos' | ||
123 | + ) |
1 | +++ a/pf/biblioteca/tests.py | ||
@@ -0,0 +1,58 @@ | @@ -0,0 +1,58 @@ | ||
1 | +import doctest | ||
2 | +import unittest | ||
3 | + | ||
4 | +from Testing import ZopeTestCase as ztc | ||
5 | + | ||
6 | +from Products.Five import zcml | ||
7 | +from Products.PloneTestCase import PloneTestCase as ptc | ||
8 | +from Products.PloneTestCase.layer import PloneSite | ||
9 | +from Products.PloneTestCase.layer import onsetup | ||
10 | + | ||
11 | +import pf.biblioteca | ||
12 | + | ||
13 | +OPTION_FLAGS = doctest.NORMALIZE_WHITESPACE | \ | ||
14 | + doctest.ELLIPSIS | ||
15 | + | ||
16 | +ptc.setupPloneSite(products=['pf.biblioteca']) | ||
17 | + | ||
18 | + | ||
19 | +class TestCase(ptc.PloneTestCase): | ||
20 | + | ||
21 | + class layer(PloneSite): | ||
22 | + | ||
23 | + @classmethod | ||
24 | + def setUp(cls): | ||
25 | + zcml.load_config('configure.zcml', | ||
26 | + pf.biblioteca) | ||
27 | + | ||
28 | + @classmethod | ||
29 | + def tearDown(cls): | ||
30 | + pass | ||
31 | + | ||
32 | + | ||
33 | +def test_suite(): | ||
34 | + return unittest.TestSuite([ | ||
35 | + | ||
36 | + # Unit tests | ||
37 | + #doctestunit.DocFileSuite( | ||
38 | + # 'README.txt', package='pf.biblioteca', | ||
39 | + # setUp=testing.setUp, tearDown=testing.tearDown), | ||
40 | + | ||
41 | + #doctestunit.DocTestSuite( | ||
42 | + # module='pf.biblioteca.mymodule', | ||
43 | + # setUp=testing.setUp, tearDown=testing.tearDown), | ||
44 | + | ||
45 | + | ||
46 | + # Integration tests that use PloneTestCase | ||
47 | + ztc.ZopeDocFileSuite( | ||
48 | + 'INTEGRATION.txt', | ||
49 | + package='pf.biblioteca', | ||
50 | + optionflags = OPTION_FLAGS, | ||
51 | + test_class=TestCase), | ||
52 | + | ||
53 | + # -*- extra stuff goes here -*- | ||
54 | + | ||
55 | + ]) | ||
56 | + | ||
57 | +if __name__ == '__main__': | ||
58 | + unittest.main(defaultTest='test_suite') |
1 | +++ a/plone.cfg | ||
@@ -0,0 +1,28 @@ | @@ -0,0 +1,28 @@ | ||
1 | +[buildout] | ||
2 | +find-links = | ||
3 | + http://dist.plone.org/thirdparty/ | ||
4 | +extends = | ||
5 | + http://dist.plone.org/release/4.0.1/versions.cfg | ||
6 | +parts = instance | ||
7 | +version = versions | ||
8 | + | ||
9 | +zcml = | ||
10 | + | ||
11 | +[versions] | ||
12 | + | ||
13 | +[instance] | ||
14 | +recipe = plone.recipe.zope2instance | ||
15 | +effective-user = ${buildout:effective-user} | ||
16 | +user = admin:password | ||
17 | +http-address = 8080 | ||
18 | + | ||
19 | +eggs = | ||
20 | + Plone | ||
21 | + PILwoTK | ||
22 | + elementtree | ||
23 | + | ||
24 | +environment-vars = | ||
25 | + PYTHON_EGG_CACHE /tmp/egg-cache | ||
26 | +zcml = | ||
27 | + ${buildout:zcml} | ||
28 | + |
1 | +++ a/setup.py | ||
@@ -0,0 +1,49 @@ | @@ -0,0 +1,49 @@ | ||
1 | +from setuptools import setup, find_packages | ||
2 | +import os | ||
3 | + | ||
4 | +version = '1.0.5' | ||
5 | + | ||
6 | +setup(name='pf.biblioteca', | ||
7 | + version=version, | ||
8 | + description="pf.biblioteca", | ||
9 | + long_description=open("README.md").read() + "\n" + open(os.path.join("docs", "HISTORY.txt")).read(), | ||
10 | + # Get more strings from | ||
11 | + # http://pypi.python.org/pypi?%3Aaction=list_classifiers | ||
12 | + classifiers=[ | ||
13 | + "Framework :: Plone", | ||
14 | + "Programming Language :: Python", | ||
15 | + "Topic :: Software Development :: Libraries :: Python Modules", | ||
16 | + ], | ||
17 | + keywords='', | ||
18 | + author='Liberiun', | ||
19 | + author_email='', | ||
20 | + url='http://svn.plone.org/svn/collective/', | ||
21 | + license='General Public License - GPL (“Licença Pública Geral”), versão 3.0, em português', | ||
22 | + packages=find_packages(exclude=['ez_setup']), | ||
23 | + namespace_packages=['pf'], | ||
24 | + include_package_data=True, | ||
25 | + zip_safe=False, | ||
26 | + install_requires=[ | ||
27 | + 'setuptools', | ||
28 | + 'plone.app.dexterity [grok]', | ||
29 | + 'plone.app.relationfield', | ||
30 | + 'plone.namedfile [blobs]', | ||
31 | + 'plone.formwidget.namedfile', | ||
32 | + 'plone.behavior', | ||
33 | + # -*- Extra requirements: -*- | ||
34 | + 'plone.app.ldap', | ||
35 | + 'Products.AdvancedQuery', | ||
36 | + 'plone.api' | ||
37 | + ], | ||
38 | + entry_points=""" | ||
39 | + # -*- Entry points: -*- | ||
40 | + [z3c.autoinclude.plugin] | ||
41 | + target = plone | ||
42 | + """, | ||
43 | + # The next two lines may be deleted after you no longer need | ||
44 | + # addcontent support from paster and before you distribute | ||
45 | + # your package. | ||
46 | + # setup_requires=["PasteScript"], | ||
47 | + # paster_plugins=["ZopeSkel"], | ||
48 | + | ||
49 | + ) |