actions.py 7.58 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
10
11
12
13
14
15
16
17
from cubicweb.common.selectors import (
    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
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
def match_searched_etype(cls, req, rset, row=None, col=None, **kwargs):
    return req.match_search_state(rset)

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

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

46
# generic primary actions #####################################################
Adrien Di Mascio's avatar
Adrien Di Mascio committed
47

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


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


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


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

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

113
class MultipleEditAction(Action):
114
    id = 'muledit' # XXX get strange conflicts if id='edit'
115
116
117
118
    __selectors__ = (match_search_state('normal'),
                     two_lines_rset, one_etype_rset,
                     has_permission('update'))

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


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

129
class ManagePermissionsAction(Action):
130
    id = 'addpermission'
131
    __selectors__ = match_user_groups('managers') 
132

133
    title = _('manage permissions')
134
    category = 'moreactions'
135
    order = 100
136
137
138
139
140
141

    def registered(cls, vreg):
        if 'require_permission' in vreg.schema:
            cls.__selectors__ |= relation_possible('require_permission', 'subject', 'EPermission',
                                                   action='add')
            
142
143
    def url(self):
        return self.rset.get_entity(0, 0).absolute_url(vid='security')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
144
145

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

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


202
# logged user actions #########################################################
Adrien Di Mascio's avatar
Adrien Di Mascio committed
203
204
205

class UserPreferencesAction(Action):
    id = 'myprefs'
206
207
    __selectors__ = (authenticated_user,)
    
Adrien Di Mascio's avatar
Adrien Di Mascio committed
208
    title = _('user preferences')
209
210
    category = 'useractions'
    order = 10
Adrien Di Mascio's avatar
Adrien Di Mascio committed
211
212
213
214
215
216
217

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


class UserInfoAction(Action):
    id = 'myinfos'
218
219
    __selectors__ = (authenticated_user,)
    
Adrien Di Mascio's avatar
Adrien Di Mascio committed
220
    title = _('personnal informations')
221
222
    category = 'useractions'
    order = 20
Adrien Di Mascio's avatar
Adrien Di Mascio committed
223
224
225
226

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

227

Adrien Di Mascio's avatar
Adrien Di Mascio committed
228
229
class LogoutAction(Action):
    id = 'logout'
230
231
    __selectors__ = (authenticated_user,)
    
Adrien Di Mascio's avatar
Adrien Di Mascio committed
232
    title = _('logout')
233
234
    category = 'useractions'
    order = 30
Adrien Di Mascio's avatar
Adrien Di Mascio committed
235
236
237

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

Adrien Di Mascio's avatar
Adrien Di Mascio committed
239
    
240
# site actions ################################################################
Adrien Di Mascio's avatar
Adrien Di Mascio committed
241
242
243

class ManagersAction(Action):
    __abstract__ = True
244
245
246
    __selectors__ = (match_user_groups('managers'),)

    category = 'siteactions'
Adrien Di Mascio's avatar
Adrien Di Mascio committed
247
248
249

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

Adrien Di Mascio's avatar
Adrien Di Mascio committed
251
252
253
254
    
class SiteConfigurationAction(ManagersAction):
    id = 'siteconfig'
    title = _('site configuration')
255
    order = 10
256

Adrien Di Mascio's avatar
Adrien Di Mascio committed
257
258
259
260
    
class ManageAction(ManagersAction):
    id = 'manage'
    title = _('manage')
261
    order = 20
Adrien Di Mascio's avatar
Adrien Di Mascio committed
262
263
264


class ViewSchemaAction(Action):
265
    id = 'schema'
266
267
    __selectors__ = (yes,)
    
268
    title = _("site schema")
269
    category = 'siteactions'
Adrien Di Mascio's avatar
Adrien Di Mascio committed
270
271
272
273
    order = 30
    
    def url(self):
        return self.build_url(self.id)