actions.py 7.65 KB
Newer Older
Adrien Di Mascio's avatar
Adrien Di Mascio committed
1
2
3
"""Set of HTML base actions

:organization: Logilab
4
:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
Adrien Di Mascio's avatar
Adrien Di Mascio committed
5
6
7
8
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
"""
__docformat__ = "restructuredtext en"

9
from cubicweb.vregistry import objectify_selector
10
from cubicweb.selectors import (
11
12
13
14
15
16
17
18
    yes, one_line_rset, two_lines_rset, one_etype_rset, relation_possible,
    non_final_entity,
    authenticated_user, match_user_groups, match_search_state,
    has_editable_relation, has_permission, has_add_permission,
    )

from cubicweb.web.action import Action
from cubicweb.web.views import linksearch_select_url
Adrien Di Mascio's avatar
Adrien Di Mascio committed
19
20
21
22
from cubicweb.web.views.baseviews import vid_from_rset

_ = unicode

23
@objectify_selector
24
25
26
def match_searched_etype(cls, req, rset, row=None, col=None, **kwargs):
    return req.match_search_state(rset)

27
@objectify_selector
28
29
30
31
32
33
34
def view_is_not_default_view(cls, req, rset, row, col, **kwargs):
    # interesting if it propose another view than the current one
    vid = req.form.get('vid')
    if vid and vid != vid_from_rset(req, rset, cls.schema):
        return 1
    return 0

35
@objectify_selector
36
37
38
39
40
41
42
43
44
45
46
47
48
49
def addable_etype_empty_rset(cls, req, rset, **kwargs):
    if rset is not None and not rset.rowcount:
        rqlst = rset.syntax_tree()
        if len(rqlst.children) > 1:
            return 0
        select = rqlst.children[0]
        if len(select.defined_vars) == 1 and len(select.solutions) == 1:
            rset._searched_etype = select.solutions[0].itervalues().next()
            eschema = cls.schema.eschema(rset._searched_etype)
            if not (eschema.is_final() or eschema.is_subobject(strict=True)) \
                   and eschema.has_perm(req, 'add'):
                return 1
    return 0

50
# generic primary actions #####################################################
Adrien Di Mascio's avatar
Adrien Di Mascio committed
51

52
class SelectAction(Action):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
53
54
55
56
57
    """base class for link search actions. By default apply on
    any size entity result search it the current state is 'linksearch'
    if accept match.
    """
    id = 'select'
58
    __select__ = match_search_state('linksearch') & match_searched_etype()
Adrien Di Mascio's avatar
Adrien Di Mascio committed
59
    
60
61
62
    title = _('select')
    category = 'mainactions'    
    order = 0
Adrien Di Mascio's avatar
Adrien Di Mascio committed
63
64
65
66
67
68
69
    
    def url(self):
        return linksearch_select_url(self.req, self.rset)


class CancelSelectAction(Action):
    id = 'cancel'
70
    __select__ = match_search_state('linksearch')
71
    
Adrien Di Mascio's avatar
Adrien Di Mascio committed
72
    title = _('cancel select')
73
74
    category = 'mainactions'
    order = 10
Adrien Di Mascio's avatar
Adrien Di Mascio committed
75
76
    
    def url(self):
77
78
        target, eid, r_type, searched_type = self.req.search_state[1]
        return self.build_url(str(eid),
Adrien Di Mascio's avatar
Adrien Di Mascio committed
79
80
81
82
83
                              vid='edition', __mode='normal')


class ViewAction(Action):
    id = 'view'
84
85
86
87
    __select__ = (match_search_state('normal') &
                  match_user_groups('users', 'managers') &
                  view_is_not_default_view() & 
                  non_final_entity())
Adrien Di Mascio's avatar
Adrien Di Mascio committed
88
    
89
90
91
    title = _('view')
    category = 'mainactions'    
    order = 0
Adrien Di Mascio's avatar
Adrien Di Mascio committed
92
93
94
95
96
    
    def url(self):
        params = self.req.form.copy()
        params.pop('vid', None)
        params.pop('__message', None)
97
98
        return self.build_url(self.req.relative_path(includeparams=False),
                              **params)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
99
100


101
class ModifyAction(Action):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
102
    id = 'edit'
103
104
105
    __select__ = (match_search_state('normal') &
                  one_line_rset() & 
                  (has_permission('update') | has_editable_relation('add')))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
106
    
107
108
109
    title = _('modify')
    category = 'mainactions'
    order = 10
Adrien Di Mascio's avatar
Adrien Di Mascio committed
110
111
112
113

    def url(self):
        entity = self.rset.get_entity(self.row or 0, self.col or 0)
        return entity.absolute_url(vid='edition')
114
115
        

116
class MultipleEditAction(Action):
117
    id = 'muledit' # XXX get strange conflicts if id='edit'
118
    __select__ = (match_search_state('normal') &
119
                  two_lines_rset() & one_etype_rset() &
120
                  has_permission('update'))
121

122
    title = _('modify')
123
124
    category = 'mainactions'
    order = 10
125
126
127
128
129
130
131
    
    def url(self):
        return self.build_url('view', rql=self.rset.rql, vid='muledit')


# generic secondary actions ###################################################

132
class ManagePermissionsAction(Action):
133
    id = 'addpermission'
134
    __select__ = match_user_groups('managers') 
135

136
    title = _('manage permissions')
137
    category = 'moreactions'
138
    order = 100
139

140
    @classmethod
141
    def registered(cls, vreg):
142
        super(ManagePermissionsAction, cls).registered(vreg)
143
        if 'require_permission' in vreg.schema:
144
145
146
147
            cls.__select__ |= relation_possible('require_permission', 'subject', 'EPermission',
                                                action='add')
        return super(ManagePermissionsAction, cls).registered(vreg)
    
148
149
    def url(self):
        return self.rset.get_entity(0, 0).absolute_url(vid='security')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
150
151

    
152
class DeleteAction(Action):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
153
    id = 'delete'
154
    __select__ = one_line_rset() & has_permission('delete')
155
    
Adrien Di Mascio's avatar
Adrien Di Mascio committed
156
    title = _('delete')
157
158
    category = 'moreactions' 
    order = 20
Adrien Di Mascio's avatar
Adrien Di Mascio committed
159
160
161
162
163
164
165
166
    
    def url(self):
        if len(self.rset) == 1:
            entity = self.rset.get_entity(0, 0)
            return self.build_url(entity.rest_path(), vid='deleteconf')
        return self.build_url(rql=self.rset.printable_rql(), vid='deleteconf')
    
        
167
class CopyAction(Action):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
168
    id = 'copy'
169
    __select__ = one_line_rset() & has_permission('add')
170
    
Adrien Di Mascio's avatar
Adrien Di Mascio committed
171
    title = _('copy')
172
173
    category = 'moreactions'
    order = 30
Adrien Di Mascio's avatar
Adrien Di Mascio committed
174
175
176
177
178
179
180
181
182
183
    
    def url(self):
        entity = self.rset.get_entity(self.row or 0, self.col or 0)
        return entity.absolute_url(vid='copy')


class AddNewAction(MultipleEditAction):
    """when we're seeing more than one entity with the same type, propose to
    add a new one
    """
184
    id = 'addentity'
185
186
    __select__ = (match_search_state('normal') &
                  (addable_etype_empty_rset()
187
                   | (two_lines_rset() & one_etype_rset & has_add_permission()))
188
                  )
189
190

    category = 'moreactions'
191
    order = 40
Adrien Di Mascio's avatar
Adrien Di Mascio committed
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
    
    @property
    def rsettype(self):
        if self.rset:
            return self.rset.description[0][0]
        return self.rset._searched_etype

    @property
    def title(self):
        return self.req.__('add a %s' % self.rsettype) # generated msgid

    def url(self):
        return self.build_url('add/%s' % self.rsettype)


207
# logged user actions #########################################################
Adrien Di Mascio's avatar
Adrien Di Mascio committed
208
209
210

class UserPreferencesAction(Action):
    id = 'myprefs'
211
    __select__ = authenticated_user()
212
    
Adrien Di Mascio's avatar
Adrien Di Mascio committed
213
    title = _('user preferences')
214
215
    category = 'useractions'
    order = 10
Adrien Di Mascio's avatar
Adrien Di Mascio committed
216
217
218
219
220
221
222

    def url(self):
        return self.build_url(self.id)


class UserInfoAction(Action):
    id = 'myinfos'
223
    __select__ = authenticated_user()
224
    
Adrien Di Mascio's avatar
Adrien Di Mascio committed
225
    title = _('personnal informations')
226
227
    category = 'useractions'
    order = 20
Adrien Di Mascio's avatar
Adrien Di Mascio committed
228
229
230
231

    def url(self):
        return self.build_url('euser/%s'%self.req.user.login, vid='edition')

232

Adrien Di Mascio's avatar
Adrien Di Mascio committed
233
234
class LogoutAction(Action):
    id = 'logout'
235
    __select__ = authenticated_user()
236
    
Adrien Di Mascio's avatar
Adrien Di Mascio committed
237
    title = _('logout')
238
239
    category = 'useractions'
    order = 30
Adrien Di Mascio's avatar
Adrien Di Mascio committed
240
241
242

    def url(self):
        return self.build_url(self.id)
243

Adrien Di Mascio's avatar
Adrien Di Mascio committed
244
    
245
# site actions ################################################################
Adrien Di Mascio's avatar
Adrien Di Mascio committed
246
247
248

class ManagersAction(Action):
    __abstract__ = True
249
    __select__ = match_user_groups('managers')
250
251

    category = 'siteactions'
Adrien Di Mascio's avatar
Adrien Di Mascio committed
252
253
254

    def url(self):
        return self.build_url(self.id)
255

Adrien Di Mascio's avatar
Adrien Di Mascio committed
256
257
258
259
    
class SiteConfigurationAction(ManagersAction):
    id = 'siteconfig'
    title = _('site configuration')
260
    order = 10
261

Adrien Di Mascio's avatar
Adrien Di Mascio committed
262
263
264
265
    
class ManageAction(ManagersAction):
    id = 'manage'
    title = _('manage')
266
    order = 20
Adrien Di Mascio's avatar
Adrien Di Mascio committed
267
268
269


class ViewSchemaAction(Action):
270
    id = 'schema'
271
    __select__ = yes()
272
    
273
    title = _("site schema")
274
    category = 'siteactions'
Adrien Di Mascio's avatar
Adrien Di Mascio committed
275
276
277
278
    order = 30
    
    def url(self):
        return self.build_url(self.id)