Projet

Général

Profil

0001-misc-remove-custom-myspace-page-72820.patch

Frédéric Péters, 29 décembre 2022 10:11

Télécharger (15,4 ko)

Voir les différences:

Subject: [PATCH] misc: remove custom myspace page (#72820)

 auquotidien/modules/myspace.py | 321 ---------------------------------
 auquotidien/modules/root.py    |   3 -
 tests/test_user_pages.py       |  55 ------
 3 files changed, 379 deletions(-)
 delete mode 100644 auquotidien/modules/myspace.py
auquotidien/modules/myspace.py
1
try:
2
    import lasso
3
except ImportError:
4
    pass
5

  
6
import json
7
import time
8

  
9
from quixote import get_publisher, get_request, redirect, get_response, get_session_manager, get_session
10
from quixote.directory import AccessControlled, Directory
11
from quixote.html import TemplateIO, htmltext
12
from quixote.util import StaticFile, FileStream
13

  
14
from wcs.qommon import _, N_
15
from wcs.qommon import template
16
from wcs.qommon.form import *
17
from wcs.qommon import get_cfg, get_logger
18
from wcs.qommon import errors
19
from wcs.api import get_user_from_api_query_string
20

  
21
import wcs.qommon.ident.password
22
from wcs.qommon.ident.password_accounts import PasswordAccount
23

  
24
from wcs.qommon.admin.texts import TextsDirectory
25

  
26
from wcs.formdef import FormDef
27
import wcs.myspace
28

  
29

  
30
class JsonDirectory(Directory):
31
    """Export of several lists in json, related to the current user or the
32
    SAMLv2 NameID we'd get in the URL"""
33

  
34
    _q_exports = ['forms']
35

  
36
    user = None
37

  
38
    def _q_traverse(self, path):
39
        self.user = get_user_from_api_query_string() or get_request().user
40
        if not self.user:
41
            raise errors.AccessUnauthorizedError()
42
        return Directory._q_traverse(self, path)
43

  
44
    def forms(self):
45
        formdefs = FormDef.select(order_by='name', ignore_errors=True)
46
        user_forms = []
47
        for formdef in formdefs:
48
            user_forms.extend(formdef.data_class().get_with_indexed_value('user_id', self.user.id))
49
        epoch = time.localtime(1970)
50
        user_forms.sort(key=lambda x: x.receipt_time or epoch)
51

  
52
        get_response().set_content_type('application/json')
53

  
54
        forms_output = []
55
        for form in user_forms:
56
            visible_status = form.get_visible_status(user=self.user)
57
            # skip drafts and hidden forms
58
            if not visible_status:
59
                continue
60
            name = form.formdef.name
61
            id = form.get_display_id()
62
            status = visible_status.name
63
            title = _('%(name)s #%(id)s (%(status)s)') % {'name': name, 'id': id, 'status': status}
64
            url = form.get_url()
65
            d = {'title': title, 'url': url}
66
            d.update(form.get_substitution_variables(minimal=True))
67
            forms_output.append(d)
68
        return json.dumps(forms_output, cls=misc.JSONEncoder)
69

  
70

  
71
class MyspaceDirectory(wcs.myspace.MyspaceDirectory):
72
    _q_exports = ['', 'profile', 'new', 'password', 'remove', 'drafts', 'forms', 'json']
73

  
74
    json = JsonDirectory()
75

  
76
    def _q_traverse(self, path):
77
        get_response().breadcrumb.append(('myspace/', _('My Space')))
78

  
79
        # Migrate custom text settings
80
        texts_cfg = get_cfg('texts', {})
81
        if 'text-aq-top-of-profile' in texts_cfg and (not 'text-top-of-profile' in texts_cfg):
82
            texts_cfg['text-top-of-profile'] = texts_cfg['text-aq-top-of-profile']
83
            del texts_cfg['text-aq-top-of-profile']
84
            get_publisher().write_cfg()
85

  
86
        return Directory._q_traverse(self, path)
87

  
88
    def _q_index(self):
89
        user = get_request().user
90
        if not user:
91
            raise errors.AccessUnauthorizedError()
92
        template.html_top(_('My Space'))
93
        r = TemplateIO(html=True)
94
        if user.anonymous:
95
            return redirect('new')
96

  
97
        user_formdef = user.get_formdef()
98

  
99
        user_forms = []
100
        if user:
101
            formdefs = FormDef.select(order_by='name', ignore_errors=True)
102
            user_forms = []
103
            for formdef in formdefs:
104
                user_forms.extend(formdef.data_class().get_with_indexed_value('user_id', user.id))
105
            epoch = time.localtime(1970)
106
            user_forms.sort(key=lambda x: x.receipt_time or epoch)
107

  
108
        profile_links = []
109
        if not get_cfg('sp', {}).get('idp-manage-user-attributes', False):
110
            if user_formdef:
111
                profile_links.append('<a href="#my-profile">%s</a>' % _('My Profile'))
112
        if user_forms:
113
            profile_links.append('<a href="#my-forms">%s</a>' % _('My Forms'))
114

  
115
        root_url = get_publisher().get_root_url()
116
        if user.can_go_in_backoffice():
117
            profile_links.append('<a href="%sbackoffice/">%s</a>' % (root_url, _('Back office')))
118
        if user.is_admin:
119
            profile_links.append('<a href="%sadmin/">%s</a>' % (root_url, _('Admin')))
120

  
121
        if profile_links:
122
            r += htmltext('<p id="profile-links">')
123
            r += htmltext(' - '.join(profile_links))
124
            r += htmltext('</p>')
125

  
126
        if not get_cfg('sp', {}).get('idp-manage-user-attributes', False):
127
            if user_formdef:
128
                r += self._my_profile(user_formdef, user)
129

  
130
            r += self._index_buttons(user_formdef)
131

  
132
            try:
133
                x = PasswordAccount.get_on_index(get_request().user.id, str('user_id'))
134
            except KeyError:
135
                pass
136
            else:
137
                r += htmltext('<p>')
138
                r += _(
139
                    'You can delete your account freely from the services portal. '
140
                    'This action is irreversible; it will destruct your personal '
141
                    'datas and destruct the access to your request history.'
142
                )
143
                r += htmltext(' <strong><a href="remove" rel="popup">%s</a></strong>.') % _(
144
                    'Delete My Account'
145
                )
146
                r += htmltext('</p>')
147

  
148
        if user_forms:
149
            r += htmltext('<h3 id="my-forms">%s</h3>') % _('My Forms')
150
            from . import root
151

  
152
            r += root.FormsRootDirectory().user_forms(user_forms)
153

  
154
        return r.getvalue()
155

  
156
    def _my_profile(self, user_formdef, user):
157
        r = TemplateIO(html=True)
158
        r += htmltext('<h3 id="my-profile">%s</h3>') % _('My Profile')
159

  
160
        r += TextsDirectory.get_html_text('top-of-profile')
161

  
162
        if user.form_data:
163
            r += htmltext('<ul>')
164
            for field in user_formdef.fields:
165
                if not hasattr(field, str('get_view_value')):
166
                    continue
167
                value = user.form_data.get(field.id)
168
                r += htmltext('<li>')
169
                r += field.label
170
                r += ' : '
171
                if value:
172
                    r += field.get_view_value(value)
173
                r += htmltext('</li>')
174
            r += htmltext('</ul>')
175
        else:
176
            r += htmltext('<p>%s</p>') % _('Empty profile')
177
        return r.getvalue()
178

  
179
    def _index_buttons(self, form_data):
180
        r = TemplateIO(html=True)
181
        passwords_cfg = get_cfg('passwords', {})
182
        ident_method = get_cfg('identification', {}).get('methods', ['idp'])[0]
183
        if get_session().lasso_session_dump:
184
            ident_method = 'idp'
185

  
186
        if form_data and ident_method != 'idp':
187
            r += htmltext('<p class="command"><a href="profile" rel="popup">%s</a></p>') % _(
188
                'Edit My Profile'
189
            )
190

  
191
        if ident_method == 'password' and passwords_cfg.get('can_change', False):
192
            r += htmltext('<p class="command"><a href="password" rel="popup">%s</a></p>') % _(
193
                'Change My Password'
194
            )
195

  
196
        return r.getvalue()
197

  
198
    def profile(self):
199
        user = get_request().user
200
        if not user or user.anonymous:
201
            raise errors.AccessUnauthorizedError()
202

  
203
        form = Form(enctype='multipart/form-data')
204
        formdef = user.get_formdef()
205
        formdef.add_fields_to_form(form, form_data=user.form_data)
206

  
207
        form.add_submit('submit', _('Apply Changes'))
208
        form.add_submit('cancel', _('Cancel'))
209

  
210
        if form.get_submit() == 'cancel':
211
            return redirect('.')
212

  
213
        if form.is_submitted() and not form.has_errors():
214
            self.profile_submit(form, formdef)
215
            return redirect('.')
216

  
217
        template.html_top(_('Edit Profile'))
218
        return form.render()
219

  
220
    def profile_submit(self, form, formdef):
221
        user = get_request().user
222
        data = formdef.get_data(form)
223

  
224
        user.set_attributes_from_formdata(data)
225
        user.form_data = data
226

  
227
        user.store()
228

  
229
    def password(self):
230
        ident_method = get_cfg('identification', {}).get('methods', ['idp'])[0]
231
        if ident_method != 'password':
232
            raise errors.TraversalError()
233

  
234
        user = get_request().user
235
        if not user or user.anonymous:
236
            raise errors.AccessUnauthorizedError()
237

  
238
        form = Form(enctype='multipart/form-data')
239
        form.add(PasswordWidget, 'new_password', title=_('New Password'), required=True)
240
        form.add(PasswordWidget, 'new2_password', title=_('New Password (confirm)'), required=True)
241

  
242
        form.add_submit('submit', _('Change Password'))
243
        form.add_submit('cancel', _('Cancel'))
244

  
245
        if form.get_submit() == 'cancel':
246
            return redirect('.')
247

  
248
        if form.is_submitted() and not form.has_errors():
249
            wcs.qommon.ident.password.check_password(form, 'new_password')
250
            new_password = form.get_widget('new_password').parse()
251
            new2_password = form.get_widget('new2_password').parse()
252
            if new_password != new2_password:
253
                form.set_error('new2_password', _('Passwords do not match'))
254

  
255
        if form.is_submitted() and not form.has_errors():
256
            self.submit_password(new_password)
257
            return redirect('.')
258

  
259
        template.html_top(_('Change Password'))
260
        return form.render()
261

  
262
    def submit_password(self, new_password):
263
        passwords_cfg = get_cfg('passwords', {})
264
        account = PasswordAccount.get(get_session().username)
265
        account.hashing_algo = passwords_cfg.get('hashing_algo')
266
        account.set_password(new_password)
267
        account.store()
268

  
269
    def new(self):
270
        if not get_request().user or not get_request().user.anonymous:
271
            raise errors.AccessUnauthorizedError()
272

  
273
        form = Form(enctype='multipart/form-data')
274
        formdef = get_publisher().user_class.get_formdef()
275
        if formdef:
276
            formdef.add_fields_to_form(form)
277
        else:
278
            get_logger().error('missing user formdef (in myspace/new)')
279

  
280
        form.add_submit('submit', _('Register'))
281

  
282
        if form.is_submitted() and not form.has_errors():
283
            user = get_publisher().user_class()
284
            data = formdef.get_data(form)
285
            user.set_attributes_from_formdata(data)
286
            user.name_identifiers = get_request().user.name_identifiers
287
            user.lasso_dump = get_request().user.lasso_dump
288
            user.set_attributes_from_formdata(data)
289
            user.form_data = data
290
            user.store()
291
            get_session().set_user(user.id)
292
            root_url = get_publisher().get_root_url()
293
            return redirect('%smyspace' % root_url)
294

  
295
        template.html_top(_('Welcome'))
296
        return form.render()
297

  
298
    def remove(self):
299
        user = get_request().user
300
        if not user or user.anonymous:
301
            raise errors.AccessUnauthorizedError()
302

  
303
        form = Form(enctype='multipart/form-data')
304
        form.widgets.append(
305
            HtmlWidget('<p>%s</p>' % _('Are you really sure you want to remove your account?'))
306
        )
307
        form.add_submit('submit', _('Remove my account'))
308
        form.add_submit('cancel', _('Cancel'))
309

  
310
        if form.get_submit() == 'cancel':
311
            return redirect('.')
312

  
313
        if form.is_submitted() and not form.has_errors():
314
            user = get_request().user
315
            account = PasswordAccount.get_on_index(user.id, str('user_id'))
316
            get_session_manager().expire_session()
317
            account.remove_self()
318
            return redirect(get_publisher().get_root_url())
319

  
320
        template.html_top(_('Removing Account'))
321
        return form.render()
auquotidien/modules/root.py
36 36
from wcs.qommon.admin.emails import EmailsDirectory
37 37
from wcs.qommon.admin.texts import TextsDirectory
38 38

  
39
from .myspace import MyspaceDirectory
40

  
41 39
import wcs.forms.root
42 40
from wcs.workflows import Workflow
43 41
from wcs.forms.preview import PreviewDirectory
......
245 243
    register = AlternateRegisterDirectory()
246 244
    login = AlternateLoginDirectory()
247 245
    ident = AlternateIdentDirectory()
248
    myspace = MyspaceDirectory()
249 246
    saml = Saml2Directory()
250 247
    code = wcs.forms.root.TrackingCodesDirectory()
251 248
    preview = AlternatePreviewDirectory()
tests/test_user_pages.py
69 69
    user = create_user()
70 70
    app = login(get_app(pub), username='user', password='user')
71 71
    resp = app.get('/', status=200)
72
    resp = app.get('/myspace/', status=200)
73

  
74

  
75
def test_myspace_with_user_forms():
76
    user = create_user()
77
    formdef = create_formdef()
78

  
79
    cat = Category(name='cat')
80
    cat.store()
81
    formdef.category_id = cat.id
82
    formdef.enable_tracking_codes = True
83

  
84
    wf = Workflow(name='status')
85
    st1 = wf.add_status('Status1', 'st1')
86
    wf.store()
87
    formdef.workflow_id = wf.id
88
    formdef.store()
89

  
90
    formdef.data_class().wipe()
91
    formdata = formdef.data_class()()
92
    formdata.user_id = user.id
93
    formdata.status = 'wf-st1'
94
    formdata.receipt_time = time.localtime()
95
    formdata.data = {}
96
    formdata.store()
97
    draft = formdef.data_class()()
98
    draft.user_id = user.id
99
    draft.status = 'draft'
100
    draft.receipt_time = time.localtime()
101
    draft.data = {}
102
    draft.store()
103

  
104
    app = login(get_app(pub), username='user', password='user')
105
    resp = app.get('/myspace/')
106
    assert formdata.id != draft.id
107
    assert '<a href="/test/%s/"' % formdata.id in resp
108
    assert '<a href="/test/%s/"' % draft.id in resp
109
    resp = app.get('/test/%s/' % formdata.id, status=302)
110
    assert resp.location == 'http://example.net/cat/test/%s/' % formdata.id
111
    resp = app.get('/test/%s/' % draft.id, status=302)
112
    resp = resp.follow(status=302)
113
    assert resp.location.startswith('http://example.net/cat/test/?mt=')
114
    resp = resp.follow(status=200)
115

  
116
    # disable formdef: formdatas are still visible and accessible, drafts are not
117
    formdef.disabled = True
118
    formdef.store()
119
    resp = app.get('/myspace/')
120
    assert formdata.id != draft.id
121
    assert '<a href="/test/%s/"' % formdata.id in resp
122
    assert not '<a href="/test/%s"' % draft.id in resp
123
    resp = app.get('/cat/test/%s' % formdata.id)
124
    resp.status_int = 200
125
    resp = app.get('/cat/test/%s/' % draft.id, status=302)
126
    resp = resp.follow(status=403)
127 72

  
128 73

  
129 74
def test_form_category_redirection():
130
-