Compare commits
192 commits
Author | SHA1 | Date | |
---|---|---|---|
a72553c2de | |||
1d264fc54f | |||
80c83d5c9f | |||
77fedaaeaa | |||
636b209e9a | |||
520c89f4b2 | |||
b6c93302b9 | |||
0340992932 | |||
ed5e560ba4 | |||
aa0443d0b5 | |||
0de7ef2550 | |||
bbc277e81d | |||
c3efe7a6f9 | |||
8d2f185d17 | |||
ec88df3405 | |||
678ed53ab5 | |||
72d7fdd05f | |||
eddb58c794 | |||
8a578b46a8 | |||
78c8b196bf | |||
2b5a5ec65a | |||
b8ce799b12 | |||
c0fc7fd464 | |||
e01a7362f9 | |||
74a3f9210b | |||
95ed826629 | |||
22efffa11b | |||
0f2232648c | |||
14ea59a307 | |||
8d7cda5ec0 | |||
cfa079de0d | |||
dc87e32a63 | |||
2a689a871b | |||
76e189ac45 | |||
0e180bb229 | |||
98f023195b | |||
5dcc7d2fc6 | |||
2cf3569fcb | |||
6169a2d728 | |||
ffa5c8701e | |||
48a51c54b1 | |||
74ce78dae9 | |||
f2a737e0a8 | |||
6ae2590f50 | |||
1da71c72a9 | |||
010106406d | |||
992b5c012d | |||
bf1fda008c | |||
5e5e9aedfc | |||
956a6d01b3 | |||
52ac41a82f | |||
04a9d9ced0 | |||
509000a996 | |||
ce7015b224 | |||
53be77b5b9 | |||
42d24a5c3f | |||
494612235e | |||
ca70050bec | |||
7a9be5d79b | |||
98bd9b0a46 | |||
7b3c7c182e | |||
77aaad1aa0 | |||
4041841c65 | |||
cb994dc238 | |||
baedf02d78 | |||
6efe2b7a46 | |||
d5a8068261 | |||
73ac0af54e | |||
3c82ec9fdc | |||
81fef0e1d5 | |||
31886012ce | |||
086868d5b7 | |||
f51f3d4f25 | |||
536903f3d8 | |||
75fdced678 | |||
a739aed66a | |||
92bc00e134 | |||
fb9d6991cd | |||
bea7ed0254 | |||
bece8863ef | |||
16a8bcf5c3 | |||
2dbbf977d4 | |||
23623aeb3d | |||
70a93f56d9 | |||
ec87bcd682 | |||
3d3e221a5c | |||
4635a00caf | |||
64ad40fb96 | |||
b4b93b122e | |||
5c4b7fd730 | |||
380d7e7b59 | |||
1cd9908afe | |||
6994d923a2 | |||
997bffc286 | |||
81aa9d4e1e | |||
45d568b77b | |||
4343dc517f | |||
a2ccb8a35b | |||
8e81bab3bf | |||
466044eb77 | |||
a65c138949 | |||
2c22df9c1d | |||
506e539c2d | |||
781521ca88 | |||
6d39f9f354 | |||
e3359db4ca | |||
c9c537af23 | |||
![]() |
1cf6bd3c06 | ||
![]() |
d4edd8ee7a | ||
![]() |
4b54cadcac | ||
8e94c5971e | |||
![]() |
aab2d6c955 | ||
![]() |
34c9d24ffa | ||
1504375a25 | |||
346d041be4 | |||
4b4a804cb7 | |||
2ddf3e03e7 | |||
fecac89a84 | |||
4f710c15d6 | |||
522e40f242 | |||
61a146a43d | |||
31b81d10e3 | |||
347e19a2c6 | |||
ebcbab1a6c | |||
ebacd14134 | |||
d07f3b85a9 | |||
9d9cfd6fc7 | |||
dd23787d27 | |||
0cd2e1f47d | |||
8723289204 | |||
b471deef43 | |||
c3079472de | |||
![]() |
b59248ee31 | ||
![]() |
1b0f0e4859 | ||
082acf3fbc | |||
9ab3e61f9a | |||
1854903d0f | |||
b4a8ae1ed1 | |||
c5fe2044b5 | |||
9c2517a518 | |||
dc5d913b99 | |||
814f10ae51 | |||
dae9610e2e | |||
7567374e50 | |||
2012181382 | |||
e1b1a82ee1 | |||
233d146587 | |||
aa263eb635 | |||
![]() |
66b616e5e1 | ||
7dcf4a9f4e | |||
181846b29a | |||
37d508cec2 | |||
f8bca9e7d6 | |||
7a3cfbc175 | |||
63220a656f | |||
![]() |
fb924fdc03 | ||
dc75d56951 | |||
8f12304074 | |||
30c13d57d7 | |||
f9ba9d2115 | |||
4339f25ca3 | |||
ccc9886113 | |||
![]() |
e27f4000f7 | ||
![]() |
c64f067d6e | ||
![]() |
fbacdd7465 | ||
0b5c50c100 | |||
4a18c42283 | |||
0915d04e30 | |||
24cd81e267 | |||
2e096a3682 | |||
f69a43699c | |||
970775f847 | |||
![]() |
1f4d246994 | ||
![]() |
fbf4efc40c | ||
bd33c28d08 | |||
babb222868 | |||
![]() |
9ec755ecd3 | ||
a3b649582c | |||
0b4fdef7b5 | |||
![]() |
16b5665bfa | ||
357c660659 | |||
5c90a19859 | |||
a2dca10e15 | |||
ec28357ba7 | |||
4a0b31b34d | |||
d09e2a9d0a | |||
019eef29a6 | |||
c029cb2356 | |||
e929a3154e | |||
57588f1e19 | |||
853782fb35 | |||
9f9df6599f |
6
.gitignore
vendored
|
@ -1,8 +1,14 @@
|
|||
*.pyc
|
||||
*.pyo
|
||||
*.swp
|
||||
dist/
|
||||
var/
|
||||
*.egg-info
|
||||
*.project
|
||||
*.pydevproject
|
||||
*.ropeproject
|
||||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
.env
|
||||
.settings
|
||||
adminuser.zcml
|
||||
|
|
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (C) 2023 cyberconcepts.org team
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
222
LICENSE.GPL
|
@ -1,222 +0,0 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
|
@ -1,61 +0,0 @@
|
|||
#
|
||||
# Copyright (c) 2011 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
"""
|
||||
$Id$
|
||||
"""
|
||||
|
||||
from zope.app.security.interfaces import IAuthentication
|
||||
from zope.app.security.interfaces import ILogout, IUnauthenticatedPrincipal
|
||||
from zope import component
|
||||
from zope.interface import implements
|
||||
|
||||
from loops.browser.node import NodeView
|
||||
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||
from zope.cachedescriptors.property import Lazy
|
||||
|
||||
|
||||
class LoginForm(NodeView):
|
||||
|
||||
template = ViewPageTemplateFile('auth.pt')
|
||||
|
||||
@Lazy
|
||||
def macro(self):
|
||||
return self.template.macros['login_form']
|
||||
|
||||
@Lazy
|
||||
def item(self):
|
||||
return self
|
||||
|
||||
|
||||
class Logout(object):
|
||||
|
||||
implements(ILogout)
|
||||
|
||||
def __init__(self, context, request):
|
||||
self.context = context
|
||||
self.request = request
|
||||
|
||||
def __call__(self):
|
||||
nextUrl = self.request.get('nextURL') or self.request.URL[-1]
|
||||
if not IUnauthenticatedPrincipal.providedBy(self.request.principal):
|
||||
auth = component.getUtility(IAuthentication)
|
||||
ILogout(auth).logout(self.request)
|
||||
return self.request.response.redirect(nextUrl)
|
||||
|
||||
|
19
config.py
Normal file
|
@ -0,0 +1,19 @@
|
|||
# loops/config.py
|
||||
# (used for testing only)
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from os import getenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
server_port = getenv('SERVER_PORT', '8099')
|
||||
|
||||
app_factory = zope_app_factory
|
||||
|
||||
# storage settings
|
||||
dbengine = 'postgresql+psycopg'
|
||||
dbname = getenv('DBNAME', 'demo')
|
||||
dbuser = getenv('DBUSER', 'demo')
|
||||
dbpassword = getenv('DBPASSWORD', 'secret')
|
||||
dbschema = getenv('DBSCHEMA', 'demo')
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
#
|
||||
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
"""
|
||||
Filter query results.
|
||||
|
||||
$Id$
|
||||
"""
|
||||
|
||||
from zope.interface import implements
|
||||
|
||||
from loops.expert.interfaces import IQueryInstance
|
||||
|
||||
|
||||
class QueryInstance(object):
|
||||
|
||||
implements(IQueryInstance)
|
||||
|
||||
def __init__(self, query, *filters, **kw):
|
||||
self.query = query
|
||||
self.filters = filters
|
||||
self.filterQueries = {}
|
||||
for k, v in kw.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
def apply(self, uidsOnly=False):
|
||||
result = self.query.apply()
|
||||
return result
|
||||
|
14
inst/bluebream/adminuser.zcml.in
Normal file
|
@ -0,0 +1,14 @@
|
|||
<configure xmlns="http://namespaces.zope.org/zope">
|
||||
|
||||
<principal
|
||||
id="zope.manager"
|
||||
title="Manager"
|
||||
login="admin"
|
||||
password="admin"
|
||||
password_manager="Plain Text" />
|
||||
|
||||
<grant
|
||||
role="zope.Manager"
|
||||
principal="zope.manager" />
|
||||
|
||||
</configure>
|
11
inst/bluebream/application.zcml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<configure xmlns="http://namespaces.zope.org/zope">
|
||||
|
||||
<include package="loops" file="bluebream.zcml" />
|
||||
|
||||
<include package="loops" file="securitypolicy.zcml" />
|
||||
|
||||
<include file="adminuser.zcml" />
|
||||
|
||||
<includeOverrides file="overrides.zcml" />
|
||||
|
||||
</configure>
|
9
inst/bluebream/config.py
Normal file
|
@ -0,0 +1,9 @@
|
|||
# loops/inst/bluebream/config.py
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from os import getenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
server_port = getenv('SERVER_PORT', '8099')
|
||||
|
8
inst/bluebream/env.in
Normal file
|
@ -0,0 +1,8 @@
|
|||
# loops/inst/bluebream/.env
|
||||
|
||||
SERVER_PORT=8800
|
||||
|
||||
DBNAME=ccotest
|
||||
DBUSER=ccotest
|
||||
DBPASSWORD=cco
|
||||
DBSCHEMA=testing
|
15
inst/bluebream/main.py
Normal file
|
@ -0,0 +1,15 @@
|
|||
# loops/inst/bluebream/main.py
|
||||
|
||||
import waitress
|
||||
from zope.app.wsgi import config, getWSGIApplication
|
||||
|
||||
def run(app, config):
|
||||
port = int(config.server_port)
|
||||
#print(f'Serving on port {port}.')
|
||||
waitress.serve(app, port=port)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import config
|
||||
app = getWSGIApplication('zope.conf')
|
||||
run(app, config)
|
4
inst/bluebream/overrides.zcml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<configure xmlns="http://namespaces.zope.org/zope">
|
||||
|
||||
</configure>
|
||||
|
39
inst/bluebream/zope.conf
Normal file
|
@ -0,0 +1,39 @@
|
|||
# loops/inst/bluebream/zope.conf
|
||||
# main zope configuration file for deployment
|
||||
|
||||
# Identify the component configuration used to define the site:
|
||||
site-definition application.zcml
|
||||
|
||||
<zodb>
|
||||
|
||||
<filestorage>
|
||||
path var/filestorage/Data.fs
|
||||
blob-dir var/blob
|
||||
</filestorage>
|
||||
|
||||
# Uncomment this if you want to connect to a ZEO server instead:
|
||||
# <zeoclient>
|
||||
# server localhost:8100
|
||||
# storage 1
|
||||
# # ZEO client cache, in bytes
|
||||
# cache-size 20MB
|
||||
# # Uncomment to have a persistent disk cache
|
||||
# #client zeo1
|
||||
# </zeoclient>
|
||||
</zodb>
|
||||
|
||||
<eventlog>
|
||||
# This sets up logging to both a file and to standard output (STDOUT).
|
||||
# The "path" setting can be a relative or absolute filesystem path or
|
||||
# the tokens STDOUT or STDERR.
|
||||
|
||||
<logfile>
|
||||
path var/log/bluebream.log
|
||||
formatter zope.exceptions.log.Formatter
|
||||
</logfile>
|
||||
|
||||
<logfile>
|
||||
path STDOUT
|
||||
formatter zope.exceptions.log.Formatter
|
||||
</logfile>
|
||||
</eventlog>
|
14
inst/loops/adminuser.zcml.in
Normal file
|
@ -0,0 +1,14 @@
|
|||
<configure xmlns="http://namespaces.zope.org/zope">
|
||||
|
||||
<principal
|
||||
id="zope.manager"
|
||||
title="Manager"
|
||||
login="admin"
|
||||
password="admin"
|
||||
password_manager="Plain Text" />
|
||||
|
||||
<grant
|
||||
role="zope.Manager"
|
||||
principal="zope.manager" />
|
||||
|
||||
</configure>
|
33
inst/loops/application.zcml
Normal file
|
@ -0,0 +1,33 @@
|
|||
<configure xmlns="http://namespaces.zope.org/zope">
|
||||
|
||||
<include package="loops" file="bluebream.zcml" />
|
||||
|
||||
<include package="loops" file="securitypolicy.zcml" />
|
||||
|
||||
<module module="loops.patch" />
|
||||
|
||||
<include file="adminuser.zcml" />
|
||||
|
||||
<include package="cybertools" />
|
||||
<include package="cybertools.ajax.dojo" />
|
||||
<include package="cybertools.catalog" />
|
||||
<include package="cybertools.composer.layout" />
|
||||
<include package="cybertools.container" />
|
||||
<!--<include package="cybertools.pyscript" />-->
|
||||
<!--<include package="cybertools.xedit" />-->
|
||||
|
||||
<include package="loops" />
|
||||
|
||||
<!--<include package="cco.schema" />
|
||||
<include package="cco.skin.r2" />
|
||||
<include package="cco.webapi" />
|
||||
<include package="cyberapps.ccmkg" />
|
||||
<include package="cyberapps.knowledge" />-->
|
||||
|
||||
<include package="loops.server" file="auth.zcml" />
|
||||
|
||||
<!-- Override registrations -->
|
||||
<includeOverrides package="loops" file="overrides.zcml" />
|
||||
<includeOverrides file="overrides.zcml" />
|
||||
|
||||
</configure>
|
41
inst/loops/config.py
Normal file
|
@ -0,0 +1,41 @@
|
|||
# loops/inst/loops/config.py
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from os import getenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
server_id = getenv('SERVER_ID')
|
||||
zope_conf = getenv('ZOPE_CONF', 'zope.conf')
|
||||
server_port = getenv('SERVER_PORT',
|
||||
server_id and getenv(f'SERVER_PORT_{server_id}')) or '8080'
|
||||
base_url = getenv('BASE_URL',
|
||||
server_id and getenv(f'BASE_URL_{server_id}')) or 'https://test.example.com'
|
||||
|
||||
shell_pw = (getenv('SHELL_PW', 'dummy'))
|
||||
loops_path = (getenv('LOOPS_PATH', 'loops/demo'))
|
||||
|
||||
# storage settings
|
||||
from scopes.storage.db.postgres import StorageFactory
|
||||
dbengine = getenv('DBENGINE', 'postgresql+psycopg')
|
||||
dbname = getenv('DBNAME', 'demo')
|
||||
dbuser = getenv('DBUSER', 'demo')
|
||||
dbpassword = getenv('DBPASSWORD', 'secret')
|
||||
dbschema = getenv('DBSCHEMA', 'demo')
|
||||
|
||||
# OpenID Connect (OIDC, e.g. via zitadel) authentication settings
|
||||
oidc_provider = getenv('OIDC_PROVIDER', '') #'https://instance1-abcdef.zitadel.cloud')
|
||||
oidc_client_id = getenv('OIDC_CLIENT_ID', '12345')
|
||||
oidc_params = dict(
|
||||
op_config_url=oidc_provider + '/.well-known/openid-configuration',
|
||||
op_uris=None,
|
||||
op_keys=None,
|
||||
callback_url=getenv('OIDC_CALLBACK_URL', base_url + '/auth_callback'),
|
||||
client_id=oidc_client_id,
|
||||
principal_prefix=getenv('OIDC_PRINCIPAL_PREFIX', 'loops.'),
|
||||
cookie_name=getenv('OIDC_COOKIE_NAME', 'oidc_' + oidc_client_id),
|
||||
cookie_domain=getenv('OIDC_COOKIE_DOMAIN', None),
|
||||
cookie_lifetime=getenv('OIDC_COOKIE_LIFETIME', '86400'),
|
||||
cookie_crypt=getenv('OIDC_COOKIE_CRYPT', None)
|
||||
)
|
||||
|
12
inst/loops/env.in
Normal file
|
@ -0,0 +1,12 @@
|
|||
# loops/inst/loops/.env
|
||||
|
||||
SERVER_ID=0
|
||||
SERVER_PORT_0=8800
|
||||
|
||||
SHELL_PW=dummy
|
||||
LOOPS_PATH=demo
|
||||
|
||||
DBNAME=loops
|
||||
DBUSER=demouser
|
||||
DBPASSWORD=dummy
|
||||
DBSCHEMA=demo
|
4
inst/loops/overrides.zcml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<configure xmlns="http://namespaces.zope.org/zope">
|
||||
|
||||
</configure>
|
||||
|
7
inst/loops/runserver.sh
Executable file
|
@ -0,0 +1,7 @@
|
|||
# inst/loops/runserver.sh
|
||||
set -a
|
||||
|
||||
# use environment variables for instance-specific configuration:
|
||||
#SERVER_ID=0
|
||||
|
||||
python -c "from loops.server.main import main; main()"
|
39
inst/loops/zope.conf
Normal file
|
@ -0,0 +1,39 @@
|
|||
# loops/inst/bluebream/zope.conf
|
||||
# main zope configuration file for deployment
|
||||
|
||||
# Identify the component configuration used to define the site:
|
||||
site-definition application.zcml
|
||||
|
||||
<zodb>
|
||||
|
||||
<filestorage>
|
||||
path var/filestorage/Data.$(SERVER_ID).fs
|
||||
blob-dir var/blob.$(SERVER_ID)
|
||||
</filestorage>
|
||||
|
||||
# Uncomment this if you want to connect to a ZEO server instead:
|
||||
# <zeoclient>
|
||||
# server $(ZEO_SERVER)
|
||||
# storage 1
|
||||
# # ZEO client cache, in bytes
|
||||
# cache-size $(ZEO_CACHE_SIZE)
|
||||
# # Uncomment to have a persistent disk cache
|
||||
# #client zeo1$(SERVER_ID)
|
||||
# </zeoclient>
|
||||
</zodb>
|
||||
|
||||
<eventlog>
|
||||
# This sets up logging to both a file and to standard output (STDOUT).
|
||||
# The "path" setting can be a relative or absolute filesystem path or
|
||||
# the tokens STDOUT or STDERR.
|
||||
|
||||
<logfile>
|
||||
path var/log/loops-$(SERVER_ID).log
|
||||
formatter zope.exceptions.log.Formatter
|
||||
</logfile>
|
||||
|
||||
<logfile>
|
||||
path STDOUT
|
||||
formatter zope.exceptions.log.Formatter
|
||||
</logfile>
|
||||
</eventlog>
|
9
inst/loops/zshell.sh
Executable file
|
@ -0,0 +1,9 @@
|
|||
# inst/loops/zshell.sh
|
||||
set -a
|
||||
|
||||
# use environment variables for instance-specific configuration:
|
||||
#SERVER_ID=0
|
||||
#LOOPS_PATH=sites/mysite
|
||||
|
||||
python -ic "from loops.server import psu; psu.setup()"
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
#
|
||||
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
"""
|
||||
Access to external objects.
|
||||
|
||||
$Id$
|
||||
"""
|
||||
|
||||
import os, re
|
||||
|
||||
from zope import component
|
||||
from zope.cachedescriptors.property import Lazy
|
||||
from zope.component import adapts
|
||||
from zope.interface import implements
|
||||
|
||||
from cybertools.integrator.interfaces import IContainerFactory
|
||||
from loops.common import AdapterBase, adapted
|
||||
from loops.integrator.content.interfaces import IExternalAccess
|
||||
from loops.interfaces import IConcept
|
||||
from loops.type import TypeInterfaceSourceList
|
||||
|
||||
|
||||
TypeInterfaceSourceList.typeInterfaces += (IExternalAccess,)
|
||||
|
||||
|
||||
class ExternalAccess(AdapterBase):
|
||||
""" A concept adapter for accessing external collection.
|
||||
"""
|
||||
|
||||
implements(IExternalAccess)
|
||||
adapts(IConcept)
|
||||
|
||||
_contextAttributes = list(IExternalAccess) + list(IConcept)
|
||||
|
||||
def __call__(self):
|
||||
factory = component.getUtility(IContainerFactory, self.providerName)
|
||||
address = os.path.join(self.baseAddress, self.address or '')
|
||||
return factory(address, __parent__=self.context)
|
|
@ -1,45 +0,0 @@
|
|||
#
|
||||
# Copyright (c) 2009 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
"""
|
||||
Adapter for mail resources.
|
||||
|
||||
$Id$
|
||||
"""
|
||||
|
||||
from zope.cachedescriptors.property import Lazy
|
||||
from zope import component
|
||||
from zope.component import adapts
|
||||
from zope.interface import implements
|
||||
|
||||
from loops.integrator.mail.interfaces import IMailResource
|
||||
from loops.resource import TextDocumentAdapter
|
||||
from loops.type import TypeInterfaceSourceList
|
||||
|
||||
|
||||
TypeInterfaceSourceList.typeInterfaces += (IMailResource,)
|
||||
|
||||
|
||||
class MailResource(TextDocumentAdapter):
|
||||
""" A concept adapter for accessing a mail collection.
|
||||
May delegate access to a named utility.
|
||||
"""
|
||||
|
||||
implements(IMailResource)
|
||||
|
||||
_contextAttributes = list(IMailResource)
|
|
@ -1 +0,0 @@
|
|||
'''package loops.knowledge.qualification'''
|
|
@ -1,43 +0,0 @@
|
|||
#
|
||||
# Copyright (c) 2013 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
"""
|
||||
Controlling qualification activities of persons.
|
||||
|
||||
Central part of CCM competence and certification management framework.
|
||||
"""
|
||||
|
||||
from zope.component import adapts
|
||||
from zope.interface import implementer, implements
|
||||
|
||||
from loops.common import AdapterBase
|
||||
from loops.interfaces import IConcept
|
||||
from loops.knowledge.qualification.interfaces import ICompetence
|
||||
from loops.type import TypeInterfaceSourceList
|
||||
|
||||
|
||||
TypeInterfaceSourceList.typeInterfaces += (ICompetence,)
|
||||
|
||||
|
||||
class Competence(AdapterBase):
|
||||
|
||||
implements(ICompetence)
|
||||
|
||||
_contextAttributes = list(ICompetence)
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ with lower-level aspects like type or state management.
|
|||
|
||||
Let's also import some common stuff needed later.
|
||||
|
||||
>>> from loops.common import adapted
|
||||
>>> from loops.common import adapted, baseObject
|
||||
>>> from loops.setup import addAndConfigureObject
|
||||
|
||||
|
||||
|
@ -48,14 +48,14 @@ top-level loops container and a concept manager:
|
|||
>>> cc1 = Concept()
|
||||
>>> concepts['cc1'] = cc1
|
||||
>>> cc1.title
|
||||
u''
|
||||
''
|
||||
>>> loopsRoot.getLoopsUri(cc1)
|
||||
'.loops/concepts/cc1'
|
||||
|
||||
>>> cc2 = Concept(u'Zope 3')
|
||||
>>> cc2 = Concept('Zope 3')
|
||||
>>> concepts['cc2'] = cc2
|
||||
>>> cc2.title
|
||||
u'Zope 3'
|
||||
'Zope 3'
|
||||
|
||||
Now we want to relate the second concept to the first one.
|
||||
|
||||
|
@ -73,11 +73,11 @@ ConceptRelation):
|
|||
We can now ask our concepts for their related child and parent concepts:
|
||||
|
||||
>>> [getName(c) for c in cc1.getChildren()]
|
||||
[u'cc2']
|
||||
['cc2']
|
||||
>>> len(cc1.getParents())
|
||||
0
|
||||
>>> [getName(p) for p in cc2.getParents()]
|
||||
[u'cc1']
|
||||
['cc1']
|
||||
|
||||
>>> len(cc2.getChildren())
|
||||
0
|
||||
|
@ -90,24 +90,24 @@ a special predicate 'hasType'.
|
|||
>>> typeObject = concepts['type']
|
||||
>>> typeObject.setConceptType(typeObject)
|
||||
>>> typeObject.getConceptType().title
|
||||
u'Type'
|
||||
'Type'
|
||||
|
||||
>>> concepts['unknown'] = Concept(u'Unknown Type')
|
||||
>>> concepts['unknown'] = Concept('Unknown Type')
|
||||
>>> unknown = concepts['unknown']
|
||||
>>> unknown.setConceptType(typeObject)
|
||||
>>> unknown.getConceptType().title
|
||||
u'Type'
|
||||
'Type'
|
||||
|
||||
>>> cc1.setConceptType(unknown)
|
||||
>>> cc1.getConceptType().title
|
||||
u'Unknown Type'
|
||||
'Unknown Type'
|
||||
|
||||
>>> concepts['topic'] = Concept(u'Topic')
|
||||
>>> concepts['topic'] = Concept('Topic')
|
||||
>>> topic = concepts['topic']
|
||||
>>> topic.setConceptType(typeObject)
|
||||
>>> cc1.setConceptType(topic)
|
||||
>>> cc1.getConceptType().title
|
||||
u'Topic'
|
||||
'Topic'
|
||||
|
||||
We get a list of types using the ConceptTypeSourceList.
|
||||
In order for the type machinery to work we first have to provide a
|
||||
|
@ -124,7 +124,7 @@ type manager.
|
|||
>>> from loops.concept import ConceptTypeSourceList
|
||||
>>> types = ConceptTypeSourceList(cc1)
|
||||
>>> sorted(t.title for t in types)
|
||||
[u'Customer', u'Domain', u'Predicate', u'Topic', u'Type', u'Unknown Type']
|
||||
['Customer', 'Domain', 'Predicate', 'Topic', 'Type', 'Unknown Type']
|
||||
|
||||
Using a PredicateSourceList we can retrieve a list of the available
|
||||
predicates.
|
||||
|
@ -136,7 +136,7 @@ Note that the 'hasType' predicate is suppressed from this list as the
|
|||
corresponding relation is only assigned via the conceptType attribute:
|
||||
|
||||
>>> sorted(t.title for t in predicates)
|
||||
[u'subobject']
|
||||
['subobject']
|
||||
|
||||
Concept Views
|
||||
-------------
|
||||
|
@ -146,7 +146,7 @@ Concept Views
|
|||
|
||||
>>> children = list(view.children())
|
||||
>>> [c.title for c in children]
|
||||
[u'Zope 3']
|
||||
['Zope 3']
|
||||
|
||||
The token attribute provided with the items returned by the children() and
|
||||
parents() methods identifies identifies not only the item itself but
|
||||
|
@ -159,14 +159,14 @@ of URIs to item and the predicate of the relationship:
|
|||
There is also a concept configuration view that allows updating the
|
||||
underlying context object:
|
||||
|
||||
>>> cc3 = Concept(u'loops for Zope 3')
|
||||
>>> cc3 = Concept('loops for Zope 3')
|
||||
>>> concepts['cc3'] = cc3
|
||||
>>> view = ConceptConfigureView(cc1,
|
||||
... TestRequest(action='assign', tokens=['.loops/concepts/cc3']))
|
||||
>>> view.update()
|
||||
True
|
||||
>>> sorted(c.title for c in cc1.getChildren())
|
||||
[u'Zope 3', u'loops for Zope 3']
|
||||
['Zope 3', 'loops for Zope 3']
|
||||
|
||||
>>> input = {'action': 'remove', 'qualifier': 'children',
|
||||
... 'form.button.submit': 'Remove Chiildren',
|
||||
|
@ -175,18 +175,18 @@ underlying context object:
|
|||
>>> view.update()
|
||||
True
|
||||
>>> sorted(c.title for c in cc1.getChildren())
|
||||
[u'loops for Zope 3']
|
||||
['loops for Zope 3']
|
||||
|
||||
We can also create a new concept and assign it.
|
||||
|
||||
>>> params = {'action': 'create', 'create.name': 'cc4',
|
||||
... 'create.title': u'New concept',
|
||||
... 'create.title': 'New concept',
|
||||
... 'create.type': '.loops/concepts/topic'}
|
||||
>>> view = ConceptConfigureView(cc1, TestRequest(**params))
|
||||
>>> view.update()
|
||||
True
|
||||
>>> sorted(c.title for c in cc1.getChildren())
|
||||
[u'New concept', u'loops for Zope 3']
|
||||
['New concept', 'loops for Zope 3']
|
||||
|
||||
The concept configuration view provides methods for displaying concept
|
||||
types and predicates.
|
||||
|
@ -198,15 +198,15 @@ types and predicates.
|
|||
>>> component.provideAdapter(LoopsTerms, (IIterableSource, IBrowserRequest), ITerms)
|
||||
|
||||
>>> sorted((t.title, t.token) for t in view.conceptTypes())
|
||||
[(u'Customer', '.loops/concepts/customer'),
|
||||
(u'Domain', '.loops/concepts/domain'),
|
||||
(u'Predicate', '.loops/concepts/predicate'),
|
||||
(u'Topic', '.loops/concepts/topic'),
|
||||
(u'Type', '.loops/concepts/type'),
|
||||
(u'Unknown Type', '.loops/concepts/unknown')]
|
||||
[('Customer', '.loops/concepts/customer'),
|
||||
('Domain', '.loops/concepts/domain'),
|
||||
('Predicate', '.loops/concepts/predicate'),
|
||||
('Topic', '.loops/concepts/topic'),
|
||||
('Type', '.loops/concepts/type'),
|
||||
('Unknown Type', '.loops/concepts/unknown')]
|
||||
|
||||
>>> sorted((t.title, t.token) for t in view.predicates())
|
||||
[(u'subobject', '.loops/concepts/standard')]
|
||||
[('subobject', '.loops/concepts/standard')]
|
||||
|
||||
Index attributes adapter
|
||||
------------------------
|
||||
|
@ -214,10 +214,10 @@ Index attributes adapter
|
|||
>>> from loops.concept import IndexAttributes
|
||||
>>> idx = IndexAttributes(cc2)
|
||||
>>> idx.text()
|
||||
u'cc2 Zope 3'
|
||||
'cc2 Zope 3'
|
||||
|
||||
>>> idx.title()
|
||||
u'cc2 Zope 3'
|
||||
'cc2 Zope 3'
|
||||
|
||||
|
||||
Resources and what they have to do with Concepts
|
||||
|
@ -233,27 +233,27 @@ A common type of resource is a document:
|
|||
|
||||
>>> from loops.interfaces import IDocument
|
||||
>>> from loops.resource import Document
|
||||
>>> doc1 = Document(u'Zope Info')
|
||||
>>> doc1 = Document('Zope Info')
|
||||
>>> resources['doc1'] = doc1
|
||||
>>> doc1.title
|
||||
u'Zope Info'
|
||||
'Zope Info'
|
||||
>>> doc1.data
|
||||
u''
|
||||
''
|
||||
>>> doc1.contentType
|
||||
u''
|
||||
''
|
||||
|
||||
We can also directly use Resource objects; these behave like files.
|
||||
In fact, by using resource types we can explicitly assign a resource
|
||||
the 'file' type, but we will use this feature later:
|
||||
|
||||
>>> img = Resource(u'A png Image')
|
||||
>>> img = Resource('A png Image')
|
||||
|
||||
For testing we use some simple files from the tests directory:
|
||||
|
||||
>>> from loops import tests
|
||||
>>> import os
|
||||
>>> path = os.path.join(*tests.__path__)
|
||||
>>> img.data = open(os.path.join(path, 'test_icon.png')).read()
|
||||
>>> img.data = open(os.path.join(path, 'test_icon.png'), 'rb').read()
|
||||
>>> img.getSize()
|
||||
381
|
||||
>>> img.getImageSize()
|
||||
|
@ -261,8 +261,8 @@ For testing we use some simple files from the tests directory:
|
|||
>>> img.contentType
|
||||
'image/png'
|
||||
|
||||
>>> pdf = Resource(u'A pdf File')
|
||||
>>> pdf.data = open(os.path.join(path, 'test.pdf')).read()
|
||||
>>> pdf = Resource('A pdf File')
|
||||
>>> pdf.data = open(os.path.join(path, 'test.pdf'), 'rb').read()
|
||||
>>> pdf.getSize()
|
||||
25862
|
||||
>>> pdf.getImageSize()
|
||||
|
@ -287,7 +287,7 @@ from concepts to resources:
|
|||
... 'tokens': ['.loops/resources/doc1:.loops/concepts/standard']}
|
||||
>>> view = ConceptConfigureView(cc1, TestRequest(form=form))
|
||||
>>> [getName(r.context) for r in view.resources()]
|
||||
[u'doc1']
|
||||
['doc1']
|
||||
>>> view.update()
|
||||
True
|
||||
>>> len(cc1.getResources())
|
||||
|
@ -316,10 +316,10 @@ Index attributes adapter
|
|||
>>> component.provideAdapter(FileAdapter, provides=IFile)
|
||||
>>> idx = IndexAttributes(doc1)
|
||||
>>> idx.text()
|
||||
u''
|
||||
''
|
||||
|
||||
>>> idx.title()
|
||||
u'doc1 Zope Info'
|
||||
'doc1 Zope Info'
|
||||
|
||||
|
||||
Views/Nodes: Menus, Menu Items, Listings, Pages, etc
|
||||
|
@ -343,14 +343,14 @@ The view manager has already been created during setup.
|
|||
The view space is typically built up with nodes; a node may be a top-level
|
||||
menu that may contain other nodes as menu or content items:
|
||||
|
||||
>>> m1 = views['m1'] = Node(u'Menu')
|
||||
>>> m11 = m1['m11'] = Node(u'Zope')
|
||||
>>> m111 = m11['m111'] = Node(u'Zope in General')
|
||||
>>> m112 = m11['m112'] = Node(u'Zope 3')
|
||||
>>> m1 = views['m1'] = Node('Menu')
|
||||
>>> m11 = m1['m11'] = Node('Zope')
|
||||
>>> m111 = m11['m111'] = Node('Zope in General')
|
||||
>>> m112 = m11['m112'] = Node('Zope 3')
|
||||
>>> m112.title
|
||||
u'Zope 3'
|
||||
'Zope 3'
|
||||
>>> m112.description
|
||||
u''
|
||||
''
|
||||
|
||||
There are a few convienence methods for accessing parent and child nodes:
|
||||
|
||||
|
@ -359,7 +359,7 @@ There are a few convienence methods for accessing parent and child nodes:
|
|||
>>> m11.getParentNode() is m1
|
||||
True
|
||||
>>> [getName(child) for child in m11.getChildNodes()]
|
||||
[u'm111', u'm112']
|
||||
['m111', 'm112']
|
||||
|
||||
What is returned by these may be controlled by the nodeType attribute:
|
||||
|
||||
|
@ -444,13 +444,13 @@ Node Views
|
|||
>>> page = view.page
|
||||
>>> items = page.textItems
|
||||
>>> for item in items:
|
||||
... print item.url, item.editable
|
||||
... print(item.url, item.editable)
|
||||
http://127.0.0.1/loops/views/m1/m11/m112 False
|
||||
|
||||
>>> menu = view.menu
|
||||
>>> items = menu.menuItems
|
||||
>>> for item in items:
|
||||
... print item.url, view.selected(item)
|
||||
... print(item.url, view.selected(item))
|
||||
http://127.0.0.1/loops/views/m1/m11 True
|
||||
|
||||
A NodeView provides an itemNum attribute that may be used to count elements
|
||||
|
@ -493,11 +493,11 @@ view; these views we have to provide as multi-adapters:
|
|||
>>> len(tt)
|
||||
9
|
||||
>>> sorted((t.token, t.title) for t in view.targetTypes())[1]
|
||||
('.loops/concepts/domain', u'Domain')
|
||||
('.loops/concepts/domain', 'Domain')
|
||||
>>> view.update()
|
||||
True
|
||||
>>> sorted(resources.keys())
|
||||
[u'd001.txt', u'd002.txt', u'd003.txt', u'doc1', u'm1.m11.m111']
|
||||
['d001.txt', 'd002.txt', 'd003.txt', 'doc1', 'm1.m11.m111']
|
||||
|
||||
>>> view.target.title, view.target.token
|
||||
('New Resource', '.loops/resources/m1.m11.m111')
|
||||
|
@ -537,28 +537,28 @@ view for rendering.)
|
|||
>>> component.provideAdapter(LoopsType)
|
||||
>>> view = NodeView(m112, TestRequest())
|
||||
>>> view.renderTarget()
|
||||
u'<pre></pre>'
|
||||
>>> doc1.data = u'Test data\n\nAnother paragraph'
|
||||
'<pre></pre>'
|
||||
>>> doc1.data = 'Test data\n\nAnother paragraph'
|
||||
>>> view.renderTarget()
|
||||
u'<pre>Test data\n\nAnother paragraph</pre>'
|
||||
'<pre>Test data\n\nAnother paragraph</pre>'
|
||||
|
||||
>>> doc1.contentType = 'text/restructured'
|
||||
>>> doc1.data = u'Test data\n\nAnother `paragraph <para>`_'
|
||||
>>> doc1.data = 'Test data\n\nAnother `paragraph <para>`_'
|
||||
|
||||
>>> from loops.wiki.base import wikiLinksActive
|
||||
>>> wikiLinksActive(loopsRoot)
|
||||
False
|
||||
|
||||
>>> view.renderTarget()
|
||||
u'<p>Test data</p>\n<p>Another <a class="reference external" href="para">paragraph</a></p>\n'
|
||||
'<p>Test data</p>\n<p>Another <a class="reference external" href="para">paragraph</a></p>\n'
|
||||
|
||||
u'<p>Test data</p>\n<p>Another <a class="reference create"
|
||||
'<p>Test data</p>\n<p>Another <a class="reference create"
|
||||
href="http://127.0.0.1/loops/wiki/create.html?linkid=0000001">?paragraph</a></p>\n'
|
||||
|
||||
>>> #links = loopsRoot.getRecordManager()['links']
|
||||
>>> #links['0000001']
|
||||
|
||||
<Link ['42', 1, '', '... ...', u'para', None]: {}>
|
||||
<Link ['42', 1, '', '... ...', 'para', None]: {}>
|
||||
|
||||
If the target object is removed from its container all references
|
||||
to it are removed as well. (To make this work we have to handle
|
||||
|
@ -661,9 +661,9 @@ Breadcrumbs
|
|||
>>> view = NodeView(m114, request)
|
||||
>>> request.annotations.setdefault('loops.view', {})['nodeView'] = view
|
||||
>>> view.breadcrumbs()
|
||||
[{'url': 'http://127.0.0.1/loops/views/m1', 'label': u'Menu'},
|
||||
{'url': 'http://127.0.0.1/loops/views/m1/m11', 'label': u'Zope'},
|
||||
{'url': 'http://127.0.0.1/loops/views/m1/m11/m114', 'label': u''}]
|
||||
[{'label': 'Menu', 'url': 'http://127.0.0.1/loops/views/m1'},
|
||||
{'label': 'Zope', 'url': 'http://127.0.0.1/loops/views/m1/m11'},
|
||||
{'label': '', 'url': 'http://127.0.0.1/loops/views/m1/m11/m114'}]
|
||||
|
||||
|
||||
End-user Forms and Special Views
|
||||
|
@ -705,8 +705,8 @@ been created during setup.
|
|||
>>> custType = TypeConcept(customer)
|
||||
>>> custType.options
|
||||
[]
|
||||
>>> cust1 = concepts['cust1'] = Concept(u'Zope Corporation')
|
||||
>>> cust2 = concepts['cust2'] = Concept(u'cyberconcepts')
|
||||
>>> cust1 = concepts['cust1'] = Concept('Zope Corporation')
|
||||
>>> cust2 = concepts['cust2'] = Concept('cyberconcepts')
|
||||
>>> for c in (cust1, cust2): c.conceptType = customer
|
||||
>>> custType.options = ('qualifier:assign',)
|
||||
>>> ConceptType(cust1).qualifiers
|
||||
|
@ -714,7 +714,7 @@ been created during setup.
|
|||
|
||||
>>> form = CreateObjectForm(m112, TestRequest())
|
||||
>>> form.presetTypesForAssignment
|
||||
[{'token': 'loops:concept:customer', 'title': u'Customer'}]
|
||||
[{'title': 'Customer', 'token': 'loops:concept:customer'}]
|
||||
|
||||
If the node's target is a type concept we don't get any assignments because
|
||||
it does not make much sense to assign resources or other concepts as
|
||||
|
@ -736,18 +736,18 @@ on data provided in this form:
|
|||
>>> note_tc = concepts['note']
|
||||
|
||||
>>> component.provideAdapter(NameChooser)
|
||||
>>> request = TestRequest(form={'title': u'Test Note',
|
||||
... 'form.type': u'.loops/concepts/note',
|
||||
... 'contentType': u'text/restructured',
|
||||
... 'linkUrl': u'http://'})
|
||||
>>> request = TestRequest(form={'title': 'Test Note',
|
||||
... 'form.type': '.loops/concepts/note',
|
||||
... 'contentType': 'text/restructured',
|
||||
... 'linkUrl': 'http://'})
|
||||
>>> view = NodeView(m112, request)
|
||||
>>> cont = CreateObject(view, request)
|
||||
>>> cont.update()
|
||||
False
|
||||
>>> sorted(resources.keys())
|
||||
[...u'test_note'...]
|
||||
[...'test_note'...]
|
||||
>>> resources['test_note'].title
|
||||
u'Test Note'
|
||||
'Test Note'
|
||||
|
||||
If there is a concept selected in the combo box we assign this to the newly
|
||||
created object:
|
||||
|
@ -755,8 +755,8 @@ created object:
|
|||
>>> from loops import util
|
||||
>>> topicUid = util.getUidForObject(topic)
|
||||
>>> predicateUid = util.getUidForObject(concepts.getDefaultPredicate())
|
||||
>>> request = TestRequest(form={'title': u'Test Note',
|
||||
... 'form.type': u'.loops/concepts/note',
|
||||
>>> request = TestRequest(form={'title': 'Test Note',
|
||||
... 'form.type': '.loops/concepts/note',
|
||||
... 'form.assignments.selected':
|
||||
... [':'.join((topicUid, predicateUid))]})
|
||||
>>> view = NodeView(m112, request)
|
||||
|
@ -764,22 +764,22 @@ created object:
|
|||
>>> cont.update()
|
||||
False
|
||||
>>> sorted(resources.keys())
|
||||
[...u'test_note-2'...]
|
||||
[...'test_note-2'...]
|
||||
>>> note = resources['test_note-2']
|
||||
>>> sorted(t.__name__ for t in note.getConcepts())
|
||||
[u'note', u'topic']
|
||||
['note', 'topic']
|
||||
|
||||
When creating an object its name may be automatically generated using the title
|
||||
of the object. Let's make sure that the name chooser also handles special
|
||||
and possibly critcal cases:
|
||||
|
||||
>>> nc = NameChooser(resources)
|
||||
>>> nc.chooseName(u'', Resource(u'abc: (cde)'))
|
||||
u'abc__cde'
|
||||
>>> nc.chooseName(u'', Resource(u'\xdcml\xe4ut'))
|
||||
u'uemlaeut'
|
||||
>>> nc.chooseName(u'', Resource(u'A very very loooooong title'))
|
||||
u'a_title'
|
||||
>>> nc.chooseName('', Resource('abc: (cde)'))
|
||||
'abc__cde'
|
||||
>>> nc.chooseName('', Resource('\xdcml\xe4ut'))
|
||||
'uemlaeut'
|
||||
>>> nc.chooseName('', Resource('A very very loooooong title'))
|
||||
'a_title'
|
||||
|
||||
Editing an Object
|
||||
-----------------
|
||||
|
@ -796,7 +796,7 @@ that in turns calls formlibs ``setUpWidgets()``.
|
|||
The new technique uses the ``fields`` and ``data`` attributes...
|
||||
|
||||
>>> for f in view.fields:
|
||||
... print f.name, f.fieldType, f.required, f.vocabulary
|
||||
... print(f.name, f.fieldType, f.required, f.vocabulary)
|
||||
title textline True None
|
||||
data textarea False None
|
||||
contentType dropdown True <...SimpleVocabulary object...>
|
||||
|
@ -804,22 +804,22 @@ The new technique uses the ``fields`` and ``data`` attributes...
|
|||
linkText textline False None
|
||||
|
||||
>>> view.data
|
||||
{'linkUrl': u'http://', 'contentType': u'text/restructured', 'data': u'',
|
||||
'linkText': u'', 'title': u'Test Note'}
|
||||
{'title': 'Test Note', 'data': '', 'contentType': 'text/restructured',
|
||||
'linkUrl': 'http://', 'linkText': ''}
|
||||
|
||||
The object is changed via a FormController adapter created for
|
||||
a NodeView.
|
||||
|
||||
>>> form = dict(
|
||||
... title=u'Test Note - changed',
|
||||
... contentType=u'text/plain',)
|
||||
... title='Test Note - changed',
|
||||
... contentType='text/plain',)
|
||||
>>> request = TestRequest(form=form)
|
||||
>>> view = NodeView(m112, request)
|
||||
>>> cont = EditObject(view, request)
|
||||
>>> cont.update()
|
||||
False
|
||||
>>> resources['test_note'].title
|
||||
u'Test Note - changed'
|
||||
'Test Note - changed'
|
||||
|
||||
Virtual Targets
|
||||
---------------
|
||||
|
@ -883,13 +883,13 @@ informations about all parents of an object.
|
|||
|
||||
>>> parents = m113.getAllParents()
|
||||
>>> for p in parents:
|
||||
... print p.object.title
|
||||
... print(p.object.title)
|
||||
Zope
|
||||
Menu
|
||||
|
||||
>>> parents = resources['test_note'].getAllParents()
|
||||
>>> for p in parents:
|
||||
... print p.object.title, len(p.relations)
|
||||
... print(p.object.title, len(p.relations))
|
||||
Note 1
|
||||
Type 2
|
||||
|
||||
|
@ -916,10 +916,30 @@ relates ISO country codes with the full name of the country.
|
|||
[('at', ['Austria']), ('de', ['Germany'])]
|
||||
|
||||
>>> countries.dataAsRecords()
|
||||
[{'value': 'Austria', 'key': 'at'}, {'value': 'Germany', 'key': 'de'}]
|
||||
[{'key': 'at', 'value': 'Austria'}, {'key': 'de', 'value': 'Germany'}]
|
||||
|
||||
>>> countries.getRowsByValue('value', 'Germany')
|
||||
[{'value': 'Germany', 'key': 'de'}]
|
||||
[{'key': 'de', 'value': 'Germany'}]
|
||||
|
||||
The ``recordstable`` type is a variation of this datable type that contains
|
||||
a simple list of records - without a key column. A record in this type is a
|
||||
dictionary with the field name as key and the field value as value.
|
||||
|
||||
>>> from loops.table import IRecordsTable, RecordsTable
|
||||
>>> component.provideAdapter(RecordsTable, provides=IRecordsTable)
|
||||
|
||||
>>> drType = addAndConfigureObject(concepts, Concept, 'recordstable',
|
||||
... title='Records Table', conceptType=concepts['type'],
|
||||
... typeInterface=IRecordsTable)
|
||||
|
||||
We just reuse the existing ``countries`` table and convert it to a records table.
|
||||
|
||||
>>> baseObject(countries).setType(drType)
|
||||
|
||||
>>> countries = adapted(concepts['countries'])
|
||||
|
||||
>>> countries.data
|
||||
[{'key': 'at', 'value': 'Austria'}, {'key': 'de', 'value': 'Germany'}]
|
||||
|
||||
|
||||
Caching
|
||||
|
@ -931,7 +951,7 @@ To be done...
|
|||
>>> obj = resources['test_note']
|
||||
>>> cxObj = cached(obj)
|
||||
>>> [p.object.title for p in cxObj.getAllParents()]
|
||||
[u'Note', u'Type']
|
||||
['Note', 'Type']
|
||||
|
||||
|
||||
Security
|
|
@ -1,30 +1,13 @@
|
|||
#
|
||||
# Copyright (c) 2017 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# loops.base
|
||||
|
||||
"""
|
||||
Implementation of loops root object.
|
||||
""" Implementation of loops root object.
|
||||
"""
|
||||
|
||||
from zope.app.container.btree import BTreeContainer
|
||||
from zope.app.folder.folder import Folder
|
||||
from zope.app.folder.interfaces import IFolder
|
||||
from zope.container.btree import BTreeContainer
|
||||
from zope.site.folder import Folder
|
||||
from zope.site.interfaces import IFolder
|
||||
from zope.traversing.api import getPath, traverse
|
||||
from zope.interface import implements
|
||||
from zope.interface import implementer
|
||||
|
||||
from cybertools.util.jeep import Jeep
|
||||
from loops.interfaces import ILoops
|
||||
|
@ -32,17 +15,8 @@ from loops.interfaces import ILoops
|
|||
loopsPrefix = '.loops'
|
||||
|
||||
|
||||
@implementer(ILoops)
|
||||
class Loops(Folder):
|
||||
#class Loops(BTreeContainer):
|
||||
|
||||
implements(ILoops)
|
||||
|
||||
#def getSiteManager(self):
|
||||
# return self.__parent__.getSiteManager()
|
||||
|
||||
#@property
|
||||
#def _SampleContainer__data(self):
|
||||
# return self.data
|
||||
|
||||
_skinName = ''
|
||||
def getSkinName(self): return self._skinName
|
||||
|
@ -72,7 +46,8 @@ class Loops(Folder):
|
|||
return self.get('records')
|
||||
|
||||
def getLoopsUri(self, obj):
|
||||
return str(loopsPrefix + getPath(obj)[len(getPath(self)):])
|
||||
uri = loopsPrefix + getPath(obj)[len(getPath(self)):]
|
||||
return uri
|
||||
|
||||
def loopsTraverse(self, uri):
|
||||
prefix = loopsPrefix + '/'
|
68
loops/bluebream.zcml
Normal file
|
@ -0,0 +1,68 @@
|
|||
<configure
|
||||
xmlns="http://namespaces.zope.org/zope"
|
||||
xmlns:browser="http://namespaces.zope.org/browser">
|
||||
|
||||
<include package="zope.component" file="meta.zcml" />
|
||||
<include package="zope.security" file="meta.zcml" />
|
||||
<include package="zope.publisher" file="meta.zcml" />
|
||||
<include package="zope.i18n" file="meta.zcml" />
|
||||
<include package="zope.browserresource" file="meta.zcml" />
|
||||
<include package="zope.browsermenu" file="meta.zcml" />
|
||||
<include package="zope.browserpage" file="meta.zcml" />
|
||||
<include package="zope.securitypolicy" file="meta.zcml" />
|
||||
<include package="zope.principalregistry" file="meta.zcml" />
|
||||
<include package="zope.app.publication" file="meta.zcml" />
|
||||
<include package="zope.app.form.browser" file="meta.zcml" />
|
||||
<include package="zope.app.container.browser" file="meta.zcml" />
|
||||
|
||||
<include package="zope.browserresource" />
|
||||
<include package="zope.copypastemove" />
|
||||
<include package="zope.publisher" />
|
||||
<include package="zope.component" />
|
||||
<include package="zope.traversing" />
|
||||
<include package="zope.location" />
|
||||
<include package="zope.site" />
|
||||
<include package="zope.annotation" />
|
||||
<include package="zope.principalregistry" />
|
||||
<include package="zope.container" />
|
||||
<include package="zope.componentvocabulary" />
|
||||
<include package="zope.formlib" />
|
||||
<include package="zope.app.appsetup" />
|
||||
<include package="zope.app.security" />
|
||||
<include package="zope.app.publication" />
|
||||
<include package="zope.app.form.browser" />
|
||||
<include package="zope.app.basicskin" />
|
||||
<include package="zope.browsermenu" />
|
||||
<include package="zope.authentication" />
|
||||
<include package="zope.securitypolicy" />
|
||||
<include package="zope.login" />
|
||||
<include package="zope.session" />
|
||||
<include package="zope.error" />
|
||||
<include package="zope.app.zcmlfiles" file="menus.zcml" />
|
||||
<include package="zope.app.authentication" />
|
||||
<include package="zope.app.security.browser" />
|
||||
<include package="zope.app.catalog" />
|
||||
<include package="zope.traversing.browser" />
|
||||
<include package="zope.browserpage" />
|
||||
<include package="zope.app.schema" />
|
||||
<include package="zope.app.http" />
|
||||
<include package="zope.keyreference" />
|
||||
<include package="zope.intid" />
|
||||
<include package="zope.contentprovider" />
|
||||
<include package="zope.i18n" />
|
||||
<include package="zope.catalog" />
|
||||
<include package="zope.dublincore.browser" />
|
||||
|
||||
<include package="zope.app.zcmlfiles" />
|
||||
<include package="zope.app.i18n" />
|
||||
<include package="zope.app.intid" />
|
||||
<include package="zope.app.renderer" />
|
||||
<include package="zope.app.session" />
|
||||
<include package="zope.sendmail" file="meta.zcml" />
|
||||
|
||||
<browser:defaultView
|
||||
for="zope.container.interfaces.IContainer"
|
||||
name="index.html" />
|
||||
|
||||
</configure>
|
||||
|
|
@ -1,26 +1,9 @@
|
|||
#
|
||||
# Copyright (c) 2013 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# loops.browser.action
|
||||
|
||||
"""
|
||||
Base classes (sort of views) for action portlet items.
|
||||
""" Base classes (sort of views) for action portlet items.
|
||||
"""
|
||||
|
||||
from urllib import urlencode
|
||||
from urllib.parse import urlencode
|
||||
from zope import component
|
||||
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||
from zope.cachedescriptors.property import Lazy
|
78
loops/browser/auth.py
Normal file
|
@ -0,0 +1,78 @@
|
|||
# loops.browser.auth
|
||||
|
||||
""" Login, logout, unauthorized stuff.
|
||||
"""
|
||||
|
||||
from zope.app.exception.browser.unauthorized import Unauthorized as DefaultUnauth
|
||||
from zope.authentication.interfaces import IAuthentication
|
||||
from zope.authentication.interfaces import ILogout, IUnauthenticatedPrincipal
|
||||
from zope.browserpage import ViewPageTemplateFile
|
||||
from zope.cachedescriptors.property import Lazy
|
||||
from zope import component
|
||||
from zope.interface import implementer
|
||||
|
||||
from loops.browser.concept import ConceptView
|
||||
from loops.browser.node import NodeView
|
||||
|
||||
|
||||
template = ViewPageTemplateFile('auth.pt')
|
||||
|
||||
|
||||
class LoginConcept(ConceptView):
|
||||
|
||||
template = template
|
||||
|
||||
@Lazy
|
||||
def macro(self):
|
||||
return self.template.macros['login_form']
|
||||
|
||||
|
||||
class LoginForm(NodeView):
|
||||
|
||||
template = template
|
||||
|
||||
@Lazy
|
||||
def macro(self):
|
||||
return self.template.macros['login_form']
|
||||
|
||||
@Lazy
|
||||
def item(self):
|
||||
return self
|
||||
|
||||
|
||||
@implementer(ILogout)
|
||||
class Logout(object):
|
||||
|
||||
|
||||
def __init__(self, context, request):
|
||||
self.context = context
|
||||
self.request = request
|
||||
|
||||
def __call__(self):
|
||||
nextUrl = self.request.get('nextURL') or self.request.URL[-1]
|
||||
if not IUnauthenticatedPrincipal.providedBy(self.request.principal):
|
||||
auth = component.getUtility(IAuthentication)
|
||||
ILogout(auth).logout(self.request)
|
||||
return self.request.response.redirect(nextUrl)
|
||||
|
||||
|
||||
class Unauthorized(ConceptView):
|
||||
|
||||
isTopLevel = True
|
||||
|
||||
def __init__(self, context, request):
|
||||
self.context = context
|
||||
self.request = request
|
||||
|
||||
def __call__(self):
|
||||
response = self.request.response
|
||||
response.setStatus(403)
|
||||
# make sure that squid does not keep the response in the cache
|
||||
response.setHeader('Expires', 'Mon, 26 Jul 1997 05:00:00 GMT')
|
||||
response.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate')
|
||||
response.setHeader('Pragma', 'no-cache')
|
||||
if self.nodeView is None:
|
||||
v = DefaultUnauth(self.context, self.request)
|
||||
return v()
|
||||
url = self.nodeView.topMenu.url
|
||||
response.redirect(url + '/unauthorized')
|
|
@ -1,45 +1,28 @@
|
|||
#
|
||||
# Copyright (c) 2016 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# loops.browser.common
|
||||
|
||||
"""
|
||||
Common base class for loops browser view classes.
|
||||
""" Common base class for loops browser view classes.
|
||||
"""
|
||||
|
||||
from cgi import parse_qs, parse_qsl
|
||||
#import mimetypes # use more specific assignments from cybertools.text
|
||||
from datetime import date, datetime
|
||||
from logging import getLogger
|
||||
import re
|
||||
from time import strptime
|
||||
from urllib import urlencode
|
||||
from urllib.parse import parse_qs, parse_qsl, urlencode
|
||||
from zope import component
|
||||
from zope.app.form.browser.interfaces import ITerms
|
||||
from zope.app.i18n.interfaces import ITranslationDomain
|
||||
from zope.app.security.interfaces import IAuthentication, IUnauthenticatedPrincipal
|
||||
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||
from zope.app.security.interfaces import IUnauthenticatedPrincipal
|
||||
from zope.app.security.interfaces import PrincipalLookupError
|
||||
from zope.authentication.interfaces import IAuthentication, IUnauthenticatedPrincipal
|
||||
from zope.authentication.interfaces import IUnauthenticatedPrincipal
|
||||
from zope.authentication.interfaces import PrincipalLookupError
|
||||
from zope.browser.interfaces import ITerms
|
||||
from zope.browserpage import ViewPageTemplateFile
|
||||
from zope.cachedescriptors.property import Lazy
|
||||
from zope.dottedname.resolve import resolve
|
||||
from zope.dublincore.interfaces import IZopeDublinCore
|
||||
from zope.formlib import form
|
||||
from zope.formlib.form import FormFields
|
||||
from zope.formlib.namedtemplate import NamedTemplate
|
||||
from zope.interface import Interface, implements
|
||||
from zope.i18n.interfaces import ITranslationDomain
|
||||
from zope.interface import Interface, implementer
|
||||
from zope.proxy import removeAllProxies
|
||||
from zope.publisher.browser import applySkin
|
||||
from zope.publisher.interfaces.browser import IBrowserSkinType, IBrowserView
|
||||
|
@ -98,16 +81,20 @@ class NameField(schema.ASCIILine):
|
|||
class ViewMode(object):
|
||||
|
||||
def __init__(self, name='view', title=None, url=None, active=False,
|
||||
description=u''):
|
||||
description=u'', subViewModes=Jeep()):
|
||||
self.name = name
|
||||
self.title = title
|
||||
self.url = url
|
||||
self.active = active
|
||||
self.description = description
|
||||
self.subViewModes = subViewModes
|
||||
|
||||
@property
|
||||
def cssClass(self):
|
||||
return self.active and u'active' or u'inactive'
|
||||
result = self.active and u'active' or u'inactive'
|
||||
if self.subViewModes:
|
||||
result += u' sub-modes'
|
||||
return result
|
||||
|
||||
|
||||
class IAddForm(Interface):
|
||||
|
@ -205,6 +192,10 @@ class BaseView(GenericView, I18NView, SortableMixin):
|
|||
self.context = removeSecurityProxy(context)
|
||||
try:
|
||||
if not self.checkPermissions():
|
||||
logger = getLogger('loops.browser.common-153')
|
||||
principal = request.principal and request.principal.id
|
||||
msg = 'Unauthorized: %s, %s' % (self.contextInfo, principal)
|
||||
logger.warn(msg)
|
||||
raise Unauthorized(str(self.contextInfo))
|
||||
except ForbiddenAttribute: # ignore when testing
|
||||
pass
|
||||
|
@ -904,6 +895,7 @@ class BaseView(GenericView, I18NView, SortableMixin):
|
|||
|
||||
@Lazy
|
||||
def xeditable(self):
|
||||
return False
|
||||
if self.typeOptions('no_external_edit'):
|
||||
return False
|
||||
ct = getattr(self.context, 'contentType', '')
|
||||
|
@ -952,9 +944,9 @@ class BaseView(GenericView, I18NView, SortableMixin):
|
|||
djConfig='parseOnLoad: true, usePlainJson: true, '
|
||||
#'isDebug: true, '
|
||||
'locale: "%s"' % self.languageInfo.language)
|
||||
jsCall = ('dojo.require("dojo.parser"); '
|
||||
'dojo.registerModulePath("jocy", "/@@/cybertools.jocy"); '
|
||||
'dojo.require("jocy.data");')
|
||||
jsCall = ('dojo.require("dojo.parser"); ')
|
||||
#'dojo.registerModulePath("jocy", "/@@/cybertools.jocy"); '
|
||||
#'dojo.require("jocy.data");')
|
||||
cm.register('js-execute', 'dojo_registration', jsCall=jsCall)
|
||||
cm.register('css', identifier='Lightbox.css', position=0,
|
||||
resourceName='ajax.dojo/dojox/image/resources/Lightbox.css',
|
||||
|
@ -1082,13 +1074,12 @@ class LoggedIn(object):
|
|||
|
||||
# vocabulary stuff
|
||||
|
||||
@implementer(ITerms)
|
||||
class SimpleTerms(object):
|
||||
""" Provide the ITerms interface, e.g. for usage in selection
|
||||
lists.
|
||||
"""
|
||||
|
||||
implements(ITerms)
|
||||
|
||||
def __init__(self, source, request):
|
||||
# the source parameter is a list of tuples (token, title).
|
||||
self.source = source
|
||||
|
@ -1103,13 +1094,12 @@ class SimpleTerms(object):
|
|||
return (token, self.terms[token])
|
||||
|
||||
|
||||
@implementer(ITerms)
|
||||
class LoopsTerms(object):
|
||||
""" Provide the ITerms interface, e.g. for usage in selection
|
||||
lists.
|
||||
"""
|
||||
|
||||
implements(ITerms)
|
||||
|
||||
def __init__(self, source, request):
|
||||
# the source parameter is a view or adapter of a real context object:
|
||||
self.source = source
|
||||
|
@ -1131,12 +1121,11 @@ class LoopsTerms(object):
|
|||
return self.loopsRoot.loopsTraverse(token)
|
||||
|
||||
|
||||
@implementer(ITerms)
|
||||
class InterfaceTerms(object):
|
||||
""" Provide the ITerms interface for source list of interfaces.
|
||||
"""
|
||||
|
||||
implements(ITerms)
|
||||
|
||||
def __init__(self, source, request):
|
||||
self.source = source
|
||||
self.request = request
|
|
@ -1,40 +1,22 @@
|
|||
#
|
||||
# Copyright (c) 2016 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# loops.browser.concept
|
||||
|
||||
"""
|
||||
Definition of the concept view classes.
|
||||
""" Definition of the concept view classes.
|
||||
"""
|
||||
|
||||
from itertools import groupby
|
||||
from zope import interface, component, schema
|
||||
from zope.app.catalog.interfaces import ICatalog
|
||||
from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent
|
||||
from zope.app.container.contained import ObjectRemovedEvent
|
||||
from zope.app.form.browser.interfaces import ITerms
|
||||
from zope.app.form.interfaces import IDisplayWidget
|
||||
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||
from zope.app.security.interfaces import IUnauthenticatedPrincipal
|
||||
from zope.authentication.interfaces import IUnauthenticatedPrincipal
|
||||
from zope.browser.interfaces import ITerms
|
||||
from zope.browserpage import ViewPageTemplateFile
|
||||
from zope.cachedescriptors.property import Lazy
|
||||
from zope.catalog.interfaces import ICatalog
|
||||
from zope.container.contained import ObjectRemovedEvent
|
||||
from zope.dottedname.resolve import resolve
|
||||
from zope.event import notify
|
||||
from zope.formlib.form import EditForm, FormFields, setUpEditWidgets
|
||||
from zope.formlib.interfaces import IDisplayWidget
|
||||
from zope.formlib.namedtemplate import NamedTemplate
|
||||
from zope.interface import implements
|
||||
from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent
|
||||
from zope.publisher.interfaces import BadRequest
|
||||
from zope.publisher.interfaces.browser import IBrowserRequest
|
||||
from zope.schema.interfaces import IIterableSource
|
||||
|
@ -308,7 +290,7 @@ class ConceptView(BaseView):
|
|||
def breadcrumbsParent(self):
|
||||
for p in self.context.getParents([self.defaultPredicate]):
|
||||
view = self.nodeView.getViewForTarget(p)
|
||||
if view.showInBreadcrumbs:
|
||||
if view is not None and view.showInBreadcrumbs:
|
||||
return view
|
||||
return None
|
||||
|
||||
|
@ -463,7 +445,7 @@ class ConceptView(BaseView):
|
|||
|
||||
def parents(self):
|
||||
rels = sorted(self.context.getParentRelations(),
|
||||
key=(lambda x: x.first.title and x.first.title.lower()))
|
||||
key=(lambda x: x.first.title and x.first.title.lower() or ''))
|
||||
for r in rels:
|
||||
yield self.childViewFactory(r, self.request)
|
||||
|
|
@ -10,7 +10,9 @@
|
|||
|
||||
<metal:data define-macro="conceptdata">
|
||||
<div tal:attributes="class string:content-$level;">
|
||||
<metal:block use-macro="view/concept_macros/concepttitle" />
|
||||
<tal:block condition="not:title_shown|python:False">
|
||||
<metal:block use-macro="view/concept_macros/concepttitle"/>
|
||||
</tal:block>
|
||||
<metal:slot define-slot="fields">
|
||||
<metal:block use-macro="view/concept_macros/conceptfields" />
|
||||
</metal:slot>
|
||||
|
@ -185,7 +187,7 @@
|
|||
</tr>
|
||||
<tal:nested condition="list_nested">
|
||||
<tr tal:define="children python:
|
||||
list(related.unique(related.children()));
|
||||
list(related.unique(related.children()));
|
||||
resources python:list(related.resources())"
|
||||
tal:condition="python:children or resources">
|
||||
<td tal:condition="item/showCheckboxes|nothing" />
|
|
@ -34,16 +34,18 @@
|
|||
|
||||
<!-- login/logout -->
|
||||
|
||||
<page for="loops.interfaces.INode"
|
||||
<!--<page for="loops.interfaces.INode"
|
||||
name="login.html"
|
||||
class="loops.browser.auth.LoginForm"
|
||||
permission="zope.View" />
|
||||
permission="zope.View" />-->
|
||||
|
||||
<page for="loops.interfaces.INode"
|
||||
name="logout.html"
|
||||
class="loops.browser.auth.Logout"
|
||||
permission="zope.View" />
|
||||
|
||||
<!-- see also view/adapter "login.html" in section "query views" -->
|
||||
|
||||
<!-- macros -->
|
||||
|
||||
<page
|
||||
|
@ -537,6 +539,14 @@
|
|||
|
||||
<!-- query views -->
|
||||
|
||||
<!--<zope:adapter
|
||||
name="login.html"
|
||||
for="loops.interfaces.IConcept
|
||||
zope.publisher.interfaces.browser.IBrowserRequest"
|
||||
provides="zope.interface.Interface"
|
||||
factory="loops.browser.auth.LoginConcept"
|
||||
permission="zope.View" />-->
|
||||
|
||||
<zope:adapter
|
||||
name="list_children.html"
|
||||
for="loops.interfaces.IConcept
|
|
@ -1,28 +1,8 @@
|
|||
#
|
||||
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# loops.browser.external
|
||||
|
||||
"""
|
||||
view class(es) for import/export.
|
||||
|
||||
$Id$
|
||||
""" view class(es) for import/export.
|
||||
"""
|
||||
|
||||
from zope.interface import Interface, implements
|
||||
from zope.app import zapi
|
||||
from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
|
||||
from zope.cachedescriptors.property import Lazy
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
@ -1,35 +1,18 @@
|
|||
#
|
||||
# Copyright (c) 2017 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# loops.browser.form
|
||||
|
||||
"""
|
||||
Classes for form presentation and processing.
|
||||
""" Classes for form presentation and processing.
|
||||
"""
|
||||
|
||||
from urllib import urlencode, unquote_plus
|
||||
from zope.app.container.contained import ObjectRemovedEvent
|
||||
from urllib.parse import urlencode, unquote_plus
|
||||
from zope import component, interface, schema
|
||||
from zope.component import adapts
|
||||
from zope.container.contained import ObjectRemovedEvent
|
||||
from zope.event import notify
|
||||
from zope.interface import Interface
|
||||
from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent
|
||||
from zope.app.container.interfaces import INameChooser
|
||||
from zope.app.container.contained import ObjectAddedEvent
|
||||
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||
from zope.container.interfaces import INameChooser
|
||||
from zope.lifecycleevent import ObjectAddedEvent
|
||||
from zope.browserpage import ViewPageTemplateFile
|
||||
from zope.cachedescriptors.property import Lazy
|
||||
from zope.contenttype import guess_content_type
|
||||
from zope.publisher.browser import FileUpload
|
||||
|
@ -182,7 +165,9 @@ class ObjectForm(NodeView):
|
|||
field = self.schema.fields.get(k)
|
||||
if field:
|
||||
fi = field.getFieldInstance(self.instance)
|
||||
input = unquote_plus(form[k])
|
||||
input = form[k]
|
||||
if isinstance(input, str):
|
||||
input = unquote_plus(input)
|
||||
data[k] = fi.marshall(fi.unmarshall(input))
|
||||
#data[k] = toUnicode(form[k])
|
||||
return data
|
||||
|
@ -364,6 +349,7 @@ class CreateObjectForm(ObjectForm):
|
|||
def adapted(self):
|
||||
ad = self.typeInterface(Resource())
|
||||
ad.storageName = 'unknown' # hack for file objects: don't try to retrieve data
|
||||
ad.__is_dummy__ = True
|
||||
ad.__type__ = adapted(self.typeConcept)
|
||||
return ad
|
||||
|
|
@ -1,26 +1,9 @@
|
|||
#
|
||||
# Copyright (c) 2012 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# loops.browser.lobo.standard
|
||||
|
||||
"""
|
||||
View classes for lobo (blueprint-based) layouts.
|
||||
""" View classes for lobo (blueprint-based) layouts.
|
||||
"""
|
||||
|
||||
from cgi import parse_qs
|
||||
from urllib.parse import parse_qs
|
||||
from zope import interface, component
|
||||
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||
from zope.cachedescriptors.property import Lazy
|
|
@ -1,3 +1,4 @@
|
|||
# loops.browser.lobo.tests
|
||||
|
||||
import unittest, doctest
|
||||
from zope.interface.verify import verifyClass
|
||||
|
@ -12,9 +13,9 @@ class Test(unittest.TestCase):
|
|||
def test_suite():
|
||||
flags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
|
||||
return unittest.TestSuite((
|
||||
unittest.makeSuite(Test),
|
||||
doctest.DocFileSuite('README.txt', optionflags=flags),
|
||||
))
|
||||
unittest.TestLoader().loadTestsFromTestCase(Test),
|
||||
doctest.DocFileSuite('README.txt', optionflags=flags),
|
||||
))
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main(defaultTest='test_suite')
|
Before Width: | Height: | Size: 942 B After Width: | Height: | Size: 942 B |
|
@ -1,31 +1,11 @@
|
|||
#
|
||||
# Copyright (c) 2011 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# loops.browser.mobile.default
|
||||
|
||||
"""
|
||||
Default layouts for the loops mobile skin.
|
||||
|
||||
$Id$
|
||||
""" Default layouts for the loops mobile skin.
|
||||
"""
|
||||
|
||||
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||
from zope.cachedescriptors.property import Lazy
|
||||
from zope import component
|
||||
from zope.interface import implements
|
||||
|
||||
from cybertools.browser.renderer import RendererFactory
|
||||
from cybertools.composer.layout.base import Layout
|
|
@ -1,35 +1,20 @@
|
|||
#
|
||||
# Copyright (c) 2017 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# loops.browser.node
|
||||
|
||||
"""
|
||||
View class for Node objects.
|
||||
""" View class for Node objects.
|
||||
"""
|
||||
|
||||
from urlparse import urlparse, urlunparse
|
||||
from zope import component, interface, schema
|
||||
from zope.cachedescriptors.property import Lazy
|
||||
from zope.annotation.interfaces import IAnnotations
|
||||
from zope.app.catalog.interfaces import ICatalog
|
||||
from logging import getLogger
|
||||
from urllib.parse import urlencode, urlparse, urlunparse
|
||||
#from urlparse import urlparse, urlunparse
|
||||
from zope.app.container.browser.contents import JustContents
|
||||
from zope.app.container.browser.adding import Adding
|
||||
from zope.app.container.traversal import ItemTraverser
|
||||
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||
from zope.app.security.interfaces import IUnauthenticatedPrincipal
|
||||
from zope import component, interface, schema
|
||||
from zope.annotation.interfaces import IAnnotations
|
||||
from zope.authentication.interfaces import IUnauthenticatedPrincipal
|
||||
from zope.browserpage import ViewPageTemplateFile
|
||||
from zope.cachedescriptors.property import Lazy
|
||||
from zope.catalog.interfaces import ICatalog
|
||||
from zope.container.traversal import ItemTraverser
|
||||
from zope.dottedname.resolve import resolve
|
||||
from zope.event import notify
|
||||
from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent
|
||||
|
@ -37,6 +22,7 @@ from zope.lifecycleevent import Attributes
|
|||
from zope.formlib.form import Form, FormFields
|
||||
from zope.proxy import removeAllProxies
|
||||
from zope.publisher.defaultview import getDefaultViewName
|
||||
from zope.publisher.interfaces import NotFound
|
||||
from zope.security import canAccess, canWrite, checkPermission
|
||||
from zope.security.proxy import removeSecurityProxy
|
||||
from zope.traversing.api import getParent, getParents, getPath
|
||||
|
@ -65,6 +51,7 @@ from loops import util
|
|||
from loops.util import _
|
||||
from loops.versioning.util import getVersion
|
||||
|
||||
logger = getLogger('loops.browser.node')
|
||||
|
||||
node_macros = ViewPageTemplateFile('node_macros.pt')
|
||||
info_macros = ViewPageTemplateFile('info.pt')
|
||||
|
@ -473,6 +460,11 @@ class NodeView(BaseView):
|
|||
def active(self, item):
|
||||
return item.context == self.context or item.context in self.parents
|
||||
|
||||
@Lazy
|
||||
def logoutUrl(self):
|
||||
nextUrl = urlencode(dict(nextUrl=self.menu.url))
|
||||
return '%s/logout.html?%s' % (self.menu.url, nextUrl)
|
||||
|
||||
@Lazy
|
||||
def authenticationMethod(self):
|
||||
return self.viewAnnotations.get('auth_method') or 'standard'
|
||||
|
@ -589,7 +581,7 @@ class NodeView(BaseView):
|
|||
@Lazy
|
||||
def typeProvider(self):
|
||||
if self.virtualTargetObject is not None:
|
||||
return IType(self.virtualTargetObject).typeProvider
|
||||
return IType(baseObject(self.virtualTargetObject)).typeProvider
|
||||
return None
|
||||
|
||||
# target viewing and editing support
|
||||
|
@ -777,11 +769,11 @@ class InlineEdit(NodeView):
|
|||
if ti is not None:
|
||||
target = ti(target)
|
||||
data = self.request.form['editorContent']
|
||||
if type(data) != unicode:
|
||||
if not isinstance(data, str):
|
||||
try:
|
||||
data = data.decode('ISO-8859-15') # IE hack
|
||||
except UnicodeDecodeError:
|
||||
print 'loops.browser.node.InlineEdit.save():', data
|
||||
print('loops.browser.node.InlineEdit.save():', data)
|
||||
return
|
||||
# data = data.decode('UTF-8')
|
||||
target.data = data
|
||||
|
@ -953,9 +945,9 @@ class NodeAdding(Adding):
|
|||
return info
|
||||
|
||||
|
||||
@interface.implementer(IViewConfiguratorSchema)
|
||||
class ViewPropertiesConfigurator(object):
|
||||
|
||||
interface.implements(IViewConfiguratorSchema)
|
||||
component.adapts(INode)
|
||||
|
||||
def __init__(self, context):
|
||||
|
@ -1041,7 +1033,12 @@ class NodeTraverser(ItemTraverser):
|
|||
viewAnnotations['targetView'] = view
|
||||
view.logInfo('NodeTraverser:targetView = %r' % view)
|
||||
return self.context
|
||||
obj = super(NodeTraverser, self).publishTraverse(request, name)
|
||||
try:
|
||||
obj = super(NodeTraverser, self).publishTraverse(request, name)
|
||||
except NotFound:
|
||||
logger.warn('NodeTraverser: NotFound: URL = %s, name = %r' %
|
||||
(request.URL, name))
|
||||
raise
|
||||
return obj
|
||||
|
||||
def getTargetUid(self, request):
|
||||
|
@ -1089,7 +1086,9 @@ def setViewConfiguration(context, request):
|
|||
config = IViewConfiguratorSchema(context)
|
||||
skinName = config.skinName
|
||||
if not skinName:
|
||||
skinName = context.getLoopsRoot().skinName
|
||||
root = removeSecurityProxy(context.getLoopsRoot())
|
||||
skinName = root.skinName
|
||||
#skinName = context.getLoopsRoot().skinName
|
||||
if skinName:
|
||||
viewAnnotations['skinName'] = skinName
|
||||
if config.options:
|
||||
|
@ -1108,12 +1107,12 @@ def getViewConfiguration(context, request):
|
|||
class TestView(NodeView):
|
||||
|
||||
def __call__(self):
|
||||
print '*** begin'
|
||||
print( '*** begin')
|
||||
for i in range(500):
|
||||
#x = util.getObjectForUid('1994729849')
|
||||
x = util.getObjectForUid('2018653366')
|
||||
self.c = list(x.getChildren())
|
||||
#self.c = list(x.getChildren([self.defaultPredicate]))
|
||||
print '*** end', len(self.c)
|
||||
print('*** end', len(self.c))
|
||||
return 'done'
|
||||
|
Before Width: | Height: | Size: 942 B After Width: | Height: | Size: 942 B |
|
@ -267,19 +267,28 @@
|
|||
|
||||
|
||||
<metal:actions define-macro="view_modes">
|
||||
<div style="margin-bottom: 10px"
|
||||
tal:define="viewModes view/viewModes"
|
||||
tal:condition="viewModes">
|
||||
<ul class="view-modes">
|
||||
<li tal:repeat="mode viewModes"
|
||||
tal:attributes="class mode/cssClass">
|
||||
<a tal:attributes="href mode/url;
|
||||
title mode/description"
|
||||
tal:content="mode/title"
|
||||
i18n:translate="" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<ul class="view-modes"
|
||||
tal:define="viewModes view/viewModes"
|
||||
tal:condition="viewModes">
|
||||
<li tal:repeat="mode viewModes"
|
||||
tal:attributes="class mode/cssClass">
|
||||
<a tal:attributes="href mode/url;
|
||||
title mode/description"
|
||||
tal:content="mode/title"
|
||||
i18n:translate="" />
|
||||
<ul class="sub-view-modes"
|
||||
tal:define="subModes mode/subViewModes|nothing"
|
||||
tal:condition="subModes">
|
||||
<li tal:repeat="mode subModes"
|
||||
tal:attributes="class mode/cssClass">
|
||||
<a tal:attributes="href mode/url;
|
||||
title mode/description;"
|
||||
tal:content="mode/title"
|
||||
i18n:translate=""></a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</metal:actions>
|
||||
|
||||
|
||||
|
@ -335,8 +344,7 @@
|
|||
|
||||
|
||||
<metal:actions define-macro="personal">
|
||||
<div><a href="logout.html?nextURL=login.html"
|
||||
tal:attributes="href string:logout.html?nextURL=${view/menu/url}"
|
||||
<div><a tal:attributes="href view/logoutUrl"
|
||||
i18n:translate="">Log out</a></div>
|
||||
<tal:actions repeat="action python:view.getAllowedActions('personal')">
|
||||
<metal:action use-macro="action/macro" />
|
|
@ -18,10 +18,6 @@
|
|||
<a href="#"
|
||||
tal:attributes="href string:${target/url}/@@configure.html"
|
||||
tal:content="target/title">Document xy</a>
|
||||
<tal:xedit define="xeditObjectUrl target/url"
|
||||
condition="target/xeditable">
|
||||
<metal:xedit use-macro="views/xedit_macros/editLink" />
|
||||
</tal:xedit>
|
||||
</tal:target>
|
||||
</div>
|
||||
|
|
@ -52,7 +52,7 @@
|
|||
tal:attributes="value item/token" />
|
||||
</td>
|
||||
<td>
|
||||
<a tal:content="item/title"
|
||||
<a tal:content="item/title|string:???"
|
||||
tal:attributes="href string:${item/url}/@@SelectedManagementView.html">
|
||||
Title
|
||||
</a>
|
|
@ -1,36 +1,18 @@
|
|||
#
|
||||
# Copyright (c) 2015 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# loops.browser.resource
|
||||
|
||||
"""
|
||||
View class for resource objects.
|
||||
""" View class for resource objects.
|
||||
"""
|
||||
|
||||
import os.path
|
||||
import urllib
|
||||
from zope.authentication.interfaces import IUnauthenticatedPrincipal
|
||||
from zope.browserpage import ViewPageTemplateFile
|
||||
from zope.cachedescriptors.property import Lazy
|
||||
from zope import component
|
||||
from zope.app.catalog.interfaces import ICatalog
|
||||
from zope.app.container.interfaces import INameChooser
|
||||
from zope.app.form.browser.textwidgets import FileWidget
|
||||
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||
from zope.app.security.interfaces import IUnauthenticatedPrincipal
|
||||
from zope.catalog.interfaces import ICatalog
|
||||
from zope.container.interfaces import INameChooser
|
||||
from zope.formlib.form import FormFields
|
||||
from zope.formlib.interfaces import DISPLAY_UNWRITEABLE
|
||||
from zope.formlib.textwidgets import FileWidget
|
||||
from zope.proxy import removeAllProxies
|
||||
from zope.schema.interfaces import IBytes
|
||||
from zope.security import canAccess, canWrite
|
||||
|
@ -272,7 +254,7 @@ class ResourceView(BaseView):
|
|||
#wp = wiki.createPage(getName(self.context))
|
||||
wp = wiki.addPage(LoopsWikiPage(self.context))
|
||||
wp.text = text
|
||||
#print wp.wiki.getManager()
|
||||
#print(wp.wiki.getManager())
|
||||
#return util.toUnicode(wp.render(self.request))
|
||||
return super(ResourceView, self).renderText(text, contentType)
|
||||
|
||||
|
@ -467,7 +449,7 @@ class ExternalEditorView(ExternalEditorView, BaseView):
|
|||
r.append('meta_type:' + '.'.join((context.__module__, context.__class__.__name__)))
|
||||
auth = self.request.get('_auth')
|
||||
if auth:
|
||||
print 'ExternalEditorView: auth = ', auth
|
||||
print('ExternalEditorView: auth = ', auth)
|
||||
if auth.endswith('\n'):
|
||||
auth = auth[:-1]
|
||||
r.append('auth:' + auth)
|
|
@ -72,6 +72,7 @@
|
|||
<div>
|
||||
<span class="button">
|
||||
<a i18n:translate=""
|
||||
target="_blank"
|
||||
tal:attributes="href
|
||||
string:${view/virtualTargetUrl}/download.html?version=this">
|
||||
Download
|
||||
|
@ -130,4 +131,4 @@
|
|||
</metal:actions>
|
||||
|
||||
|
||||
</html>
|
||||
</html>
|
|
@ -25,6 +25,7 @@
|
|||
</div>
|
||||
|
||||
<div id="content" class="span-6"
|
||||
tal:attributes="class content_class|string:span-6"
|
||||
metal:define-macro="content">
|
||||
<metal:breadcrumbs define-slot="breadcrumbs">
|
||||
<metal:tabs use-macro="views/node_macros/breadcrumbs" />
|
||||
|
@ -37,7 +38,9 @@
|
|||
tal:condition="msg"
|
||||
tal:content="msg" />
|
||||
</metal:message>
|
||||
<metal:tabs use-macro="views/node_macros/view_modes" />
|
||||
<metal:tabs define-slot="view_modes">
|
||||
<metal:tabs use-macro="views/node_macros/view_modes" />
|
||||
</metal:tabs>
|
||||
<metal:content define-slot="content">
|
||||
<tal:content define="item nocall:view/item;
|
||||
level level|python: 1;
|
||||
|
@ -48,13 +51,18 @@
|
|||
</metal:content>
|
||||
</div>
|
||||
|
||||
<div id="portlets" class="span-2 last">
|
||||
<tal:portlet repeat="macro controller/macros/portlet_left">
|
||||
<metal:portlet use-macro="macro" />
|
||||
</tal:portlet>
|
||||
<tal:portlet repeat="macro controller/macros/portlet_right">
|
||||
<metal:portlet use-macro="macro" />
|
||||
</tal:portlet>
|
||||
<div id="portlets" class="span-2 last"
|
||||
tal:attributes="class portlets_class|string:span-2 last">
|
||||
<metal:portlet define-slot="portlet-left" >
|
||||
<tal:portlet repeat="macro controller/macros/portlet_left">
|
||||
<metal:portlet use-macro="macro" />
|
||||
</tal:portlet>
|
||||
</metal:portlet>
|
||||
<metal:portlet define-slot="portlet-right" >
|
||||
<tal:portlet repeat="macro controller/macros/portlet_right">
|
||||
<metal:portlet use-macro="macro" />
|
||||
</tal:portlet>
|
||||
</metal:portlet>
|
||||
</div>
|
||||
|
||||
<div id="footer" class="footer clear"
|