Commit 5046caafa4eb9f665b3629469485d8f4d962c177
Exists in
master
and in
28 other branches
Merge branch 'master' of portal.softwarepublico.gov.br:softwarepublico/colab
Showing
18 changed files
with
259 additions
and
119 deletions
Show diff stats
colab/accounts/forms.py
@@ -141,8 +141,9 @@ class UserUpdateForm(UserForm): | @@ -141,8 +141,9 @@ class UserUpdateForm(UserForm): | ||
141 | 141 | ||
142 | class ListsForm(forms.Form): | 142 | class ListsForm(forms.Form): |
143 | LISTS_NAMES = (( | 143 | LISTS_NAMES = (( |
144 | - listname, u'{} ({})'.format(listname, description) | ||
145 | - ) for listname, description in mailman.all_lists(description=True)) | 144 | + mlist.get('listname'), u'{} ({})'.format(mlist.get('listname'), |
145 | + mlist.get('description')) | ||
146 | + ) for mlist in mailman.all_lists()) | ||
146 | 147 | ||
147 | lists = forms.MultipleChoiceField(label=_(u'Mailing lists'), | 148 | lists = forms.MultipleChoiceField(label=_(u'Mailing lists'), |
148 | required=False, | 149 | required=False, |
colab/accounts/models.py
@@ -60,7 +60,7 @@ class User(AbstractUser): | @@ -60,7 +60,7 @@ class User(AbstractUser): | ||
60 | return mailman.user_lists(self) | 60 | return mailman.user_lists(self) |
61 | 61 | ||
62 | def update_subscription(self, email, lists): | 62 | def update_subscription(self, email, lists): |
63 | - mailman.update_subscription(email, lists) | 63 | + return mailman.update_subscription(email, lists) |
64 | 64 | ||
65 | def save(self, *args, **kwargs): | 65 | def save(self, *args, **kwargs): |
66 | 66 |
colab/accounts/templates/accounts/user_detail.html
@@ -84,7 +84,6 @@ | @@ -84,7 +84,6 @@ | ||
84 | {% endif %} | 84 | {% endif %} |
85 | {% endif %} | 85 | {% endif %} |
86 | </ul> | 86 | </ul> |
87 | - | ||
88 | {% if user_.mailinglists %} | 87 | {% if user_.mailinglists %} |
89 | <b>{% trans 'Groups: ' %}</b> | 88 | <b>{% trans 'Groups: ' %}</b> |
90 | {% for list in user_.mailinglists %} | 89 | {% for list in user_.mailinglists %} |
colab/accounts/utils/mailman.py
@@ -4,66 +4,99 @@ import requests | @@ -4,66 +4,99 @@ import requests | ||
4 | import logging | 4 | import logging |
5 | 5 | ||
6 | from django.conf import settings | 6 | from django.conf import settings |
7 | +from django.contrib import messages | ||
7 | 8 | ||
8 | TIMEOUT = 1 | 9 | TIMEOUT = 1 |
9 | 10 | ||
10 | LOGGER = logging.getLogger('colab.mailman') | 11 | LOGGER = logging.getLogger('colab.mailman') |
11 | 12 | ||
12 | - | ||
13 | -def get_url(listname=None): | 13 | +S = 'success' |
14 | +I = 'info' | ||
15 | +E = 'error' | ||
16 | + | ||
17 | +MAILMAN_MSGS = { | ||
18 | + 0: (S, '%s: Success!'), | ||
19 | + 1: (S, '%s: An email confirmation was sent to you, please check your inbox.'), | ||
20 | + 2: (I, '%s: Your subscription was sent successfully! Please wait for the list\'s admin approval.'), | ||
21 | + 3: (I, '%s: You are already a member of this list.'), | ||
22 | + 4: (E, '%s: You are banned from this list!'), | ||
23 | + 5: (E, '%s: You appear to have an invalid email address.'), | ||
24 | + 6: (E, '%s: Your email address is considered to be hostile.'), | ||
25 | + 7: (E, '%s: You are not a member of this list.'), | ||
26 | + 8: (E, 'Missing information: `email_from`, `subject` and `body` are mandatory.'), | ||
27 | +} | ||
28 | + | ||
29 | + | ||
30 | +def get_url(path, listname=None): | ||
31 | + url = urlparse.urljoin(settings.MAILMAN_API_URL, path) | ||
14 | if listname: | 32 | if listname: |
15 | - return urlparse.urljoin(settings.MAILMAN_API_URL, '/' + listname) | ||
16 | - | ||
17 | - return settings.MAILMAN_API_URL | 33 | + return urlparse.urljoin(url, listname) |
34 | + return url | ||
18 | 35 | ||
19 | 36 | ||
20 | def subscribe(listname, address): | 37 | def subscribe(listname, address): |
21 | - url = get_url(listname) | 38 | + url = get_url('subscribe/', listname=listname) |
22 | try: | 39 | try: |
23 | - requests.put(url, timeout=TIMEOUT, data={'address': address}) | 40 | + result = requests.put(url, timeout=TIMEOUT, data={'address': address}) |
41 | + msg_type, message = MAILMAN_MSGS[result.json()] | ||
42 | + return msg_type, message % listname | ||
24 | except: | 43 | except: |
25 | LOGGER.exception('Unable to subscribe user') | 44 | LOGGER.exception('Unable to subscribe user') |
26 | - return False | ||
27 | - return True | 45 | + return E, 'Error: Unable to subscribe user' |
28 | 46 | ||
29 | 47 | ||
30 | def unsubscribe(listname, address): | 48 | def unsubscribe(listname, address): |
31 | - url = get_url(listname) | 49 | + url = get_url('subscribe/', listname) |
32 | try: | 50 | try: |
33 | - requests.delete(url, timeout=TIMEOUT, data={'address': address}) | 51 | + result = requests.delete(url, timeout=TIMEOUT, data={'address': address}) |
52 | + msg_type, message = MAILMAN_MSGS[result.json()] | ||
53 | + return msg_type, message % listname | ||
34 | except: | 54 | except: |
35 | LOGGER.exception('Unable to unsubscribe user') | 55 | LOGGER.exception('Unable to unsubscribe user') |
36 | - return False | ||
37 | - return True | 56 | + return E, 'Error: Unable to subscribe user' |
38 | 57 | ||
39 | 58 | ||
40 | def update_subscription(address, lists): | 59 | def update_subscription(address, lists): |
41 | - current_lists = mailing_lists(address=address) | 60 | + current_lists = mailing_lists(address=address, names_only=True) |
61 | + info_messages = [] | ||
42 | 62 | ||
43 | for maillist in current_lists: | 63 | for maillist in current_lists: |
44 | if maillist not in lists: | 64 | if maillist not in lists: |
45 | - unsubscribe(maillist, address) | 65 | + info_messages.append(unsubscribe(maillist, address)) |
46 | 66 | ||
47 | for maillist in lists: | 67 | for maillist in lists: |
48 | if maillist not in current_lists: | 68 | if maillist not in current_lists: |
49 | - subscribe(maillist, address) | 69 | + info_messages.append(subscribe(maillist, address)) |
70 | + | ||
71 | + return info_messages | ||
50 | 72 | ||
51 | 73 | ||
52 | def mailing_lists(**kwargs): | 74 | def mailing_lists(**kwargs): |
53 | - url = get_url() | 75 | + url = get_url('lists/') |
54 | 76 | ||
55 | try: | 77 | try: |
56 | - lists = requests.get(url, timeout=TIMEOUT, params=kwargs) | 78 | + lists = requests.get(url, timeout=TIMEOUT, params=kwargs).json() |
79 | + if not isinstance(lists, (list, tuple)): | ||
80 | + raise | ||
57 | except: | 81 | except: |
58 | LOGGER.exception('Unable to list mailing lists') | 82 | LOGGER.exception('Unable to list mailing lists') |
59 | return [] | 83 | return [] |
60 | 84 | ||
61 | - return lists.json() | 85 | + if kwargs.get('names_only'): |
86 | + names_only = [] | ||
87 | + for l in lists: | ||
88 | + names_only.append(l['listname']) | ||
89 | + return names_only | ||
90 | + else: | ||
91 | + return lists | ||
62 | 92 | ||
63 | 93 | ||
64 | def is_private_list(name): | 94 | def is_private_list(name): |
65 | try: | 95 | try: |
66 | - return dict(all_lists(private=True))[name] | 96 | + privacy = {} |
97 | + privacy.update({mlist.get('listname'): mlist.get('archive_private') | ||
98 | + for mlist in all_lists()}) | ||
99 | + return privacy[name] | ||
67 | except KeyError: | 100 | except KeyError: |
68 | return [] | 101 | return [] |
69 | 102 | ||
@@ -76,22 +109,25 @@ def user_lists(user): | @@ -76,22 +109,25 @@ def user_lists(user): | ||
76 | list_set = set() | 109 | list_set = set() |
77 | 110 | ||
78 | for email in user.emails.values_list('address', flat=True): | 111 | for email in user.emails.values_list('address', flat=True): |
79 | - list_set.update(mailing_lists(address=email)) | 112 | + mlists = mailing_lists(address=email) |
113 | + list_set.update(mlist.get('listname') for mlist in mlists) | ||
80 | 114 | ||
81 | return tuple(list_set) | 115 | return tuple(list_set) |
82 | 116 | ||
83 | 117 | ||
84 | def get_list_description(listname, lists=None): | 118 | def get_list_description(listname, lists=None): |
85 | if not lists: | 119 | if not lists: |
86 | - lists = dict(all_lists(description=True)) | ||
87 | - elif not isinstance(lists, dict): | ||
88 | - lists = dict(lists) | 120 | + lists = all_lists() |
121 | + | ||
122 | + desc = "".join(mlist.get('description') for mlist in lists | ||
123 | + if isinstance(mlist, dict) and | ||
124 | + mlist.get('listname') == listname) | ||
89 | 125 | ||
90 | - return lists.get(listname) | 126 | + return desc |
91 | 127 | ||
92 | 128 | ||
93 | def list_users(listname): | 129 | def list_users(listname): |
94 | - url = get_url(listname) | 130 | + url = get_url('members/', listname) |
95 | 131 | ||
96 | params = {} | 132 | params = {} |
97 | 133 | ||
@@ -114,3 +150,10 @@ def get_user_mailinglists(user): | @@ -114,3 +150,10 @@ def get_user_mailinglists(user): | ||
114 | lists_for_user.extend(mailing_lists(address=email)) | 150 | lists_for_user.extend(mailing_lists(address=email)) |
115 | 151 | ||
116 | return lists_for_user | 152 | return lists_for_user |
153 | + | ||
154 | + | ||
155 | +def extract_listname_from_list(lists): | ||
156 | + try: | ||
157 | + return [mlist.get('listname') for mlist in lists] | ||
158 | + except ValueError: | ||
159 | + return [] |
colab/accounts/views.py
@@ -103,7 +103,12 @@ def signup(request): | @@ -103,7 +103,12 @@ def signup(request): | ||
103 | 103 | ||
104 | user.is_active = False | 104 | user.is_active = False |
105 | user.save() | 105 | user.save() |
106 | - EmailAddressValidation.create(user.email, user) | 106 | + email = EmailAddressValidation.create(user.email, user) |
107 | + | ||
108 | + location = reverse('archive_email_view', | ||
109 | + kwargs={'key': email.validation_key}) | ||
110 | + verification_url = request.build_absolute_uri(location) | ||
111 | + EmailAddressValidation.verify_email(email, verification_url) | ||
107 | 112 | ||
108 | # Check if the user's email have been used previously | 113 | # Check if the user's email have been used previously |
109 | # in the mainling lists to link the user to old messages | 114 | # in the mainling lists to link the user to old messages |
@@ -139,7 +144,11 @@ class ManageUserSubscriptionsView(UserProfileBaseMixin, DetailView): | @@ -139,7 +144,11 @@ class ManageUserSubscriptionsView(UserProfileBaseMixin, DetailView): | ||
139 | user = self.get_object() | 144 | user = self.get_object() |
140 | for email in user.emails.values_list('address', flat=True): | 145 | for email in user.emails.values_list('address', flat=True): |
141 | lists = self.request.POST.getlist(email) | 146 | lists = self.request.POST.getlist(email) |
142 | - user.update_subscription(email, lists) | 147 | + info_messages = user.update_subscription(email, lists) |
148 | + for msg_type, message in info_messages: | ||
149 | + show_message = getattr(messages, msg_type) | ||
150 | + show_message(request, _(message)) | ||
151 | + | ||
143 | 152 | ||
144 | return redirect('user_profile', username=user.username) | 153 | return redirect('user_profile', username=user.username) |
145 | 154 | ||
@@ -149,18 +158,19 @@ class ManageUserSubscriptionsView(UserProfileBaseMixin, DetailView): | @@ -149,18 +158,19 @@ class ManageUserSubscriptionsView(UserProfileBaseMixin, DetailView): | ||
149 | 158 | ||
150 | user = self.get_object() | 159 | user = self.get_object() |
151 | emails = user.emails.values_list('address', flat=True) | 160 | emails = user.emails.values_list('address', flat=True) |
152 | - all_lists = mailman.all_lists(description=True) | 161 | + all_lists = mailman.all_lists() |
153 | 162 | ||
154 | for email in emails: | 163 | for email in emails: |
155 | lists = [] | 164 | lists = [] |
156 | - lists_for_address = mailman.mailing_lists(address=email) | ||
157 | - for listname, description in all_lists: | ||
158 | - if listname in lists_for_address: | 165 | + lists_for_address = mailman.mailing_lists(address=email, names_only=True) |
166 | + for mlist in all_lists: | ||
167 | + if mlist.get('listname') in lists_for_address: | ||
159 | checked = True | 168 | checked = True |
160 | else: | 169 | else: |
161 | checked = False | 170 | checked = False |
162 | lists.append(( | 171 | lists.append(( |
163 | - {'listname': listname, 'description': description}, | 172 | + {'listname': mlist.get('listname'), |
173 | + 'description': mlist.get('description')}, | ||
164 | checked | 174 | checked |
165 | )) | 175 | )) |
166 | 176 |
colab/home/views.py
@@ -10,9 +10,10 @@ from colab.accounts.models import User | @@ -10,9 +10,10 @@ from colab.accounts.models import User | ||
10 | 10 | ||
11 | def get_user_threads(threads, lists_for_user, key): | 11 | def get_user_threads(threads, lists_for_user, key): |
12 | visible_threads = [] | 12 | visible_threads = [] |
13 | + listnames_for_user = mailman.extract_listname_from_list(lists_for_user) | ||
13 | for t in threads: | 14 | for t in threads: |
14 | if not t.mailinglist.is_private or \ | 15 | if not t.mailinglist.is_private or \ |
15 | - t.mailinglist.name in lists_for_user: | 16 | + t.mailinglist.name in listnames_for_user: |
16 | visible_threads.append(key(t)) | 17 | visible_threads.append(key(t)) |
17 | 18 | ||
18 | return visible_threads | 19 | return visible_threads |
colab/plugins/gitlab/migrations/0005_auto_20150806_1230.py
0 → 100644
@@ -0,0 +1,24 @@ | @@ -0,0 +1,24 @@ | ||
1 | +# -*- coding: utf-8 -*- | ||
2 | +from __future__ import unicode_literals | ||
3 | + | ||
4 | +from django.db import models, migrations | ||
5 | + | ||
6 | + | ||
7 | +class Migration(migrations.Migration): | ||
8 | + | ||
9 | + dependencies = [ | ||
10 | + ('gitlab', '0004_auto_20150630_1149'), | ||
11 | + ] | ||
12 | + | ||
13 | + operations = [ | ||
14 | + migrations.RemoveField( | ||
15 | + model_name='gitlabcomment', | ||
16 | + name='iid', | ||
17 | + ), | ||
18 | + migrations.AddField( | ||
19 | + model_name='gitlabissue', | ||
20 | + name='iid', | ||
21 | + field=models.IntegerField(null=True), | ||
22 | + preserve_default=True, | ||
23 | + ), | ||
24 | + ] |
colab/plugins/gitlab/models.py
@@ -64,6 +64,7 @@ class GitlabMergeRequest(Collaboration): | @@ -64,6 +64,7 @@ class GitlabMergeRequest(Collaboration): | ||
64 | class GitlabIssue(Collaboration): | 64 | class GitlabIssue(Collaboration): |
65 | 65 | ||
66 | id = models.IntegerField(primary_key=True) | 66 | id = models.IntegerField(primary_key=True) |
67 | + iid = models.IntegerField(null=True) | ||
67 | project = models.ForeignKey(GitlabProject, null=True, | 68 | project = models.ForeignKey(GitlabProject, null=True, |
68 | on_delete=models.SET_NULL) | 69 | on_delete=models.SET_NULL) |
69 | title = models.TextField() | 70 | title = models.TextField() |
@@ -82,7 +83,7 @@ class GitlabIssue(Collaboration): | @@ -82,7 +83,7 @@ class GitlabIssue(Collaboration): | ||
82 | @property | 83 | @property |
83 | def url(self): | 84 | def url(self): |
84 | return u'/gitlab/{}/issues/{}'.format( | 85 | return u'/gitlab/{}/issues/{}'.format( |
85 | - self.project.path_with_namespace, self.id) | 86 | + self.project.path_with_namespace, self.iid) |
86 | 87 | ||
87 | class Meta: | 88 | class Meta: |
88 | verbose_name = _('Gitlab Issue') | 89 | verbose_name = _('Gitlab Issue') |
@@ -92,7 +93,6 @@ class GitlabIssue(Collaboration): | @@ -92,7 +93,6 @@ class GitlabIssue(Collaboration): | ||
92 | class GitlabComment(Collaboration): | 93 | class GitlabComment(Collaboration): |
93 | 94 | ||
94 | id = models.IntegerField(primary_key=True) | 95 | id = models.IntegerField(primary_key=True) |
95 | - iid = models.IntegerField(null=True) | ||
96 | body = models.TextField() | 96 | body = models.TextField() |
97 | created_at = models.DateTimeField(blank=True, null=True) | 97 | created_at = models.DateTimeField(blank=True, null=True) |
98 | issue_comment = models.BooleanField(default=True) | 98 | issue_comment = models.BooleanField(default=True) |
@@ -139,7 +139,7 @@ class GitlabComment(Collaboration): | @@ -139,7 +139,7 @@ class GitlabComment(Collaboration): | ||
139 | url_str = u'/gitlab/{}/merge_requests/{}#notes_{}' | 139 | url_str = u'/gitlab/{}/merge_requests/{}#notes_{}' |
140 | 140 | ||
141 | return url_str.format(self.project.path_with_namespace, | 141 | return url_str.format(self.project.path_with_namespace, |
142 | - self.parent_id, self.iid) | 142 | + self.parent_id, self.id) |
143 | 143 | ||
144 | class Meta: | 144 | class Meta: |
145 | verbose_name = _('Gitlab Comments') | 145 | verbose_name = _('Gitlab Comments') |
colab/plugins/gitlab/tests/test_gitlab.py
@@ -24,9 +24,9 @@ class GitlabTest(TestCase): | @@ -24,9 +24,9 @@ class GitlabTest(TestCase): | ||
24 | pass | 24 | pass |
25 | 25 | ||
26 | def test_data_integrity(self): | 26 | def test_data_integrity(self): |
27 | - self.assertEqual(GitlabProject.objects.all().count(), 1) | ||
28 | - self.assertEqual(GitlabMergeRequest.objects.all().count(), 1) | ||
29 | - self.assertEqual(GitlabIssue.objects.all().count(), 1) | 27 | + self.assertEqual(GitlabProject.objects.all().count(), 2) |
28 | + self.assertEqual(GitlabMergeRequest.objects.all().count(), 2) | ||
29 | + self.assertEqual(GitlabIssue.objects.all().count(), 2) | ||
30 | self.assertEqual(GitlabComment.objects.all().count(), 2) | 30 | self.assertEqual(GitlabComment.objects.all().count(), 2) |
31 | 31 | ||
32 | def test_project_url(self): | 32 | def test_project_url(self): |
@@ -34,55 +34,92 @@ class GitlabTest(TestCase): | @@ -34,55 +34,92 @@ class GitlabTest(TestCase): | ||
34 | '/gitlab/softwarepublico/colab') | 34 | '/gitlab/softwarepublico/colab') |
35 | 35 | ||
36 | def test_merge_request_url(self): | 36 | def test_merge_request_url(self): |
37 | - self.assertEqual(GitlabMergeRequest.objects.get(iid=1).url, | 37 | + self.assertEqual(GitlabMergeRequest.objects.get(id=1).url, |
38 | '/gitlab/softwarepublico/colab/merge_requests/1') | 38 | '/gitlab/softwarepublico/colab/merge_requests/1') |
39 | + self.assertEqual(GitlabMergeRequest.objects.get(id=2).url, | ||
40 | + '/gitlab/softwarepublico/colabinc/merge_requests/1') | ||
39 | 41 | ||
40 | def test_issue_url(self): | 42 | def test_issue_url(self): |
41 | self.assertEqual(GitlabIssue.objects.get(id=1).url, | 43 | self.assertEqual(GitlabIssue.objects.get(id=1).url, |
42 | '/gitlab/softwarepublico/colab/issues/1') | 44 | '/gitlab/softwarepublico/colab/issues/1') |
45 | + self.assertEqual(GitlabIssue.objects.get(id=2).url, | ||
46 | + '/gitlab/softwarepublico/colabinc/issues/1') | ||
43 | 47 | ||
44 | def test_comment_on_mr_url(self): | 48 | def test_comment_on_mr_url(self): |
45 | url = '/gitlab/softwarepublico/colab/merge_requests/1#notes_1' | 49 | url = '/gitlab/softwarepublico/colab/merge_requests/1#notes_1' |
46 | - self.assertEqual(GitlabComment.objects.get(iid=1).url, url) | 50 | + self.assertEqual(GitlabComment.objects.get(id=1).url, url) |
47 | 51 | ||
48 | def test_comment_on_issue_url(self): | 52 | def test_comment_on_issue_url(self): |
49 | self.assertEqual(GitlabComment.objects.get(id=2).url, | 53 | self.assertEqual(GitlabComment.objects.get(id=2).url, |
50 | '/gitlab/softwarepublico/colab/issues/1#notes_2') | 54 | '/gitlab/softwarepublico/colab/issues/1#notes_2') |
51 | 55 | ||
52 | def create_gitlab_data(self): | 56 | def create_gitlab_data(self): |
53 | - g = GitlabProject() | ||
54 | - g.id = 1 | ||
55 | - g.name = "colab" | ||
56 | - g.name_with_namespace = "Software Public / Colab" | ||
57 | - g.path_with_namespace = "softwarepublico/colab" | ||
58 | - g.created_at = datetime.now() | ||
59 | - g.last_activity_at = datetime.now() | ||
60 | - g.save() | ||
61 | - | ||
62 | - mr = GitlabMergeRequest() | ||
63 | - mr.iid = 1 | ||
64 | - mr.project = g | ||
65 | - mr.title = "Include plugin support" | ||
66 | - mr.description = "Merge request for plugin support" | ||
67 | - mr.state = "Closed" | ||
68 | - mr.created_at = datetime.now() | ||
69 | - mr.update_user(self.user.username) | ||
70 | - mr.save() | ||
71 | - | ||
72 | - i = GitlabIssue() | ||
73 | - i.id = 1 | ||
74 | - i.project = g | ||
75 | - i.title = "Issue for colab" | ||
76 | - i.description = "Issue reported to colab" | ||
77 | - i.created_at = datetime.now() | ||
78 | - i.state = "Open" | ||
79 | - i.update_user(self.user.username) | ||
80 | - i.save() | 57 | + g1 = GitlabProject() |
58 | + g1.id = 1 | ||
59 | + g1.name = "colab" | ||
60 | + g1.name_with_namespace = "Software Public / Colab" | ||
61 | + g1.path_with_namespace = "softwarepublico/colab" | ||
62 | + g1.created_at = datetime.now() | ||
63 | + g1.last_activity_at = datetime.now() | ||
64 | + g1.save() | ||
65 | + | ||
66 | + g2 = GitlabProject() | ||
67 | + g2.id = 2 | ||
68 | + g2.name = "colabinc" | ||
69 | + g2.name_with_namespace = "Software Public / ColabInc" | ||
70 | + g2.path_with_namespace = "softwarepublico/colabinc" | ||
71 | + g2.created_at = datetime.now() | ||
72 | + g2.last_activity_at = datetime.now() | ||
73 | + g2.save() | ||
74 | + | ||
75 | + mr1 = GitlabMergeRequest() | ||
76 | + mr1.id = 1 | ||
77 | + mr1.iid = 1 | ||
78 | + mr1.project = g1 | ||
79 | + mr1.title = "Include plugin support" | ||
80 | + mr1.description = "Merge request for plugin support" | ||
81 | + mr1.state = "Closed" | ||
82 | + mr1.created_at = datetime.now() | ||
83 | + mr1.update_user(self.user.username) | ||
84 | + mr1.save() | ||
85 | + | ||
86 | + mr2 = GitlabMergeRequest() | ||
87 | + mr2.id = 2 | ||
88 | + mr2.iid = 1 | ||
89 | + mr2.project = g2 | ||
90 | + mr2.title = "Include test support" | ||
91 | + mr2.description = "Merge request for test support" | ||
92 | + mr2.state = "Closed" | ||
93 | + mr2.created_at = datetime.now() | ||
94 | + mr2.update_user(self.user.username) | ||
95 | + mr2.save() | ||
96 | + | ||
97 | + i1 = GitlabIssue() | ||
98 | + i1.id = 1 | ||
99 | + i1.iid = 1 | ||
100 | + i1.project = g1 | ||
101 | + i1.title = "Issue for colab" | ||
102 | + i1.description = "Issue reported to colab" | ||
103 | + i1.created_at = datetime.now() | ||
104 | + i1.state = "Open" | ||
105 | + i1.update_user(self.user.username) | ||
106 | + i1.save() | ||
107 | + | ||
108 | + i2 = GitlabIssue() | ||
109 | + i2.id = 2 | ||
110 | + i2.iid = 1 | ||
111 | + i2.project = g2 | ||
112 | + i2.title = "Issue for colab" | ||
113 | + i2.description = "Issue reported to colab" | ||
114 | + i2.created_at = datetime.now() | ||
115 | + i2.state = "Open" | ||
116 | + i2.update_user(self.user.username) | ||
117 | + i2.save() | ||
81 | 118 | ||
82 | c1 = GitlabComment() | 119 | c1 = GitlabComment() |
83 | - c1.iid = 1 | ||
84 | - c1.parent_id = mr.iid | ||
85 | - c1.project = g | 120 | + c1.id = 1 |
121 | + c1.parent_id = mr1.iid | ||
122 | + c1.project = g1 | ||
86 | c1.body = "Comment to merge request" | 123 | c1.body = "Comment to merge request" |
87 | c1.created_at = datetime.now() | 124 | c1.created_at = datetime.now() |
88 | c1.issue_comment = False | 125 | c1.issue_comment = False |
@@ -90,9 +127,9 @@ class GitlabTest(TestCase): | @@ -90,9 +127,9 @@ class GitlabTest(TestCase): | ||
90 | c1.save() | 127 | c1.save() |
91 | 128 | ||
92 | c2 = GitlabComment() | 129 | c2 = GitlabComment() |
93 | - c2.iid = 2 | ||
94 | - c2.parent_id = i.id | ||
95 | - c2.project = g | 130 | + c2.id = 2 |
131 | + c2.parent_id = i1.id | ||
132 | + c2.project = g1 | ||
96 | c2.body = "Comment to issue" | 133 | c2.body = "Comment to issue" |
97 | c2.created_at = datetime.now() | 134 | c2.created_at = datetime.now() |
98 | c2.issue_comment = True | 135 | c2.issue_comment = True |
colab/search/utils.py
@@ -15,11 +15,12 @@ from colab.accounts.utils import mailman | @@ -15,11 +15,12 @@ from colab.accounts.utils import mailman | ||
15 | 15 | ||
16 | def get_visible_threads_queryset(logged_user): | 16 | def get_visible_threads_queryset(logged_user): |
17 | queryset = Thread.objects | 17 | queryset = Thread.objects |
18 | - lists_for_user = [] | 18 | + listnames_for_user = [] |
19 | if logged_user: | 19 | if logged_user: |
20 | lists_for_user = mailman.get_user_mailinglists(logged_user) | 20 | lists_for_user = mailman.get_user_mailinglists(logged_user) |
21 | + listnames_for_user = mailman.extract_listname_from_list(lists_for_user) | ||
21 | 22 | ||
22 | - user_lists = Condition(mailinglist__name__in=lists_for_user) | 23 | + user_lists = Condition(mailinglist__name__in=listnames_for_user) |
23 | public_lists = Condition(mailinglist__is_private=False) | 24 | public_lists = Condition(mailinglist__is_private=False) |
24 | queryset = Thread.objects.filter(user_lists | public_lists) | 25 | queryset = Thread.objects.filter(user_lists | public_lists) |
25 | 26 | ||
@@ -28,6 +29,7 @@ def get_visible_threads_queryset(logged_user): | @@ -28,6 +29,7 @@ def get_visible_threads_queryset(logged_user): | ||
28 | 29 | ||
29 | def get_visible_threads(logged_user, filter_by_user=None): | 30 | def get_visible_threads(logged_user, filter_by_user=None): |
30 | thread_qs = get_visible_threads_queryset(logged_user) | 31 | thread_qs = get_visible_threads_queryset(logged_user) |
32 | + | ||
31 | if filter_by_user: | 33 | if filter_by_user: |
32 | message_qs = Message.objects.filter(thread__in=thread_qs) | 34 | message_qs = Message.objects.filter(thread__in=thread_qs) |
33 | messages = message_qs.filter( | 35 | messages = message_qs.filter( |
@@ -57,10 +59,8 @@ def get_collaboration_data(logged_user, filter_by_user=None): | @@ -57,10 +59,8 @@ def get_collaboration_data(logged_user, filter_by_user=None): | ||
57 | 59 | ||
58 | latest_results.extend(messages) | 60 | latest_results.extend(messages) |
59 | 61 | ||
60 | - app_names = settings.COLAB_APPS.keys() | ||
61 | - | ||
62 | - for app_name in app_names: | ||
63 | - module = importlib.import_module('{}.models'.format(app_name)) | 62 | + for app in settings.COLAB_APPS.values(): |
63 | + module = importlib.import_module('{}.models'.format(app.get('name'))) | ||
64 | 64 | ||
65 | for module_item_name in dir(module): | 65 | for module_item_name in dir(module): |
66 | module_item = getattr(module, module_item_name) | 66 | module_item = getattr(module, module_item_name) |
colab/settings.py
@@ -239,7 +239,7 @@ SUPER_ARCHIVES_EXCLUDE = [] | @@ -239,7 +239,7 @@ SUPER_ARCHIVES_EXCLUDE = [] | ||
239 | SUPER_ARCHIVES_LOCK_FILE = '/var/lock/colab/import_emails.lock' | 239 | SUPER_ARCHIVES_LOCK_FILE = '/var/lock/colab/import_emails.lock' |
240 | 240 | ||
241 | # Mailman API settings | 241 | # Mailman API settings |
242 | -MAILMAN_API_URL = 'http://localhost:8124' | 242 | +MAILMAN_API_URL = 'http://localhost:8124/v2/' |
243 | 243 | ||
244 | LOGIN_URL = '/user/login' | 244 | LOGIN_URL = '/user/login' |
245 | LOGIN_REDIRECT_URL = '/' | 245 | LOGIN_REDIRECT_URL = '/' |
@@ -266,8 +266,8 @@ for app_name, app in COLAB_APPS.items(): | @@ -266,8 +266,8 @@ for app_name, app in COLAB_APPS.items(): | ||
266 | if dep not in INSTALLED_APPS: | 266 | if dep not in INSTALLED_APPS: |
267 | INSTALLED_APPS += (dep,) | 267 | INSTALLED_APPS += (dep,) |
268 | 268 | ||
269 | - if app_name not in INSTALLED_APPS: | ||
270 | - INSTALLED_APPS += (app_name,) | 269 | + if app.get('name') not in INSTALLED_APPS: |
270 | + INSTALLED_APPS += (app.get('name'),) | ||
271 | 271 | ||
272 | if 'middlewares' in app: | 272 | if 'middlewares' in app: |
273 | for middleware in app.get('middlewares'): | 273 | for middleware in app.get('middlewares'): |
colab/super_archives/fixtures/mailinglistdata.json
@@ -6,23 +6,23 @@ | @@ -6,23 +6,23 @@ | ||
6 | "twitter": null, | 6 | "twitter": null, |
7 | "is_staff": false, | 7 | "is_staff": false, |
8 | "user_permissions": [ | 8 | "user_permissions": [ |
9 | - | 9 | + |
10 | ], | 10 | ], |
11 | "date_joined": "2015-02-24T21:10:35.004Z", | 11 | "date_joined": "2015-02-24T21:10:35.004Z", |
12 | "google_talk": null, | 12 | "google_talk": null, |
13 | - "first_name": "Gust", | 13 | + "first_name": "John", |
14 | "is_superuser": false, | 14 | "is_superuser": false, |
15 | "last_login": "2015-02-26T17:56:13.378Z", | 15 | "last_login": "2015-02-26T17:56:13.378Z", |
16 | "verification_hash": null, | 16 | "verification_hash": null, |
17 | "role": null, | 17 | "role": null, |
18 | - "email": "gustmax@hotmail.com", | ||
19 | - "username": "gustmax", | 18 | + "email": "johndoe@example.com", |
19 | + "username": "johndoe", | ||
20 | "bio": null, | 20 | "bio": null, |
21 | "needs_update": false, | 21 | "needs_update": false, |
22 | "is_active": true, | 22 | "is_active": true, |
23 | "facebook": null, | 23 | "facebook": null, |
24 | "groups": [ | 24 | "groups": [ |
25 | - | 25 | + |
26 | ], | 26 | ], |
27 | "password": "pbkdf2_sha256$12000$ez83ccNOUQZk$vYT/QcYMukXZ7D7L1qQPyYlzCUEEEF20J7/Xjef0Rqg=", | 27 | "password": "pbkdf2_sha256$12000$ez83ccNOUQZk$vYT/QcYMukXZ7D7L1qQPyYlzCUEEEF20J7/Xjef0Rqg=", |
28 | "institution": null, | 28 | "institution": null, |
@@ -37,7 +37,7 @@ | @@ -37,7 +37,7 @@ | ||
37 | "real_name": "", | 37 | "real_name": "", |
38 | "user": 1, | 38 | "user": 1, |
39 | "md5": "ed8f47ae6048f8d4456c0554578f53ff", | 39 | "md5": "ed8f47ae6048f8d4456c0554578f53ff", |
40 | - "address": "gustmax@hotmail.com" | 40 | + "address": "johndoe@example.com" |
41 | }, | 41 | }, |
42 | "model": "super_archives.emailaddress", | 42 | "model": "super_archives.emailaddress", |
43 | "pk": 1 | 43 | "pk": 1 |
colab/super_archives/models.py
@@ -41,11 +41,17 @@ class EmailAddressValidation(models.Model): | @@ -41,11 +41,17 @@ class EmailAddressValidation(models.Model): | ||
41 | def create(cls, address, user): | 41 | def create(cls, address, user): |
42 | email_address_validation = cls.objects.create(address=address, | 42 | email_address_validation = cls.objects.create(address=address, |
43 | user=user) | 43 | user=user) |
44 | - email.send_verification_email(email_address_validation.address, | ||
45 | - email_address_validation.user, | ||
46 | - email_address_validation.validation_key) | ||
47 | return email_address_validation | 44 | return email_address_validation |
48 | 45 | ||
46 | + @classmethod | ||
47 | + def verify_email(cls, email_address_validation, verification_url): | ||
48 | + return email.send_verification_email( | ||
49 | + email_address_validation.address, | ||
50 | + email_address_validation.user, | ||
51 | + email_address_validation.validation_key, | ||
52 | + verification_url | ||
53 | + ) | ||
54 | + | ||
49 | 55 | ||
50 | class EmailAddress(models.Model): | 56 | class EmailAddress(models.Model): |
51 | user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, | 57 | user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, |
colab/super_archives/templates/superarchives/emails/email_verification.txt
1 | {% load i18n %} | 1 | {% load i18n %} |
2 | {% blocktrans with fullname=user.get_full_name|title username=user.username|lower %}Hey, we want to verify that you are indeed "{{ fullname }} ({{ username }})". If that's the case, please follow the link below:{% endblocktrans %} | 2 | {% blocktrans with fullname=user.get_full_name|title username=user.username|lower %}Hey, we want to verify that you are indeed "{{ fullname }} ({{ username }})". If that's the case, please follow the link below:{% endblocktrans %} |
3 | 3 | ||
4 | -{{ SITE_URL }}{% url 'archive_email_view' key %} | 4 | +{{ verification_url }} |
5 | 5 | ||
6 | {% blocktrans with username=user.username %}If you're not {{ username }} or didn't request verification you can ignore this email.{% endblocktrans %} | 6 | {% blocktrans with username=user.username %}If you're not {{ username }} or didn't request verification you can ignore this email.{% endblocktrans %} |
colab/super_archives/tests/test_privatelist.py
@@ -2,7 +2,7 @@ | @@ -2,7 +2,7 @@ | ||
2 | import mock | 2 | import mock |
3 | 3 | ||
4 | from colab.accounts.utils import mailman | 4 | from colab.accounts.utils import mailman |
5 | -from django.test import TestCase, Client | 5 | +from django.test import TestCase, Client |
6 | 6 | ||
7 | 7 | ||
8 | class ArchivesViewTest(TestCase): | 8 | class ArchivesViewTest(TestCase): |
@@ -13,11 +13,14 @@ class ArchivesViewTest(TestCase): | @@ -13,11 +13,14 @@ class ArchivesViewTest(TestCase): | ||
13 | self.client = Client() | 13 | self.client = Client() |
14 | 14 | ||
15 | def authenticate_user(self): | 15 | def authenticate_user(self): |
16 | - self.client.login(username='gustmax', password='1234') | 16 | + self.client.login(username='johndoe', password='1234') |
17 | 17 | ||
18 | def test_see_only_private_list_if_member(self): | 18 | def test_see_only_private_list_if_member(self): |
19 | mailman.get_user_mailinglists = mock.Mock( | 19 | mailman.get_user_mailinglists = mock.Mock( |
20 | + return_value="[{'listname': 'privatelist'}]") | ||
21 | + mailman.extract_listname_from_list = mock.Mock( | ||
20 | return_value="['privatelist']") | 22 | return_value="['privatelist']") |
23 | + mailman.list_users = mock.Mock(return_value="['johndoe@example.com']") | ||
21 | 24 | ||
22 | self.authenticate_user() | 25 | self.authenticate_user() |
23 | request = self.client.get('/archives/thread/') | 26 | request = self.client.get('/archives/thread/') |
@@ -26,7 +29,7 @@ class ArchivesViewTest(TestCase): | @@ -26,7 +29,7 @@ class ArchivesViewTest(TestCase): | ||
26 | 29 | ||
27 | self.assertEqual('lista', list_data[0][0]) | 30 | self.assertEqual('lista', list_data[0][0]) |
28 | self.assertEqual('privatelist', list_data[1][0]) | 31 | self.assertEqual('privatelist', list_data[1][0]) |
29 | - self.assertEqual(2, len(list_data)) | 32 | + self.assertEqual(2, len(list_data)) |
30 | 33 | ||
31 | def test_see_only_public_if_not_logged_in(self): | 34 | def test_see_only_public_if_not_logged_in(self): |
32 | request = self.client.get('/archives/thread/') | 35 | request = self.client.get('/archives/thread/') |
@@ -34,10 +37,12 @@ class ArchivesViewTest(TestCase): | @@ -34,10 +37,12 @@ class ArchivesViewTest(TestCase): | ||
34 | list_data = request.context['lists'] | 37 | list_data = request.context['lists'] |
35 | 38 | ||
36 | self.assertEqual('lista', list_data[0][0]) | 39 | self.assertEqual('lista', list_data[0][0]) |
37 | - self.assertEqual(1, len(list_data)) | 40 | + self.assertEqual(1, len(list_data)) |
38 | 41 | ||
39 | def test_see_private_thread_in_dashboard_if_member(self): | 42 | def test_see_private_thread_in_dashboard_if_member(self): |
40 | mailman.get_user_mailinglists = mock.Mock( | 43 | mailman.get_user_mailinglists = mock.Mock( |
44 | + return_value="[{'listname': 'privatelist'}]") | ||
45 | + mailman.extract_listname_from_list = mock.Mock( | ||
41 | return_value="['privatelist']") | 46 | return_value="['privatelist']") |
42 | 47 | ||
43 | self.authenticate_user() | 48 | self.authenticate_user() |
@@ -59,7 +64,7 @@ class ArchivesViewTest(TestCase): | @@ -59,7 +64,7 @@ class ArchivesViewTest(TestCase): | ||
59 | self.assertEqual(1, len(hottest_threads)) | 64 | self.assertEqual(1, len(hottest_threads)) |
60 | 65 | ||
61 | def test_dont_see_private_threads_in_profile_if_logged_out(self): | 66 | def test_dont_see_private_threads_in_profile_if_logged_out(self): |
62 | - request = self.client.get('/account/gustmax') | 67 | + request = self.client.get('/account/johndoe') |
63 | 68 | ||
64 | emails = request.context['emails'] | 69 | emails = request.context['emails'] |
65 | 70 |
colab/super_archives/utils/email.py
@@ -10,11 +10,11 @@ def colab_send_email(subject, message, to): | @@ -10,11 +10,11 @@ def colab_send_email(subject, message, to): | ||
10 | return mail.send_mail(subject, message, from_email, [to]) | 10 | return mail.send_mail(subject, message, from_email, [to]) |
11 | 11 | ||
12 | 12 | ||
13 | -def send_verification_email(to, user, validation_key): | 13 | +def send_verification_email(to, user, validation_key, verification_url): |
14 | subject = _('Please verify your email ') + u'{}'.format(to) | 14 | subject = _('Please verify your email ') + u'{}'.format(to) |
15 | msg_tmpl = \ | 15 | msg_tmpl = \ |
16 | loader.get_template('superarchives/emails/email_verification.txt') | 16 | loader.get_template('superarchives/emails/email_verification.txt') |
17 | message = msg_tmpl.render(Context({'to': to, 'user': user, | 17 | message = msg_tmpl.render(Context({'to': to, 'user': user, |
18 | - 'key': validation_key, | ||
19 | - 'SITE_URL': settings.SITE_URL})) | 18 | + 'verification_url': verification_url |
19 | + })) | ||
20 | return colab_send_email(subject, message, to) | 20 | return colab_send_email(subject, message, to) |
colab/super_archives/views.py
@@ -9,6 +9,7 @@ import requests | @@ -9,6 +9,7 @@ import requests | ||
9 | from django import http | 9 | from django import http |
10 | from django.conf import settings | 10 | from django.conf import settings |
11 | from django.contrib import messages | 11 | from django.contrib import messages |
12 | +from django.core.urlresolvers import reverse | ||
12 | from django.db import IntegrityError | 13 | from django.db import IntegrityError |
13 | from django.views.generic import View | 14 | from django.views.generic import View |
14 | from django.utils.translation import ugettext as _ | 15 | from django.utils.translation import ugettext as _ |
@@ -32,17 +33,23 @@ class ThreadView(View): | @@ -32,17 +33,23 @@ class ThreadView(View): | ||
32 | thread = get_object_or_404(Thread, subject_token=thread_token, | 33 | thread = get_object_or_404(Thread, subject_token=thread_token, |
33 | mailinglist__name=mailinglist) | 34 | mailinglist__name=mailinglist) |
34 | 35 | ||
35 | - # TODO: Refactor this code | ||
36 | - # Use local flag is_private instead of always check the API!! | ||
37 | - all_privates = dict(mailman.all_lists(private=True)) | ||
38 | - if all_privates[thread.mailinglist.name]: | 36 | + all_privates = [] |
37 | + all_privates.extend( | ||
38 | + [mlist.get('listname') | ||
39 | + for mlist in mailman.all_lists() | ||
40 | + if mlist.get('archive_private')] | ||
41 | + ) | ||
42 | + | ||
43 | + if all_privates.count(thread.mailinglist.name): | ||
39 | if not request.user.is_authenticated(): | 44 | if not request.user.is_authenticated(): |
40 | raise PermissionDenied | 45 | raise PermissionDenied |
41 | else: | 46 | else: |
42 | user = User.objects.get(username=request.user) | 47 | user = User.objects.get(username=request.user) |
43 | emails = user.emails.values_list('address', flat=True) | 48 | emails = user.emails.values_list('address', flat=True) |
44 | lists_for_user = mailman.get_user_mailinglists(user) | 49 | lists_for_user = mailman.get_user_mailinglists(user) |
45 | - if thread.mailinglist.name not in lists_for_user: | 50 | + listnames_for_user = mailman.extract_listname_from_list( |
51 | + lists_for_user) | ||
52 | + if thread.mailinglist.name not in listnames_for_user: | ||
46 | raise PermissionDenied | 53 | raise PermissionDenied |
47 | 54 | ||
48 | thread.hit(request) | 55 | thread.hit(request) |
@@ -144,13 +151,16 @@ class ThreadDashboardView(View): | @@ -144,13 +151,16 @@ class ThreadDashboardView(View): | ||
144 | 151 | ||
145 | context['lists'] = [] | 152 | context['lists'] = [] |
146 | 153 | ||
147 | - lists_for_user = [] | 154 | + listnames_for_user = [] |
148 | if request.user.is_authenticated(): | 155 | if request.user.is_authenticated(): |
149 | user = User.objects.get(username=request.user) | 156 | user = User.objects.get(username=request.user) |
150 | lists_for_user = mailman.get_user_mailinglists(user) | 157 | lists_for_user = mailman.get_user_mailinglists(user) |
158 | + listnames_for_user = mailman.extract_listname_from_list( | ||
159 | + lists_for_user) | ||
151 | 160 | ||
152 | for list_ in MailingList.objects.order_by('name'): | 161 | for list_ in MailingList.objects.order_by('name'): |
153 | - if list_.name not in all_privates or list_.name in lists_for_user: | 162 | + if list_.name not in all_privates\ |
163 | + or list_.name in listnames_for_user: | ||
154 | context['lists'].append(( | 164 | context['lists'].append(( |
155 | list_.name, | 165 | list_.name, |
156 | mailman.get_list_description(list_.name), | 166 | mailman.get_list_description(list_.name), |
@@ -177,7 +187,7 @@ class EmailView(View): | @@ -177,7 +187,7 @@ class EmailView(View): | ||
177 | except EmailAddressValidation.DoesNotExist: | 187 | except EmailAddressValidation.DoesNotExist: |
178 | messages.error(request, _('The email address you are trying to ' | 188 | messages.error(request, _('The email address you are trying to ' |
179 | 'verify either has already been verified' | 189 | 'verify either has already been verified' |
180 | - 'or does not exist.')) | 190 | + ' or does not exist.')) |
181 | return redirect('/') | 191 | return redirect('/') |
182 | 192 | ||
183 | try: | 193 | try: |
@@ -289,8 +299,11 @@ class EmailValidationView(View): | @@ -289,8 +299,11 @@ class EmailValidationView(View): | ||
289 | raise http.Http404 | 299 | raise http.Http404 |
290 | 300 | ||
291 | try: | 301 | try: |
292 | - send_verification_email(email_addr, email.user, | ||
293 | - email.validation_key) | 302 | + location = reverse('archive_email_view', |
303 | + kwargs={'key': email.validation_key}) | ||
304 | + verification_url = request.build_absolute_uri(location) | ||
305 | + send_verification_email(request, email_addr, email.user, | ||
306 | + email.validation_key, verification_url) | ||
294 | except smtplib.SMTPException: | 307 | except smtplib.SMTPException: |
295 | logging.exception('Error sending validation email') | 308 | logging.exception('Error sending validation email') |
296 | return http.HttpResponseServerError() | 309 | return http.HttpResponseServerError() |
colab/utils/conf.py
@@ -95,6 +95,7 @@ def load_colab_apps(): | @@ -95,6 +95,7 @@ def load_colab_apps(): | ||
95 | return {'COLAB_APPS': COLAB_APPS} | 95 | return {'COLAB_APPS': COLAB_APPS} |
96 | 96 | ||
97 | for file_name in os.listdir(plugins_dir): | 97 | for file_name in os.listdir(plugins_dir): |
98 | + app_name = "" | ||
98 | file_module = file_name.split('.')[0] | 99 | file_module = file_name.split('.')[0] |
99 | 100 | ||
100 | logger.info('Loaded plugin settings: %s%s', plugins_dir, file_name) | 101 | logger.info('Loaded plugin settings: %s%s', plugins_dir, file_name) |
@@ -104,7 +105,7 @@ def load_colab_apps(): | @@ -104,7 +105,7 @@ def load_colab_apps(): | ||
104 | app_name = file_name | 105 | app_name = file_name |
105 | 106 | ||
106 | elif file_name.endswith('.py'): | 107 | elif file_name.endswith('.py'): |
107 | - app_name = py_settings_d.get('name') | 108 | + app_name = py_settings_d.get('name').split('.')[-1] |
108 | 109 | ||
109 | if not app_name: | 110 | if not app_name: |
110 | logger.warning("Plugin missing name variable (%s)", file_name) | 111 | logger.warning("Plugin missing name variable (%s)", file_name) |
@@ -121,7 +122,7 @@ def load_colab_apps(): | @@ -121,7 +122,7 @@ def load_colab_apps(): | ||
121 | 122 | ||
122 | fields = ['verbose_name', 'upstream', 'urls', | 123 | fields = ['verbose_name', 'upstream', 'urls', |
123 | 'menu_urls', 'middlewares', 'dependencies', | 124 | 'menu_urls', 'middlewares', 'dependencies', |
124 | - 'context_processors', 'private_token'] | 125 | + 'context_processors', 'private_token', 'name'] |
125 | 126 | ||
126 | for key in fields: | 127 | for key in fields: |
127 | value = py_settings_d.get(key) | 128 | value = py_settings_d.get(key) |