• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

zopefoundation / Zope / 6263629025

21 Sep 2023 03:12PM UTC coverage: 82.146% (-0.01%) from 82.159%
6263629025

Pull #1164

github

web-flow
[pre-commit.ci lite] apply automatic fixes
Pull Request #1164: Move all linters to pre-commit.

4353 of 6963 branches covered (0.0%)

Branch coverage included in aggregate %.

487 of 487 new or added lines in 186 files covered. (100.0%)

27394 of 31684 relevant lines covered (86.46%)

0.86 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

37.37
/src/Products/Five/browser/adding.py
1
##############################################################################
2
#
3
# Copyright (c) 2002-2005 Zope Foundation and Contributors.
4
# All Rights Reserved.
5
#
6
# This software is subject to the provisions of the Zope Public License,
7
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
8
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
9
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
11
# FOR A PARTICULAR PURPOSE.
12
#
13
##############################################################################
14
"""Adding View.
1✔
15

16
The Adding View is used to add new objects to a container. It is sort of
17
a factory screen.
18

19
(original: zope.app.container.browser.adding)
20
"""
21

22
import operator
1✔
23

24
from OFS.SimpleItem import SimpleItem
1✔
25
from Products.Five import BrowserView
1✔
26
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
1✔
27
from zExceptions import BadRequest
1✔
28
from zope.browser.interfaces import IAdding
1✔
29
from zope.browsermenu.menu import getMenu
1✔
30
from zope.component import getMultiAdapter
1✔
31
from zope.component import getUtility
1✔
32
from zope.component import queryMultiAdapter
1✔
33
from zope.component import queryUtility
1✔
34
from zope.component.interfaces import IFactory
1✔
35
from zope.container.constraints import checkFactory
1✔
36
from zope.container.constraints import checkObject
1✔
37
from zope.container.i18n import ZopeMessageFactory as _
1✔
38
from zope.container.interfaces import IContainerNamesContainer
1✔
39
from zope.container.interfaces import INameChooser
1✔
40
from zope.event import notify
1✔
41
from zope.exceptions.interfaces import UserError
1✔
42
from zope.interface import implementer
1✔
43
from zope.lifecycleevent import ObjectCreatedEvent
1✔
44
from zope.publisher.interfaces import IPublishTraverse
1✔
45
from zope.traversing.browser.absoluteurl import absoluteURL
1✔
46

47

48
@implementer(IAdding, IPublishTraverse)
1✔
49
class Adding(BrowserView):
1✔
50

51
    def add(self, content):
1✔
52
        """See zope.browser.interfaces.IAdding."""
53
        container = self.context
×
54
        name = self.contentName
×
55
        chooser = INameChooser(container)
×
56

57
        # check precondition
58
        checkObject(container, name, content)
×
59

60
        if IContainerNamesContainer.providedBy(container):
×
61
            # The container picks its own names.
62
            # We need to ask it to pick one.
63
            name = chooser.chooseName(self.contentName or '', content)
×
64
        else:
65
            request = self.request
×
66
            name = request.get('add_input_name', name)
×
67

68
            if name is None:
×
69
                name = chooser.chooseName(self.contentName or '', content)
×
70
            elif name == '':
×
71
                name = chooser.chooseName('', content)
×
72
            else:
73
                # Invoke the name chooser even when we have a
74
                # name. It'll do useful things with it like converting
75
                # the incoming unicode to an ASCII string.
76
                name = chooser.chooseName(name, content)
×
77

78
        content.id = name
×
79
        container._setObject(name, content)
×
80
        self.contentName = name  # Set the added object Name
×
81
        return container._getOb(name)
×
82

83
    contentName = None  # usually set by Adding traverser
1✔
84

85
    def nextURL(self):
1✔
86
        """See zope.browser.interfaces.IAdding."""
87
        # XXX this is definitely not right for all or even most uses
88
        # of Five, but can be overridden by an AddView subclass
89
        return absoluteURL(self.context, self.request) + '/manage_main'
×
90

91
    # set in BrowserView.__init__
92
    request = None
1✔
93
    context = None
1✔
94

95
    def publishTraverse(self, request, name):
1✔
96
        """See zope.publisher.interfaces.IPublishTraverse."""
97
        if '=' in name:
×
98
            view_name, content_name = name.split("=", 1)
×
99
            self.contentName = content_name
×
100

101
            if view_name.startswith('@@'):
×
102
                view_name = view_name[2:]
×
103
            return getMultiAdapter((self, request), name=view_name)
×
104

105
        if name.startswith('@@'):
×
106
            view_name = name[2:]
×
107
        else:
108
            view_name = name
×
109

110
        view = queryMultiAdapter((self, request), name=view_name)
×
111
        if view is not None:
×
112
            return view
×
113

114
        factory = queryUtility(IFactory, name)
×
115
        if factory is None:
×
116
            return super().publishTraverse(request, name)
×
117

118
        return factory
×
119

120
    def action(self, type_name='', id=''):
1✔
121
        if not type_name:
×
122
            raise UserError(_("You must select the type of object to add."))
×
123

124
        if type_name.startswith('@@'):
×
125
            type_name = type_name[2:]
×
126

127
        if '/' in type_name:
×
128
            view_name = type_name.split('/', 1)[0]
×
129
        else:
130
            view_name = type_name
×
131

132
        if queryMultiAdapter((self, self.request),
×
133
                             name=view_name) is not None:
134
            url = f"{absoluteURL(self, self.request)}/{type_name}={id}"
×
135
            self.request.response.redirect(url)
×
136
            return
×
137

138
        if not self.contentName:
×
139
            self.contentName = id
×
140

141
        factory = getUtility(IFactory, type_name)
×
142
        content = factory()
×
143

144
        notify(ObjectCreatedEvent(content))
×
145

146
        self.add(content)
×
147
        self.request.response.redirect(self.nextURL())
×
148

149
    def nameAllowed(self):
1✔
150
        """Return whether names can be input by the user."""
151
        return not IContainerNamesContainer.providedBy(self.context)
×
152

153
    menu_id = None
1✔
154
    index = ViewPageTemplateFile("adding.pt")
1✔
155

156
    def addingInfo(self):
1✔
157
        """Return menu data.
158

159
        This is sorted by title.
160
        """
161
        container = self.context
×
162
        result = []
×
163
        for menu_id in (self.menu_id, 'zope.app.container.add'):
×
164
            if not menu_id:
×
165
                continue
×
166
            for item in getMenu(menu_id, self, self.request):
×
167
                extra = item.get('extra')
×
168
                if extra:
×
169
                    factory = extra.get('factory')
×
170
                    if factory:
×
171
                        factory = getUtility(IFactory, factory)
×
172
                        if not checkFactory(container, None, factory):
×
173
                            continue
×
174
                        elif item['extra']['factory'] != item['action']:
×
175
                            item['has_custom_add_view'] = True
×
176
                result.append(item)
×
177

178
        result.sort(key=operator.itemgetter('title'))
×
179
        return result
×
180

181
    def isSingleMenuItem(self):
1✔
182
        "Return whether there is single menu item or not."
183
        return len(self.addingInfo()) == 1
×
184

185
    def hasCustomAddView(self):
1✔
186
        "This should be called only if there is `singleMenuItem` else return 0"
187
        if self.isSingleMenuItem():
×
188
            menu_item = self.addingInfo()[0]
×
189
            if 'has_custom_add_view' in menu_item:
×
190
                return True
×
191
        return False
×
192

193

194
class ContentAdding(Adding, SimpleItem):
1✔
195

196
    menu_id = "add_content"
1✔
197

198

199
@implementer(INameChooser)
1✔
200
class ObjectManagerNameChooser:
1✔
201
    """A name chooser for a Zope object manager."""
202

203
    def __init__(self, context):
1✔
204
        self.context = context
1✔
205

206
    def checkName(self, name, object):
1✔
207
        try:
1✔
208
            self.context._checkId(name, allow_dup=False)
1✔
209
        except BadRequest as e:
1✔
210
            msg = ' '.join(e.args) or "Id is in use or invalid"
1✔
211
            raise UserError(msg)
1✔
212

213
    def chooseName(self, name, object):
1✔
214
        if not name:
1✔
215
            name = object.__class__.__name__
1✔
216

217
        dot = name.rfind('.')
1✔
218
        if dot >= 0:
1!
219
            suffix = name[dot:]
×
220
            name = name[:dot]
×
221
        else:
222
            suffix = ''
1✔
223

224
        n = name + suffix
1✔
225
        i = 0
1✔
226
        while True:
227
            i += 1
1✔
228
            try:
1✔
229
                self.context._getOb(n)
1✔
230
            except (AttributeError, KeyError):
1✔
231
                break
1✔
232
            n = name + '-' + str(i) + suffix
1✔
233

234
        # Make sure the name is valid.  We may have started with
235
        # something bad.
236
        self.checkName(n, object)
1✔
237

238
        return n
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc