actions.py 7.63 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.selectors import (
10
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
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

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

    
147
class DeleteAction(Action):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
148
    id = 'delete'
149
    __selectors__ = (one_line_rset, has_permission('delete'))
150
    
Adrien Di Mascio's avatar
Adrien Di Mascio committed
151
    title = _('delete')
152
153
    category = 'moreactions' 
    order = 20
Adrien Di Mascio's avatar
Adrien Di Mascio committed
154
155
156
157
158
159
160
161
    
    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')
    
        
162
class CopyAction(Action):
Adrien Di Mascio's avatar
Adrien Di Mascio committed
163
    id = 'copy'
164
    __selectors__ = (one_line_rset, has_permission('add'))
165
    
Adrien Di Mascio's avatar
Adrien Di Mascio committed
166
    title = _('copy')
167
168
    category = 'moreactions'
    order = 30
Adrien Di Mascio's avatar
Adrien Di Mascio committed
169
170
171
172
173
174
175
176
177
178
    
    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
    """
179
    id = 'addentity'
180
181
182
183
184
185
186
    __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'
187
    order = 40
Adrien Di Mascio's avatar
Adrien Di Mascio committed
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
    
    @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)


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

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

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


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

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

228

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

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

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

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

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

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

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

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


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