actions.py 7.62 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
    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
18
19
20
21
from cubicweb.web.views.baseviews import vid_from_rset

_ = unicode

22
@objectify_selector
23
def match_searched_etype(cls, req, rset, **kwargs):
24
25
    return req.match_search_state(rset)

26
@objectify_selector
27
def view_is_not_default_view(cls, req, rset, **kwargs):
28
29
30
31
32
33
    # 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

34
@objectify_selector
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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

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

51
class SelectAction(Action):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
52
53
54
55
56
    """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'
57
    __select__ = match_search_state('linksearch') & match_searched_etype()
Adrien Di Mascio's avatar
Adrien Di Mascio committed
58
    
59
60
61
    title = _('select')
    category = 'mainactions'    
    order = 0
Adrien Di Mascio's avatar
Adrien Di Mascio committed
62
63
64
65
66
67
68
    
    def url(self):
        return linksearch_select_url(self.req, self.rset)


class CancelSelectAction(Action):
    id = 'cancel'
69
    __select__ = match_search_state('linksearch')
70
    
Adrien Di Mascio's avatar
Adrien Di Mascio committed
71
    title = _('cancel select')
72
73
    category = 'mainactions'
    order = 10
Adrien Di Mascio's avatar
Adrien Di Mascio committed
74
75
    
    def url(self):
76
77
        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
78
79
80
81
82
                              vid='edition', __mode='normal')


class ViewAction(Action):
    id = 'view'
83
84
85
86
    __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
87
    
88
89
90
    title = _('view')
    category = 'mainactions'    
    order = 0
Adrien Di Mascio's avatar
Adrien Di Mascio committed
91
92
93
94
95
    
    def url(self):
        params = self.req.form.copy()
        params.pop('vid', None)
        params.pop('__message', None)
96
97
        return self.build_url(self.req.relative_path(includeparams=False),
                              **params)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
98
99


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

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

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

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


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

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

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

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

    
151
class DeleteAction(Action):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
152
    id = 'delete'
153
    __select__ = one_line_rset() & has_permission('delete')
154
    
Adrien Di Mascio's avatar
Adrien Di Mascio committed
155
    title = _('delete')
156
157
    category = 'moreactions' 
    order = 20
Adrien Di Mascio's avatar
Adrien Di Mascio committed
158
159
160
161
162
163
164
165
    
    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')
    
        
166
class CopyAction(Action):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
167
    id = 'copy'
168
    __select__ = one_line_rset() & has_permission('add')
169
    
Adrien Di Mascio's avatar
Adrien Di Mascio committed
170
    title = _('copy')
171
172
    category = 'moreactions'
    order = 30
Adrien Di Mascio's avatar
Adrien Di Mascio committed
173
174
175
176
177
178
179
180
181
182
    
    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
    """
183
    id = 'addentity'
184
185
    __select__ = (match_search_state('normal') &
                  (addable_etype_empty_rset()
186
                   | (two_lines_rset() & one_etype_rset & has_add_permission()))
187
                  )
188
189

    category = 'moreactions'
190
    order = 40
Adrien Di Mascio's avatar
Adrien Di Mascio committed
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
    
    @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)


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

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

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


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

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

231

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

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

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

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

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

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

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

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


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