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

zopefoundation / Zope / 3956162881

pending completion
3956162881

push

github

Michael Howitz
Update to deprecation warning free releases.

4401 of 7036 branches covered (62.55%)

Branch coverage included in aggregate %.

27161 of 31488 relevant lines covered (86.26%)

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 a
17
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
        """
54
        container = self.context
×
55
        name = self.contentName
×
56
        chooser = INameChooser(container)
×
57

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

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

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

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

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

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

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

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

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

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

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

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

119
        return factory
×
120

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

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

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

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

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

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

145
        notify(ObjectCreatedEvent(content))
×
146

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

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

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

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

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

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

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

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

194

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

197
    menu_id = "add_content"
1✔
198

199

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

205
    def __init__(self, context):
1✔
206
        self.context = context
1✔
207

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

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

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

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

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

240
        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