##// END OF EJS Templates
my-account: migrated left over controller functions into pyramid views....
dan -
r1892:89ddfad2 default
parent child Browse files
Show More
@@ -0,0 +1,205 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 # -*- coding: utf-8 -*-
21
22 # Copyright (C) 2016-2017 RhodeCode GmbH
23 #
24 # This program is free software: you can redistribute it and/or modify
25 # it under the terms of the GNU Affero General Public License, version 3
26 # (only), as published by the Free Software Foundation.
27 #
28 # This program is distributed in the hope that it will be useful,
29 # but WITHOUT ANY WARRANTY; without even the implied warranty of
30 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 # GNU General Public License for more details.
32 #
33 # You should have received a copy of the GNU Affero General Public License
34 # along with this program. If not, see <http://www.gnu.org/licenses/>.
35 #
36 # This program is dual-licensed. If you wish to learn more about the
37 # RhodeCode Enterprise Edition, including its added features, Support services,
38 # and proprietary license terms, please see https://rhodecode.com/licenses/
39
40 import pytest
41
42 from rhodecode.model.db import User
43 from rhodecode.tests import TestController, assert_session_flash
44 from rhodecode.lib import helpers as h
45
46
47 def route_path(name, params=None, **kwargs):
48 import urllib
49 from rhodecode.apps._base import ADMIN_PREFIX
50
51 base_url = {
52 'my_account_edit': ADMIN_PREFIX + '/my_account/edit',
53 'my_account_update': ADMIN_PREFIX + '/my_account/update',
54 'my_account_pullrequests': ADMIN_PREFIX + '/my_account/pull_requests',
55 'my_account_pullrequests_data': ADMIN_PREFIX + '/my_account/pull_requests/data',
56 }[name].format(**kwargs)
57
58 if params:
59 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
60 return base_url
61
62
63 class TestMyAccountEdit(TestController):
64
65 def test_my_account_edit(self):
66 self.log_user()
67 response = self.app.get(route_path('my_account_edit'))
68
69 response.mustcontain('value="test_admin')
70
71 @pytest.mark.backends("git", "hg")
72 def test_my_account_my_pullrequests(self, pr_util):
73 self.log_user()
74 response = self.app.get(route_path('my_account_pullrequests'))
75 response.mustcontain('There are currently no open pull '
76 'requests requiring your participation.')
77
78 @pytest.mark.backends("git", "hg")
79 def test_my_account_my_pullrequests_data(self, pr_util, xhr_header):
80 self.log_user()
81 response = self.app.get(route_path('my_account_pullrequests_data'),
82 extra_environ=xhr_header)
83 assert response.json == {
84 u'data': [], u'draw': None,
85 u'recordsFiltered': 0, u'recordsTotal': 0}
86
87 pr = pr_util.create_pull_request(title='TestMyAccountPR')
88 expected = {
89 'author_raw': 'RhodeCode Admin',
90 'name_raw': pr.pull_request_id
91 }
92 response = self.app.get(route_path('my_account_pullrequests_data'),
93 extra_environ=xhr_header)
94 assert response.json['recordsTotal'] == 1
95 assert response.json['data'][0]['author_raw'] == expected['author_raw']
96
97 assert response.json['data'][0]['author_raw'] == expected['author_raw']
98 assert response.json['data'][0]['name_raw'] == expected['name_raw']
99
100 @pytest.mark.parametrize(
101 "name, attrs", [
102 ('firstname', {'firstname': 'new_username'}),
103 ('lastname', {'lastname': 'new_username'}),
104 ('admin', {'admin': True}),
105 ('admin', {'admin': False}),
106 ('extern_type', {'extern_type': 'ldap'}),
107 ('extern_type', {'extern_type': None}),
108 # ('extern_name', {'extern_name': 'test'}),
109 # ('extern_name', {'extern_name': None}),
110 ('active', {'active': False}),
111 ('active', {'active': True}),
112 ('email', {'email': 'some@email.com'}),
113 ])
114 def test_my_account_update(self, name, attrs, user_util):
115 usr = user_util.create_user(password='qweqwe')
116 params = usr.get_api_data() # current user data
117 user_id = usr.user_id
118 self.log_user(
119 username=usr.username, password='qweqwe')
120
121 params.update({'password_confirmation': ''})
122 params.update({'new_password': ''})
123 params.update({'extern_type': 'rhodecode'})
124 params.update({'extern_name': 'rhodecode'})
125 params.update({'csrf_token': self.csrf_token})
126
127 params.update(attrs)
128 # my account page cannot set language param yet, only for admins
129 del params['language']
130 response = self.app.post(route_path('my_account_update'), params)
131
132 assert_session_flash(
133 response, 'Your account was updated successfully')
134
135 del params['csrf_token']
136
137 updated_user = User.get(user_id)
138 updated_params = updated_user.get_api_data()
139 updated_params.update({'password_confirmation': ''})
140 updated_params.update({'new_password': ''})
141
142 params['last_login'] = updated_params['last_login']
143 params['last_activity'] = updated_params['last_activity']
144 # my account page cannot set language param yet, only for admins
145 # but we get this info from API anyway
146 params['language'] = updated_params['language']
147
148 if name == 'email':
149 params['emails'] = [attrs['email']]
150 if name == 'extern_type':
151 # cannot update this via form, expected value is original one
152 params['extern_type'] = "rhodecode"
153 if name == 'extern_name':
154 # cannot update this via form, expected value is original one
155 params['extern_name'] = str(user_id)
156 if name == 'active':
157 # my account cannot deactivate account
158 params['active'] = True
159 if name == 'admin':
160 # my account cannot make you an admin !
161 params['admin'] = False
162
163 assert params == updated_params
164
165 def test_my_account_update_err_email_exists(self):
166 self.log_user()
167
168 new_email = 'test_regular@mail.com' # already existing email
169 params = {
170 'username': 'test_admin',
171 'new_password': 'test12',
172 'password_confirmation': 'test122',
173 'firstname': 'NewName',
174 'lastname': 'NewLastname',
175 'email': new_email,
176 'csrf_token': self.csrf_token,
177 }
178
179 response = self.app.post(route_path('my_account_update'),
180 params=params)
181
182 response.mustcontain('This e-mail address is already taken')
183
184 def test_my_account_update_bad_email_address(self):
185 self.log_user('test_regular2', 'test12')
186
187 new_email = 'newmail.pl'
188 params = {
189 'username': 'test_admin',
190 'new_password': 'test12',
191 'password_confirmation': 'test122',
192 'firstname': 'NewName',
193 'lastname': 'NewLastname',
194 'email': new_email,
195 'csrf_token': self.csrf_token,
196 }
197 response = self.app.post(route_path('my_account_update'),
198 params=params)
199
200 response.mustcontain('An email address must contain a single @')
201 from rhodecode.model import validators
202 msg = validators.ValidUsername(
203 edit=False, old_data={})._messages['username_exists']
204 msg = h.html_escape(msg % {'username': 'test_admin'})
205 response.mustcontain(u"%s" % msg)
@@ -132,3 +132,9 b' class TestHomeController(TestController)'
132 132 response.mustcontain(version_string)
133 133 if state is False:
134 134 response.mustcontain(no=[version_string])
135
136 def test_logout_form_contains_csrf(self, autologin_user, csrf_token):
137 response = self.app.get(route_path('home'))
138 assert_response = response.assert_response()
139 element = assert_response.get_element('.logout #csrf_token')
140 assert element.value == csrf_token
@@ -28,6 +28,15 b' def includeme(config):'
28 28 name='my_account_profile',
29 29 pattern=ADMIN_PREFIX + '/my_account/profile')
30 30
31 # my account edit details
32 config.add_route(
33 name='my_account_edit',
34 pattern=ADMIN_PREFIX + '/my_account/edit')
35 config.add_route(
36 name='my_account_update',
37 pattern=ADMIN_PREFIX + '/my_account/update')
38
39 # my account password
31 40 config.add_route(
32 41 name='my_account_password',
33 42 pattern=ADMIN_PREFIX + '/my_account/password')
@@ -36,6 +45,7 b' def includeme(config):'
36 45 name='my_account_password_update',
37 46 pattern=ADMIN_PREFIX + '/my_account/password')
38 47
48 # my account tokens
39 49 config.add_route(
40 50 name='my_account_auth_tokens',
41 51 pattern=ADMIN_PREFIX + '/my_account/auth_tokens')
@@ -46,6 +56,7 b' def includeme(config):'
46 56 name='my_account_auth_tokens_delete',
47 57 pattern=ADMIN_PREFIX + '/my_account/auth_tokens/delete')
48 58
59 # my account emails
49 60 config.add_route(
50 61 name='my_account_emails',
51 62 pattern=ADMIN_PREFIX + '/my_account/emails')
@@ -76,6 +87,14 b' def includeme(config):'
76 87 name='my_account_notifications_toggle_visibility',
77 88 pattern=ADMIN_PREFIX + '/my_account/toggle_visibility')
78 89
90 # my account pull requests
91 config.add_route(
92 name='my_account_pullrequests',
93 pattern=ADMIN_PREFIX + '/my_account/pull_requests')
94 config.add_route(
95 name='my_account_pullrequests_data',
96 pattern=ADMIN_PREFIX + '/my_account/pull_requests/data')
97
79 98 # channelstream test
80 99 config.add_route(
81 100 name='my_account_notifications_test_channelstream',
@@ -24,8 +24,10 b' import datetime'
24 24 import formencode
25 25 from pyramid.httpexceptions import HTTPFound
26 26 from pyramid.view import view_config
27 from pyramid.renderers import render
28 from pyramid.response import Response
27 29
28 from rhodecode.apps._base import BaseAppView
30 from rhodecode.apps._base import BaseAppView, DataGridAppView
29 31 from rhodecode import forms
30 32 from rhodecode.lib import helpers as h
31 33 from rhodecode.lib import audit_logger
@@ -33,11 +35,16 b' from rhodecode.lib.ext_json import json'
33 35 from rhodecode.lib.auth import LoginRequired, NotAnonymous, CSRFRequired
34 36 from rhodecode.lib.channelstream import channelstream_request, \
35 37 ChannelstreamException
36 from rhodecode.lib.utils2 import safe_int, md5
38 from rhodecode.lib.utils import PartialRenderer
39 from rhodecode.lib.utils2 import safe_int, md5, str2bool
37 40 from rhodecode.model.auth_token import AuthTokenModel
41 from rhodecode.model.comment import CommentsModel
38 42 from rhodecode.model.db import (
39 Repository, UserEmailMap, UserApiKeys, UserFollowing, joinedload)
43 Repository, UserEmailMap, UserApiKeys, UserFollowing, joinedload,
44 PullRequest)
45 from rhodecode.model.forms import UserForm
40 46 from rhodecode.model.meta import Session
47 from rhodecode.model.pull_request import PullRequestModel
41 48 from rhodecode.model.scm import RepoList
42 49 from rhodecode.model.user import UserModel
43 50 from rhodecode.model.repo import RepoModel
@@ -46,7 +53,7 b' from rhodecode.model.validation_schema.s'
46 53 log = logging.getLogger(__name__)
47 54
48 55
49 class MyAccountView(BaseAppView):
56 class MyAccountView(BaseAppView, DataGridAppView):
50 57 ALLOW_SCOPED_TOKENS = False
51 58 """
52 59 This view has alternative version inside EE, if modified please take a look
@@ -396,4 +403,182 b' class MyAccountView(BaseAppView):'
396 403 new_status = not user.user_data.get('notification_status', True)
397 404 user.update_userdata(notification_status=new_status)
398 405 Session().commit()
399 return user.user_data['notification_status'] No newline at end of file
406 return user.user_data['notification_status']
407
408 @LoginRequired()
409 @NotAnonymous()
410 @view_config(
411 route_name='my_account_edit',
412 request_method='GET',
413 renderer='rhodecode:templates/admin/my_account/my_account.mako')
414 def my_account_edit(self):
415 c = self.load_default_context()
416 c.active = 'profile_edit'
417
418 c.perm_user = c.auth_user
419 c.extern_type = c.user.extern_type
420 c.extern_name = c.user.extern_name
421
422 defaults = c.user.get_dict()
423
424 data = render('rhodecode:templates/admin/my_account/my_account.mako',
425 self._get_template_context(c), self.request)
426 html = formencode.htmlfill.render(
427 data,
428 defaults=defaults,
429 encoding="UTF-8",
430 force_defaults=False
431 )
432 return Response(html)
433
434 @LoginRequired()
435 @NotAnonymous()
436 @CSRFRequired()
437 @view_config(
438 route_name='my_account_update',
439 request_method='POST',
440 renderer='rhodecode:templates/admin/my_account/my_account.mako')
441 def my_account_update(self):
442 _ = self.request.translate
443 c = self.load_default_context()
444 c.active = 'profile_edit'
445
446 c.perm_user = c.auth_user
447 c.extern_type = c.user.extern_type
448 c.extern_name = c.user.extern_name
449
450 _form = UserForm(edit=True,
451 old_data={'user_id': self._rhodecode_user.user_id,
452 'email': self._rhodecode_user.email})()
453 form_result = {}
454 try:
455 post_data = dict(self.request.POST)
456 post_data['new_password'] = ''
457 post_data['password_confirmation'] = ''
458 form_result = _form.to_python(post_data)
459 # skip updating those attrs for my account
460 skip_attrs = ['admin', 'active', 'extern_type', 'extern_name',
461 'new_password', 'password_confirmation']
462 # TODO: plugin should define if username can be updated
463 if c.extern_type != "rhodecode":
464 # forbid updating username for external accounts
465 skip_attrs.append('username')
466
467 UserModel().update_user(
468 self._rhodecode_user.user_id, skip_attrs=skip_attrs,
469 **form_result)
470 h.flash(_('Your account was updated successfully'),
471 category='success')
472 Session().commit()
473
474 except formencode.Invalid as errors:
475 data = render(
476 'rhodecode:templates/admin/my_account/my_account.mako',
477 self._get_template_context(c), self.request)
478
479 html = formencode.htmlfill.render(
480 data,
481 defaults=errors.value,
482 errors=errors.error_dict or {},
483 prefix_error=False,
484 encoding="UTF-8",
485 force_defaults=False)
486 return Response(html)
487
488 except Exception:
489 log.exception("Exception updating user")
490 h.flash(_('Error occurred during update of user %s')
491 % form_result.get('username'), category='error')
492 raise HTTPFound(h.route_path('my_account_profile'))
493
494 raise HTTPFound(h.route_path('my_account_profile'))
495
496 def _get_pull_requests_list(self, statuses):
497 draw, start, limit = self._extract_chunk(self.request)
498 search_q, order_by, order_dir = self._extract_ordering(self.request)
499 _render = PartialRenderer('data_table/_dt_elements.mako')
500
501 pull_requests = PullRequestModel().get_im_participating_in(
502 user_id=self._rhodecode_user.user_id,
503 statuses=statuses,
504 offset=start, length=limit, order_by=order_by,
505 order_dir=order_dir)
506
507 pull_requests_total_count = PullRequestModel().count_im_participating_in(
508 user_id=self._rhodecode_user.user_id, statuses=statuses)
509
510 data = []
511 comments_model = CommentsModel()
512 for pr in pull_requests:
513 repo_id = pr.target_repo_id
514 comments = comments_model.get_all_comments(
515 repo_id, pull_request=pr)
516 owned = pr.user_id == self._rhodecode_user.user_id
517
518 data.append({
519 'target_repo': _render('pullrequest_target_repo',
520 pr.target_repo.repo_name),
521 'name': _render('pullrequest_name',
522 pr.pull_request_id, pr.target_repo.repo_name,
523 short=True),
524 'name_raw': pr.pull_request_id,
525 'status': _render('pullrequest_status',
526 pr.calculated_review_status()),
527 'title': _render(
528 'pullrequest_title', pr.title, pr.description),
529 'description': h.escape(pr.description),
530 'updated_on': _render('pullrequest_updated_on',
531 h.datetime_to_time(pr.updated_on)),
532 'updated_on_raw': h.datetime_to_time(pr.updated_on),
533 'created_on': _render('pullrequest_updated_on',
534 h.datetime_to_time(pr.created_on)),
535 'created_on_raw': h.datetime_to_time(pr.created_on),
536 'author': _render('pullrequest_author',
537 pr.author.full_contact, ),
538 'author_raw': pr.author.full_name,
539 'comments': _render('pullrequest_comments', len(comments)),
540 'comments_raw': len(comments),
541 'closed': pr.is_closed(),
542 'owned': owned
543 })
544
545 # json used to render the grid
546 data = ({
547 'draw': draw,
548 'data': data,
549 'recordsTotal': pull_requests_total_count,
550 'recordsFiltered': pull_requests_total_count,
551 })
552 return data
553
554 @LoginRequired()
555 @NotAnonymous()
556 @view_config(
557 route_name='my_account_pullrequests',
558 request_method='GET',
559 renderer='rhodecode:templates/admin/my_account/my_account.mako')
560 def my_account_pullrequests(self):
561 c = self.load_default_context()
562 c.active = 'pullrequests'
563 req_get = self.request.GET
564
565 c.closed = str2bool(req_get.get('pr_show_closed'))
566
567 return self._get_template_context(c)
568
569 @LoginRequired()
570 @NotAnonymous()
571 @view_config(
572 route_name='my_account_pullrequests_data',
573 request_method='GET', renderer='json_ext')
574 def my_account_pullrequests_data(self):
575 req_get = self.request.GET
576 closed = str2bool(req_get.get('closed'))
577
578 statuses = [PullRequest.STATUS_NEW, PullRequest.STATUS_OPEN]
579 if closed:
580 statuses += [PullRequest.STATUS_CLOSED]
581
582 data = self._get_pull_requests_list(statuses=statuses)
583 return data
584
@@ -462,19 +462,11 b' def make_map(config):'
462 462 with rmap.submapper(path_prefix=ADMIN_PREFIX,
463 463 controller='admin/my_account') as m:
464 464
465 m.connect('my_account_edit', '/my_account/edit',
466 action='my_account_edit', conditions={'method': ['GET']})
467 m.connect('my_account', '/my_account/update',
468 action='my_account_update', conditions={'method': ['POST']})
469
470 465 # NOTE(marcink): this needs to be kept for password force flag to be
471 # handler, remove after migration to pyramid
466 # handled in pylons controllers, remove after full migration to pyramid
472 467 m.connect('my_account_password', '/my_account/password',
473 468 action='my_account_password', conditions={'method': ['GET']})
474 469
475 m.connect('my_account_pullrequests', '/my_account/pull_requests',
476 action='my_account_pullrequests', conditions={'method': ['GET']})
477
478 470 # NOTIFICATION REST ROUTES
479 471 with rmap.submapper(path_prefix=ADMIN_PREFIX,
480 472 controller='admin/notifications') as m:
@@ -136,6 +136,8 b' function registerRCRoutes() {'
136 136 pyroutes.register('search_repo', '/%(repo_name)s/search', ['repo_name']);
137 137 pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']);
138 138 pyroutes.register('my_account_profile', '/_admin/my_account/profile', []);
139 pyroutes.register('my_account_edit', '/_admin/my_account/edit', []);
140 pyroutes.register('my_account_update', '/_admin/my_account/update', []);
139 141 pyroutes.register('my_account_password', '/_admin/my_account/password', []);
140 142 pyroutes.register('my_account_password_update', '/_admin/my_account/password', []);
141 143 pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
@@ -149,6 +151,8 b' function registerRCRoutes() {'
149 151 pyroutes.register('my_account_perms', '/_admin/my_account/perms', []);
150 152 pyroutes.register('my_account_notifications', '/_admin/my_account/notifications', []);
151 153 pyroutes.register('my_account_notifications_toggle_visibility', '/_admin/my_account/toggle_visibility', []);
154 pyroutes.register('my_account_pullrequests', '/_admin/my_account/pull_requests', []);
155 pyroutes.register('my_account_pullrequests_data', '/_admin/my_account/pull_requests/data', []);
152 156 pyroutes.register('my_account_notifications_test_channelstream', '/_admin/my_account/test_channelstream', []);
153 157 pyroutes.register('gists_show', '/_admin/gists', []);
154 158 pyroutes.register('gists_new', '/_admin/gists/new', []);
@@ -37,7 +37,7 b''
37 37 <li class="${'active' if c.active=='emails' else ''}"><a href="${h.route_path('my_account_emails')}">${_('Emails')}</a></li>
38 38 <li class="${'active' if c.active=='repos' else ''}"><a href="${h.route_path('my_account_repos')}">${_('Repositories')}</a></li>
39 39 <li class="${'active' if c.active=='watched' else ''}"><a href="${h.route_path('my_account_watched')}">${_('Watched')}</a></li>
40 <li class="${'active' if c.active=='pullrequests' else ''}"><a href="${h.url('my_account_pullrequests')}">${_('Pull Requests')}</a></li>
40 <li class="${'active' if c.active=='pullrequests' else ''}"><a href="${h.route_path('my_account_pullrequests')}">${_('Pull Requests')}</a></li>
41 41 <li class="${'active' if c.active=='perms' else ''}"><a href="${h.route_path('my_account_perms')}">${_('Permissions')}</a></li>
42 42 <li class="${'active' if c.active=='my_notifications' else ''}"><a href="${h.route_path('my_account_notifications')}">${_('Live Notifications')}</a></li>
43 43 </ul>
@@ -2,7 +2,7 b''
2 2 <div class="panel panel-default user-profile">
3 3 <div class="panel-heading">
4 4 <h3 class="panel-title">${_('My Profile')}</h3>
5 <a href="${url('my_account_edit')}" class="panel-edit">${_('Edit')}</a>
5 <a href="${h.route_path('my_account_edit')}" class="panel-edit">${_('Edit')}</a>
6 6 </div>
7 7
8 8 <div class="panel-body">
@@ -6,7 +6,7 b''
6 6 </div>
7 7
8 8 <div class="panel-body">
9 ${h.secure_form(url('my_account'), method='post', class_='form')}
9 ${h.secure_form(h.route_path('my_account_update'), class_='form', method='POST')}
10 10 <% readonly = None %>
11 11 <% disabled = "" %>
12 12
@@ -2,7 +2,7 b''
2 2
3 3 <div class="panel panel-default">
4 4 <div class="panel-body">
5 %if c.show_closed:
5 %if c.closed:
6 6 ${h.checkbox('show_closed',checked="checked", label=_('Show Closed Pull Requests'))}
7 7 %else:
8 8 ${h.checkbox('show_closed',label=_('Show Closed Pull Requests'))}
@@ -12,25 +12,41 b''
12 12
13 13 <div class="panel panel-default">
14 14 <div class="panel-heading">
15 <h3 class="panel-title">${_('Pull Requests You Participate In')}: ${c.records_total_participate}</h3>
15 <h3 class="panel-title">${_('Pull Requests You Participate In')}</h3>
16 16 </div>
17 <div class="panel-body">
18 <table id="pull_request_list_table_participate" class="display"></table>
17 <div class="panel-body panel-body-min-height">
18 <table id="pull_request_list_table" class="display"></table>
19 19 </div>
20 20 </div>
21 21
22 <script>
22 <script type="text/javascript">
23 $(document).ready(function() {
24
23 25 $('#show_closed').on('click', function(e){
24 26 if($(this).is(":checked")){
25 window.location = "${h.url('my_account_pullrequests', pr_show_closed=1)}";
27 window.location = "${h.route_path('my_account_pullrequests', _query={'pr_show_closed':1})}";
26 28 }
27 29 else{
28 window.location = "${h.url('my_account_pullrequests')}";
30 window.location = "${h.route_path('my_account_pullrequests')}";
29 31 }
30 32 });
31 $(document).ready(function() {
33
34 var $pullRequestListTable = $('#pull_request_list_table');
32 35
33 var columnsDefs = [
36 // participating object list
37 $pullRequestListTable.DataTable({
38 processing: true,
39 serverSide: true,
40 ajax: {
41 "url": "${h.route_path('my_account_pullrequests_data')}",
42 "data": function (d) {
43 d.closed = "${c.closed}";
44 }
45 },
46 dom: 'rtp',
47 pageLength: ${c.visual.dashboard_items},
48 order: [[ 2, "desc" ]],
49 columns: [
34 50 { data: {"_": "status",
35 51 "sort": "status"}, title: "", className: "td-status", orderable: false},
36 52 { data: {"_": "target_repo",
@@ -45,21 +61,10 b''
45 61 "sort": "comments_raw"}, title: "", className: "td-comments", orderable: false},
46 62 { data: {"_": "updated_on",
47 63 "sort": "updated_on_raw"}, title: "${_('Last Update')}", className: "td-time" }
48 ];
49
50 // participating object list
51 $('#pull_request_list_table_participate').DataTable({
52 data: ${c.data_participate|n},
53 processing: true,
54 serverSide: true,
55 deferLoading: ${c.records_total_participate},
56 ajax: "",
57 dom: 'tp',
58 pageLength: ${c.visual.dashboard_items},
59 order: [[ 2, "desc" ]],
60 columns: columnsDefs,
64 ],
61 65 language: {
62 66 paginate: DEFAULT_GRID_PAGINATION,
67 sProcessing: _gettext('loading...'),
63 68 emptyTable: _gettext("There are currently no open pull requests requiring your participation.")
64 69 },
65 70 "drawCallback": function( settings, json ) {
@@ -74,5 +79,12 b''
74 79 }
75 80 }
76 81 });
82 $pullRequestListTable.on('xhr.dt', function(e, settings, json, xhr){
83 $pullRequestListTable.css('opacity', 1);
84 });
85
86 $pullRequestListTable.on('preXhr.dt', function(e, settings, data){
87 $pullRequestListTable.css('opacity', 0.3);
88 });
77 89 });
78 90 </script>
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now