Commit a2e34e57bdc5a61f9f47a4098b962d7e3245a8d3
Exists in
master
and in
31 other branches
Merge remote-tracking branch 'origin/remove-core-deps'
Showing
67 changed files
with
125 additions
and
1686 deletions
Show diff stats
colab/accounts/auth.py
colab/accounts/forms.py
... | ... | @@ -16,8 +16,6 @@ from django.utils.text import capfirst |
16 | 16 | from django.utils.translation import ugettext_lazy as _ |
17 | 17 | from django.utils.safestring import mark_safe |
18 | 18 | |
19 | -from conversejs.models import XMPPAccount | |
20 | - | |
21 | 19 | |
22 | 20 | from .utils.validators import validate_social_account |
23 | 21 | from .utils import mailman |
... | ... | @@ -152,42 +150,6 @@ class ListsForm(forms.Form): |
152 | 150 | choices=LISTS_NAMES) |
153 | 151 | |
154 | 152 | |
155 | -class ChangeXMPPPasswordForm(forms.ModelForm): | |
156 | - password1 = forms.CharField(label=_("Password"), | |
157 | - widget=forms.PasswordInput) | |
158 | - password2 = forms.CharField(label=_("Password confirmation"), | |
159 | - widget=forms.PasswordInput, | |
160 | - help_text=_(("Enter the same password as above" | |
161 | - ", for verification."))) | |
162 | - | |
163 | - class Meta: | |
164 | - model = XMPPAccount | |
165 | - fields = ('password1', 'password2') | |
166 | - | |
167 | - def __init__(self, *args, **kwargs): | |
168 | - super(ChangeXMPPPasswordForm, self).__init__(*args, **kwargs) | |
169 | - | |
170 | - for field_name, field in self.fields.items(): | |
171 | - # Adds form-control class to all form fields | |
172 | - field.widget.attrs.update({'class': 'form-control'}) | |
173 | - | |
174 | - def clean_password2(self): | |
175 | - password1 = self.cleaned_data.get("password1") | |
176 | - password2 = self.cleaned_data.get("password2") | |
177 | - if password1 and password2 and password1 != password2: | |
178 | - raise forms.ValidationError( | |
179 | - _("Password mismatch"), | |
180 | - code='password_mismatch', | |
181 | - ) | |
182 | - return password2 | |
183 | - | |
184 | - def save(self, commit=True): | |
185 | - self.instance.password = self.cleaned_data['password2'] | |
186 | - if commit: | |
187 | - self.instance.save() | |
188 | - return self.instance | |
189 | - | |
190 | - | |
191 | 153 | class UserCreationForm(UserForm): |
192 | 154 | """ |
193 | 155 | A form that creates a user, with no privileges, from the given username and | ... | ... |
colab/accounts/middleware.py
... | ... | @@ -1,24 +0,0 @@ |
1 | - | |
2 | -from django.shortcuts import redirect | |
3 | -from django.conf import settings | |
4 | - | |
5 | -VIEW_NAMES_ALLOWED = ('signup', 'Logout') | |
6 | - | |
7 | - | |
8 | -class UserRegisterMiddleware(object): | |
9 | - | |
10 | - def process_view(self, request, view_func, view_args, view_kwargs): | |
11 | - if not settings.BROWSERID_ENABLED: | |
12 | - return | |
13 | - | |
14 | - if request.is_ajax(): | |
15 | - return | |
16 | - | |
17 | - if not request.user.is_authenticated(): | |
18 | - return | |
19 | - | |
20 | - if not request.user.needs_update: | |
21 | - return | |
22 | - | |
23 | - if view_func.__name__ not in VIEW_NAMES_ALLOWED: | |
24 | - return redirect('signup') |
colab/accounts/models.py
... | ... | @@ -47,13 +47,6 @@ class User(AbstractUser): |
47 | 47 | |
48 | 48 | objects = ColabUserManager() |
49 | 49 | |
50 | - def check_password(self, raw_password): | |
51 | - | |
52 | - if self.xmpp.exists() and raw_password == self.xmpp.first().password: | |
53 | - return True | |
54 | - | |
55 | - return super(User, self).check_password(raw_password) | |
56 | - | |
57 | 50 | def get_absolute_url(self): |
58 | 51 | return reverse('user_profile', kwargs={'username': self.username}) |
59 | 52 | ... | ... |
colab/accounts/search_indexes.py
1 | 1 | # -*- coding: utf-8 -*- |
2 | 2 | |
3 | 3 | from haystack import indexes |
4 | -# from django.db.models import Count | |
5 | - | |
6 | -from colab.badger.utils import get_users_counters | |
7 | 4 | from .models import User |
8 | 5 | |
9 | 6 | |
... | ... | @@ -26,30 +23,13 @@ class UserIndex(indexes.SearchIndex, indexes.Indexable): |
26 | 23 | stored=False) |
27 | 24 | webpage = indexes.CharField(model_attr='webpage', null=True, stored=False) |
28 | 25 | message_count = indexes.IntegerField(stored=False) |
29 | - # changeset_count = indexes.IntegerField(stored=False) | |
30 | - # ticket_count = indexes.IntegerField(stored=False) | |
31 | - # wiki_count = indexes.IntegerField(stored=False) | |
32 | - contribution_count = indexes.IntegerField(stored=False) | |
33 | 26 | |
34 | 27 | def get_model(self): |
35 | 28 | return User |
36 | 29 | |
37 | - @property | |
38 | - def badge_counters(self): | |
39 | - if not hasattr(self, '_badge_counters'): | |
40 | - self._badge_counters = get_users_counters() | |
41 | - return self._badge_counters | |
42 | - | |
43 | 30 | def prepare(self, obj): |
44 | 31 | prepared_data = super(UserIndex, self).prepare(obj) |
45 | 32 | |
46 | - prepared_data['contribution_count'] = sum(( | |
47 | - self.prepared_data['message_count'], | |
48 | - # self.prepared_data['changeset_count'], | |
49 | - # self.prepared_data['ticket_count'], | |
50 | - # self.prepared_data['wiki_count'] | |
51 | - )) | |
52 | - | |
53 | 33 | return prepared_data |
54 | 34 | |
55 | 35 | def prepare_description(self, obj): |
... | ... | @@ -63,17 +43,5 @@ class UserIndex(indexes.SearchIndex, indexes.Indexable): |
63 | 43 | def prepare_type(self, obj): |
64 | 44 | return u'user' |
65 | 45 | |
66 | - def prepare_message_count(self, obj): | |
67 | - return self.badge_counters[obj.username]['messages'] | |
68 | - | |
69 | - # def prepare_changeset_count(self, obj): | |
70 | - # return self.badge_counters[obj.username]['revisions'] | |
71 | - | |
72 | - # def prepare_ticket_count(self, obj): | |
73 | - # return self.badge_counters[obj.username]['tickets'] | |
74 | - | |
75 | - # def prepare_wiki_count(self, obj): | |
76 | - # return self.badge_counters[obj.username]['wikis'] | |
77 | - | |
78 | 46 | def index_queryset(self, using=None): |
79 | 47 | return self.get_model().objects.filter(is_active=True) | ... | ... |
colab/accounts/templates/accounts/change_password.html
... | ... | @@ -1,21 +0,0 @@ |
1 | -{% extends "base.html" %} | |
2 | -{% load i18n %} | |
3 | - | |
4 | -{% block main-content %} | |
5 | -<form method="POST" role="form"> | |
6 | - {% csrf_token %} | |
7 | - <div class="row"> | |
8 | - <h2>{% trans "Change XMPP Client and SVN Password" %}</h2> | |
9 | - <div class="col-lg-4 col-md-4 col-sm-12 col-xs-12"> | |
10 | - {% for field in form %} | |
11 | - <div class="form-group required{% if field.errors %} alert alert-danger has-error{% endif %}"> | |
12 | - <label for="{{ field.name }}" class="control-label">{{ field.label }}</label> | |
13 | - {{ field }} | |
14 | - {{ field.errors }} | |
15 | - </div> | |
16 | - {% endfor %} | |
17 | - <button class="btn btn-primary">{% trans "Change Password" %}</button> | |
18 | - </div> | |
19 | - </div> | |
20 | -</form> | |
21 | -{% endblock %} |
colab/accounts/templates/accounts/login.html
... | ... | @@ -1,12 +0,0 @@ |
1 | -{% extends 'base.html' %} | |
2 | -{% load browserid i18n %} | |
3 | - | |
4 | -{% block main-content %} | |
5 | - <br><br><br> | |
6 | - <div class="col-lg-12 text-center"> | |
7 | - <p>{% trans 'To login please click in the link below:'%}</p> | |
8 | - {% trans 'Login' as login_text %} | |
9 | - {% browserid_login text=login_text link_class='btn btn-primary btn-lg' %} | |
10 | - </div> | |
11 | - <br><br><br> | |
12 | -{% endblock %} |
colab/accounts/templates/accounts/user_update_form.html
... | ... | @@ -178,40 +178,19 @@ $(function() { |
178 | 178 | </div> |
179 | 179 | </div> |
180 | 180 | </div> |
181 | - {% if not BROWSERID_ENABLED %} | |
182 | - <div class="col-lg-4 col-md-5 col-sm-12 col-xm-12"> | |
183 | - <div class="panel panel-default"> | |
184 | - <div class="panel-heading"> | |
185 | - <h3 class="panel-title"> | |
186 | - {% trans 'Change Password' %} | |
187 | - </h3> | |
188 | - </div> | |
189 | - <div class="panel-body"> | |
190 | - <a href="{% url 'password_change' %}" class="btn btn-default btn-primary pull-right btn-block">{% trans "Change Password" %}</a> | |
191 | - </div> | |
181 | + <div class="col-lg-4 col-md-5 col-sm-12 col-xm-12"> | |
182 | + <div class="panel panel-default"> | |
183 | + <div class="panel-heading"> | |
184 | + <h3 class="panel-title"> | |
185 | + {% trans 'Change Password' %} | |
186 | + </h3> | |
192 | 187 | </div> |
193 | - </div> | |
194 | - {% endif %} | |
195 | - </div> | |
196 | - {% if CONVERSEJS_ENABLED %} | |
197 | - <div class="row"> | |
198 | - <div class="col-lg-12"> | |
199 | - <div class="panel panel-default"> | |
200 | - <div class="panel-heading"> | |
201 | - <h3 class="panel-title"> | |
202 | - {% trans 'Change Password' %} | |
203 | - </h3> | |
204 | - </div> | |
205 | - <div class="panel-body"> | |
206 | - <div class="form-group"> | |
207 | - {% trans "This feature is available only for those who need to change the password for some reason as having an old user with the same username, forgot your password to commit, usage of other XMPP Client for connection. Usually, you won't need to change this password. Only change it if you are sure about what you are doing." %} | |
188 | + <div class="panel-body"> | |
189 | + <a href="{% url 'password_change' %}" class="btn btn-default btn-primary pull-right btn-block">{% trans "Change Password" %}</a> | |
208 | 190 | </div> |
209 | - <a href="{% url 'change_password' %}" class="btn btn-default pull-right"><span class="icon-warning-sign"></span> {% trans "Change Password" %}</a> | |
210 | 191 | </div> |
211 | 192 | </div> |
212 | - </div> | |
213 | 193 | </div> |
214 | - {% endif %} | |
215 | 194 | <div class="row"> |
216 | 195 | <div class="submit"> |
217 | 196 | <button type="submit" class="btn btn-primary btn-lg btn-block">{% trans "Update" %}</button> | ... | ... |
colab/accounts/tests/test_view_signup.py
... | ... | @@ -21,13 +21,6 @@ class TestSignUpView(TestCase): |
21 | 21 | "usertest@colab.com.br", "123colab4") |
22 | 22 | return user |
23 | 23 | |
24 | - def test_user_not_authenticated(self): | |
25 | - with self.settings(BROWSERID_ENABLED=True): | |
26 | - response = self.client.get("/account/register") | |
27 | - self.assertEquals(302, response.status_code) | |
28 | - url = "http://testserver/account/login" | |
29 | - self.assertEquals(url, response.url) | |
30 | - | |
31 | 24 | def test_user_authenticated_and_unregistered(self): |
32 | 25 | self.client.login(username="usertestcolab", password="123colab4") |
33 | 26 | response = self.client.get("/account/register/") | ... | ... |
colab/accounts/urls.py
... | ... | @@ -2,56 +2,44 @@ |
2 | 2 | from django.conf import settings |
3 | 3 | from django.conf.urls import patterns, url |
4 | 4 | |
5 | -from .views import (UserProfileDetailView, UserProfileUpdateView, LoginView, | |
6 | - ManageUserSubscriptionsView, ChangeXMPPPasswordView) | |
5 | +from .views import (UserProfileDetailView, UserProfileUpdateView, | |
6 | + ManageUserSubscriptionsView) | |
7 | 7 | |
8 | 8 | from colab.accounts import views |
9 | 9 | from django.contrib.auth import views as auth_views |
10 | 10 | |
11 | 11 | |
12 | -BROWSERID_ENABLED = getattr(settings, 'BROWSERID_ENABLED', False) | |
12 | +urlpatterns = patterns('', | |
13 | + url(r'^login/?$', 'django.contrib.auth.views.login', name='login'), | |
13 | 14 | |
15 | + url(r'^logout/?$', 'django.contrib.auth.views.logout', | |
16 | + {'next_page':'home'}, name='logout'), | |
14 | 17 | |
15 | -if not BROWSERID_ENABLED: | |
16 | - urlpatterns = patterns('', | |
17 | - url(r'^login/?$', 'django.contrib.auth.views.login', name='login'), | |
18 | + url(r'^password-reset-done/?$', 'colab.accounts.views.password_reset_done_custom', | |
19 | + name="password_reset_done"), | |
20 | + url(r'^password-reset-complete/$', 'colab.accounts.views.password_reset_complete_custom', | |
21 | + name="password_reset_complete"), | |
18 | 22 | |
19 | - url(r'^logout/?$', 'django.contrib.auth.views.logout', | |
20 | - {'next_page':'home'}, name='logout'), | |
23 | + url(r'^password-reset-confirm/(?P<uidb64>[0-9A-Za-z]+)-(?P<token>.+)/$', | |
24 | + auth_views.password_reset_confirm, | |
25 | + {'template_name':'registration/password_reset_confirm_custom.html'}, | |
26 | + name="password_reset_confirm"), | |
21 | 27 | |
22 | - url(r'^password-reset-done/?$', 'colab.accounts.views.password_reset_done_custom', | |
23 | - name="password_reset_done"), | |
24 | - url(r'^password-reset-complete/$', 'colab.accounts.views.password_reset_complete_custom', | |
25 | - name="password_reset_complete"), | |
28 | + url(r'^password-reset/?$', auth_views.password_reset, | |
29 | + {'template_name':'registration/password_reset_form_custom.html'}, | |
30 | + name="password_reset"), | |
26 | 31 | |
27 | - url(r'^password-reset-confirm/(?P<uidb64>[0-9A-Za-z]+)-(?P<token>.+)/$', | |
28 | - auth_views.password_reset_confirm, | |
29 | - {'template_name':'registration/password_reset_confirm_custom.html'}, | |
30 | - name="password_reset_confirm"), | |
32 | + url(r'^change-password/?$',auth_views.password_change, | |
33 | + {'template_name':'registration/password_change_form_custom.html'}, | |
34 | + name='password_change'), | |
31 | 35 | |
32 | - url(r'^password-reset/?$', auth_views.password_reset, | |
33 | - {'template_name':'registration/password_reset_form_custom.html'}, | |
34 | - name="password_reset"), | |
35 | - | |
36 | - url(r'^change-password/?$',auth_views.password_change, | |
37 | - {'template_name':'registration/password_change_form_custom.html'}, | |
38 | - name='password_change'), | |
39 | - | |
40 | - url(r'^change-password-done/?$', | |
41 | - 'colab.accounts.views.password_changed', name='password_change_done'), | |
42 | - ) | |
43 | -else: | |
44 | - urlpatterns = patterns('', | |
45 | - url(r'^login/?$', LoginView.as_view(), name='login'), | |
46 | - ) | |
36 | + url(r'^change-password-done/?$', | |
37 | + 'colab.accounts.views.password_changed', name='password_change_done'), | |
38 | +) | |
47 | 39 | |
48 | 40 | urlpatterns += patterns('', |
49 | 41 | url(r'^register/?$', 'colab.accounts.views.signup', name='signup'), |
50 | 42 | |
51 | -#FIXME Configure for XMPP | |
52 | -# url(r'^change-password/$', | |
53 | -# ChangeXMPPPasswordView.as_view(), name='change_password'), | |
54 | - | |
55 | 43 | url(r'^(?P<username>[\w@+.-]+)/?$', |
56 | 44 | UserProfileDetailView.as_view(), name='user_profile'), |
57 | 45 | ... | ... |
colab/accounts/views.py
... | ... | @@ -13,23 +13,16 @@ from django.core.exceptions import PermissionDenied |
13 | 13 | from django.views.generic import DetailView, UpdateView, TemplateView |
14 | 14 | from django.http import Http404 |
15 | 15 | |
16 | -from conversejs import xmpp | |
17 | -from conversejs.models import XMPPAccount | |
18 | - | |
19 | 16 | from colab.super_archives.models import (EmailAddress, |
20 | 17 | EmailAddressValidation) |
21 | 18 | from colab.search.utils import get_collaboration_data, get_visible_threads |
22 | 19 | from colab.accounts.models import User |
23 | 20 | |
24 | 21 | from .forms import (UserCreationForm, UserForm, ListsForm, |
25 | - UserUpdateForm, ChangeXMPPPasswordForm) | |
22 | + UserUpdateForm) | |
26 | 23 | from .utils import mailman |
27 | 24 | |
28 | 25 | |
29 | -class LoginView(TemplateView): | |
30 | - template_name = "accounts/login.html" | |
31 | - | |
32 | - | |
33 | 26 | class UserProfileBaseMixin(object): |
34 | 27 | model = get_user_model() |
35 | 28 | slug_field = 'username' |
... | ... | @@ -52,11 +45,6 @@ class UserProfileUpdateView(UserProfileBaseMixin, UpdateView): |
52 | 45 | |
53 | 46 | return obj |
54 | 47 | |
55 | - def get_context_data(self, **kwargs): | |
56 | - context = super(UserProfileUpdateView, self).get_context_data(**kwargs) | |
57 | - context['CONVERSEJS_ENABLED'] = getattr(settings, 'CONVERSEJS_ENABLED') | |
58 | - return context | |
59 | - | |
60 | 48 | |
61 | 49 | class UserProfileDetailView(UserProfileBaseMixin, DetailView): |
62 | 50 | template_name = 'accounts/user_detail.html' |
... | ... | @@ -94,37 +82,19 @@ class UserProfileDetailView(UserProfileBaseMixin, DetailView): |
94 | 82 | |
95 | 83 | |
96 | 84 | def signup(request): |
97 | - BROWSERID_ENABLED = getattr(settings, 'BROWSERID_ENABLED', False) | |
98 | - | |
99 | - if BROWSERID_ENABLED: | |
100 | - # If the user is not authenticated, redirect to login | |
101 | - if not request.user.is_authenticated(): | |
102 | - return redirect('login') | |
103 | 85 | |
104 | 86 | if request.user.is_authenticated(): |
105 | - # If the user doesn't need to update its main data, | |
106 | - # redirect to its profile | |
107 | - # It happens when user is created by browserid | |
108 | - # and didn't set his/her main data | |
109 | 87 | if not request.user.needs_update: |
110 | 88 | return redirect('user_profile', username=request.user.username) |
111 | 89 | |
112 | - # If the user is authenticated in Persona, but not in the Colab then he | |
113 | - # will be redirected to the register form. | |
114 | 90 | if request.method == 'GET': |
115 | - if BROWSERID_ENABLED: | |
116 | - user_form = UserForm() | |
117 | - else: | |
118 | - user_form = UserCreationForm() | |
91 | + user_form = UserCreationForm() | |
119 | 92 | lists_form = ListsForm() |
120 | 93 | |
121 | 94 | return render(request, 'accounts/user_create_form.html', |
122 | 95 | {'user_form': user_form, 'lists_form': lists_form}) |
123 | 96 | |
124 | - if BROWSERID_ENABLED: | |
125 | - user_form = UserForm(request.POST, instance=request.user) | |
126 | - else: | |
127 | - user_form = UserCreationForm(request.POST) | |
97 | + user_form = UserCreationForm(request.POST) | |
128 | 98 | lists_form = ListsForm(request.POST) |
129 | 99 | |
130 | 100 | if not user_form.is_valid() or not lists_form.is_valid(): |
... | ... | @@ -134,12 +104,9 @@ def signup(request): |
134 | 104 | user = user_form.save(commit=False) |
135 | 105 | user.needs_update = False |
136 | 106 | |
137 | - if not BROWSERID_ENABLED: | |
138 | - user.is_active = False | |
139 | - user.save() | |
140 | - EmailAddressValidation.create(user.email, user) | |
141 | - else: | |
142 | - user.save() | |
107 | + user.is_active = False | |
108 | + user.save() | |
109 | + EmailAddressValidation.create(user.email, user) | |
143 | 110 | |
144 | 111 | # Check if the user's email have been used previously |
145 | 112 | # in the mainling lists to link the user to old messages |
... | ... | @@ -208,50 +175,6 @@ class ManageUserSubscriptionsView(UserProfileBaseMixin, DetailView): |
208 | 175 | self).get_context_data(**context) |
209 | 176 | |
210 | 177 | |
211 | -class ChangeXMPPPasswordView(UpdateView): | |
212 | - model = XMPPAccount | |
213 | - form_class = ChangeXMPPPasswordForm | |
214 | - fields = ['password', ] | |
215 | - template_name = 'accounts/change_password.html' | |
216 | - | |
217 | - def get_success_url(self): | |
218 | - return reverse('user_profile', kwargs={ | |
219 | - 'username': self.request.user.username | |
220 | - }) | |
221 | - | |
222 | - def get_object(self, queryset=None): | |
223 | - obj = get_object_or_404(XMPPAccount, user=self.request.user.pk) | |
224 | - self.old_password = obj.password | |
225 | - return obj | |
226 | - | |
227 | - def form_valid(self, form): | |
228 | - transaction.set_autocommit(False) | |
229 | - | |
230 | - response = super(ChangeXMPPPasswordView, self).form_valid(form) | |
231 | - | |
232 | - changed = xmpp.change_password( | |
233 | - self.object.jid, | |
234 | - self.old_password, | |
235 | - form.cleaned_data['password1'] | |
236 | - ) | |
237 | - | |
238 | - if not changed: | |
239 | - messages.error( | |
240 | - self.request, | |
241 | - _(u'Could not change your password. Please, try again later.') | |
242 | - ) | |
243 | - transaction.rollback() | |
244 | - return response | |
245 | - else: | |
246 | - transaction.commit() | |
247 | - | |
248 | - messages.success( | |
249 | - self.request, | |
250 | - _("You've changed your password successfully!") | |
251 | - ) | |
252 | - return response | |
253 | - | |
254 | - | |
255 | 178 | def password_changed(request): |
256 | 179 | messages.success(request, _('Your password was changed.')) |
257 | 180 | ... | ... |
colab/badger/__init__.py
colab/badger/admin.py
... | ... | @@ -1,20 +0,0 @@ |
1 | -# -*- coding: utf-8 -*- | |
2 | - | |
3 | -from django.contrib import admin | |
4 | - | |
5 | -from .forms import BadgeForm | |
6 | -from .models import Badge, BadgeI18N | |
7 | - | |
8 | - | |
9 | -class BadgeI18NInline(admin.TabularInline): | |
10 | - model = BadgeI18N | |
11 | - | |
12 | - | |
13 | -class BadgeAdmin(admin.ModelAdmin): | |
14 | - form = BadgeForm | |
15 | - inlines = [BadgeI18NInline, ] | |
16 | - list_display = ['title', 'description', 'order'] | |
17 | - list_editable = ['order', ] | |
18 | - | |
19 | - | |
20 | -admin.site.register(Badge, BadgeAdmin) |
colab/badger/forms.py
... | ... | @@ -1,46 +0,0 @@ |
1 | -# -*- coding: utf-8 -*- | |
2 | - | |
3 | -from django import forms | |
4 | -from django.utils.translation import ugettext_lazy as _ | |
5 | - | |
6 | -from PIL import Image | |
7 | - | |
8 | -from .models import Badge | |
9 | - | |
10 | -try: | |
11 | - from cStringIO import StringIO | |
12 | -except ImportError: | |
13 | - from StringIO import StringIO | |
14 | - | |
15 | - | |
16 | -class BadgeForm(forms.ModelForm): | |
17 | - image = forms.ImageField(label=_(u'Image'), required=False) | |
18 | - | |
19 | - class Meta: | |
20 | - model = Badge | |
21 | - fields = ( | |
22 | - 'title', 'description', 'image', 'user_attr', 'comparison', | |
23 | - 'value', 'awardees' | |
24 | - ) | |
25 | - | |
26 | - def clean_image(self): | |
27 | - if not self.instance.pk and not self.cleaned_data['image']: | |
28 | - raise forms.ValidationError(_(u'You must add an Image')) | |
29 | - return self.cleaned_data['image'] | |
30 | - | |
31 | - def save(self, commit=True): | |
32 | - | |
33 | - instance = super(BadgeForm, self).save(commit=False) | |
34 | - | |
35 | - if self.cleaned_data['image']: | |
36 | - img = Image.open(self.cleaned_data['image']) | |
37 | - img = img.resize((50, 50), Image.ANTIALIAS) | |
38 | - f = StringIO() | |
39 | - img.save(f, 'png') | |
40 | - instance.image_base64 = f.getvalue().encode('base64') | |
41 | - f.close() | |
42 | - | |
43 | - if commit: | |
44 | - instance.save() | |
45 | - | |
46 | - return instance |
colab/badger/management/__init__.py
colab/badger/management/commands/__init__.py
colab/badger/management/commands/rebuild_badges.py
... | ... | @@ -1,44 +0,0 @@ |
1 | -# -*- coding: utf-8 -*- | |
2 | - | |
3 | -from django.core.management.base import BaseCommand | |
4 | -from haystack.query import SearchQuerySet | |
5 | - | |
6 | -from colab.accounts.models import User | |
7 | -from colab.badger.models import Badge | |
8 | - | |
9 | - | |
10 | -class Command(BaseCommand): | |
11 | - help = "Rebuild the user's badges." | |
12 | - | |
13 | - def handle(self, *args, **kwargs): | |
14 | - for badge in Badge.objects.filter(type='auto'): | |
15 | - if not badge.comparison: | |
16 | - continue | |
17 | - elif badge.comparison == 'biggest': | |
18 | - order = u'-{}'.format(Badge.USER_ATTR_OPTS[badge.user_attr]) | |
19 | - sqs = SearchQuerySet().filter(type='user') | |
20 | - user = sqs.order_by(order)[0] | |
21 | - badge.awardees.remove(*list(badge.awardees.all())) | |
22 | - badge.awardees.add(User.objects.get(pk=user.pk)) | |
23 | - continue | |
24 | - | |
25 | - comparison = u'__{}'.format(badge.comparison) if badge.comparison \ | |
26 | - is not 'equal' else u'' | |
27 | - | |
28 | - key = u'{}{}'.format( | |
29 | - Badge.USER_ATTR_OPTS[badge.user_attr], | |
30 | - comparison | |
31 | - ) | |
32 | - opts = {key: badge.value} | |
33 | - | |
34 | - sqs = SearchQuerySet().filter( | |
35 | - type='user', | |
36 | - **opts | |
37 | - ) | |
38 | - | |
39 | - # Remove all awardees to make sure that all of then | |
40 | - # still accomplish the necessary to keep the badge | |
41 | - badge.awardees.remove(*list(badge.awardees.all())) | |
42 | - | |
43 | - for user in sqs: | |
44 | - badge.awardees.add(User.objects.get(pk=user.pk)) |
colab/badger/management/commands/update_badges.py
... | ... | @@ -1,45 +0,0 @@ |
1 | -# -*- coding: utf-8 -*- | |
2 | - | |
3 | -from django.core.management.base import BaseCommand | |
4 | -from haystack.query import SearchQuerySet | |
5 | - | |
6 | -from colab.accounts.models import User | |
7 | -from colab.badger.models import Badge | |
8 | - | |
9 | -import logging | |
10 | - | |
11 | - | |
12 | -class Command(BaseCommand): | |
13 | - help = "Update the user's badges" | |
14 | - | |
15 | - def update_badges(self): | |
16 | - for badge in Badge.objects.filter(type='auto'): | |
17 | - if not badge.comparison: | |
18 | - continue | |
19 | - elif badge.comparison == 'biggest': | |
20 | - order = u'-{}'.format(Badge.USER_ATTR_OPTS[badge.user_attr]) | |
21 | - sqs = SearchQuerySet().filter(type='user') | |
22 | - user = sqs.order_by(order)[0] | |
23 | - badge.awardees.add(User.objects.get(pk=user.pk)) | |
24 | - continue | |
25 | - | |
26 | - comparison = u'__{}'.format(badge.comparison) if badge.comparison \ | |
27 | - is not 'equal' else u'' | |
28 | - | |
29 | - key = u'{}{}'.format( | |
30 | - Badge.USER_ATTR_OPTS[badge.user_attr], | |
31 | - comparison | |
32 | - ) | |
33 | - opts = {key: badge.value} | |
34 | - | |
35 | - sqs = SearchQuerySet().filter(type='user', **opts) | |
36 | - | |
37 | - for user in sqs: | |
38 | - badge.awardees.add(User.objects.get(pk=user.pk)) | |
39 | - | |
40 | - def handle(self, *args, **kwargs): | |
41 | - try: | |
42 | - self.update_badges() | |
43 | - except Exception as e: | |
44 | - logging.exception(e) | |
45 | - raise |
colab/badger/migrations/0001_initial.py
... | ... | @@ -1,53 +0,0 @@ |
1 | -# -*- coding: utf-8 -*- | |
2 | -from __future__ import unicode_literals | |
3 | - | |
4 | -from django.db import models, migrations | |
5 | -from django.conf import settings | |
6 | - | |
7 | - | |
8 | -class Migration(migrations.Migration): | |
9 | - | |
10 | - dependencies = [ | |
11 | - migrations.swappable_dependency(settings.AUTH_USER_MODEL), | |
12 | - ] | |
13 | - | |
14 | - operations = [ | |
15 | - migrations.CreateModel( | |
16 | - name='Badge', | |
17 | - fields=[ | |
18 | - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), | |
19 | - ('title', models.CharField(max_length=200, null=True, verbose_name='Title', blank=True)), | |
20 | - ('description', models.CharField(max_length=200, null=True, verbose_name='Description', blank=True)), | |
21 | - ('image_base64', models.TextField(verbose_name='Image')), | |
22 | - ('type', models.CharField(max_length=200, verbose_name='Type', choices=[('auto', 'Automatically'), ('manual', 'Manual')])), | |
23 | - ('user_attr', models.CharField(blank=True, max_length=100, null=True, verbose_name='User attribute', choices=[('messages', 'Messages'), ('contributions', 'Contributions'), ('wikis', 'Wikis'), ('revisions', 'Revisions'), ('tickets', 'Ticket')])), | |
24 | - ('comparison', models.CharField(blank=True, max_length=10, null=True, verbose_name='Comparison', choices=[('gte', 'Greater than or equal'), ('lte', 'less than or equal'), ('equal', 'Equal'), ('biggest', 'Biggest')])), | |
25 | - ('value', models.PositiveSmallIntegerField(null=True, verbose_name='Value', blank=True)), | |
26 | - ('order', models.PositiveSmallIntegerField(default=100, verbose_name='Order')), | |
27 | - ('awardees', models.ManyToManyField(to=settings.AUTH_USER_MODEL, null=True, verbose_name='Awardees', blank=True)), | |
28 | - ], | |
29 | - options={ | |
30 | - 'ordering': ['order'], | |
31 | - 'verbose_name': 'Badge', | |
32 | - 'verbose_name_plural': 'Badges', | |
33 | - }, | |
34 | - bases=(models.Model,), | |
35 | - ), | |
36 | - migrations.CreateModel( | |
37 | - name='BadgeI18N', | |
38 | - fields=[ | |
39 | - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), | |
40 | - ('i18n_language', models.CharField(max_length=10, verbose_name='language', choices=[(b'pt-br', 'Portuguese'), (b'es', 'Spanish')])), | |
41 | - ('title', models.CharField(max_length=200, null=True, verbose_name='Title', blank=True)), | |
42 | - ('description', models.CharField(max_length=200, null=True, verbose_name='Description', blank=True)), | |
43 | - ('i18n_source', models.ForeignKey(related_name=b'translations', editable=False, to='badger.Badge', verbose_name='source')), | |
44 | - ], | |
45 | - options={ | |
46 | - }, | |
47 | - bases=(models.Model,), | |
48 | - ), | |
49 | - migrations.AlterUniqueTogether( | |
50 | - name='badgei18n', | |
51 | - unique_together=set([('i18n_source', 'i18n_language')]), | |
52 | - ), | |
53 | - ] |
colab/badger/migrations/__init__.py
colab/badger/models.py
... | ... | @@ -1,83 +0,0 @@ |
1 | -# -*- coding: utf-8 -*- | |
2 | - | |
3 | -from django.conf import settings | |
4 | -from django.db import models | |
5 | -from django.utils.translation import ugettext_lazy as _ | |
6 | -from i18n_model.models import I18nModel | |
7 | - | |
8 | - | |
9 | -class Badge(models.Model): | |
10 | - COMPARISON_CHOICES = ( | |
11 | - (u'gte', _(u'Greater than or equal')), | |
12 | - (u'lte', _(u'less than or equal')), | |
13 | - (u'equal', _(u'Equal')), | |
14 | - (u'biggest', _(u'Biggest')), | |
15 | - ) | |
16 | - TYPE_CHOICES = ( | |
17 | - (u'auto', _(u'Automatically')), | |
18 | - (u'manual', _(u'Manual')), | |
19 | - ) | |
20 | - USER_ATTR_CHOICES = ( | |
21 | - (u'messages', _(u'Messages')), | |
22 | - (u'contributions', _(u'Contributions')), | |
23 | - (u'wikis', _(u'Wikis')), | |
24 | - (u'revisions', _(u'Revisions')), | |
25 | - (u'tickets', _(u'Ticket')), | |
26 | - ) | |
27 | - USER_ATTR_OPTS = { | |
28 | - u'messages': u'message_count', | |
29 | - u'revisions': u'changeset_count', | |
30 | - u'tickets': u'ticket_count', | |
31 | - u'wikis': u'wiki_count', | |
32 | - u'contributions': u'contribution_count', | |
33 | - } | |
34 | - | |
35 | - title = models.CharField(_(u'Title'), max_length=200, blank=True, | |
36 | - null=True) | |
37 | - description = models.CharField(_(u'Description'), max_length=200, | |
38 | - blank=True, null=True) | |
39 | - image_base64 = models.TextField(_(u'Image')) | |
40 | - type = models.CharField(_(u'Type'), max_length=200, choices=TYPE_CHOICES) | |
41 | - user_attr = models.CharField( | |
42 | - _(u'User attribute'), max_length=100, | |
43 | - choices=USER_ATTR_CHOICES, | |
44 | - blank=True, | |
45 | - null=True, | |
46 | - ) | |
47 | - comparison = models.CharField( | |
48 | - _(u'Comparison'), | |
49 | - max_length=10, | |
50 | - choices=COMPARISON_CHOICES, | |
51 | - blank=True, | |
52 | - null=True | |
53 | - ) | |
54 | - value = models.PositiveSmallIntegerField( | |
55 | - _(u'Value'), | |
56 | - blank=True, | |
57 | - null=True | |
58 | - ) | |
59 | - awardees = models.ManyToManyField( | |
60 | - settings.AUTH_USER_MODEL, | |
61 | - verbose_name=_(u'Awardees'), | |
62 | - blank=True, | |
63 | - null=True | |
64 | - ) | |
65 | - order = models.PositiveSmallIntegerField(_(u'Order'), default=100) | |
66 | - | |
67 | - class Meta: | |
68 | - verbose_name = _(u'Badge') | |
69 | - verbose_name_plural = _(u'Badges') | |
70 | - ordering = ['order', ] | |
71 | - | |
72 | - def __unicode__(self): | |
73 | - return u'{} ({}, {})'.format( | |
74 | - self.title, | |
75 | - self.get_user_attr_display(), | |
76 | - self.get_type_display(), | |
77 | - ) | |
78 | - | |
79 | - | |
80 | -class BadgeI18N(I18nModel): | |
81 | - class Meta: | |
82 | - source_model = Badge | |
83 | - translation_fields = ('title', 'description') |
colab/badger/tests.py
colab/badger/utils.py
... | ... | @@ -1,41 +0,0 @@ |
1 | -# -*- coding: utf-8 -*- | |
2 | - | |
3 | -from django.db.models import Count | |
4 | - | |
5 | -# from proxy.trac.models import (Ticket, Wiki) | |
6 | -# from proxy.trac.models import (Revision, WikiCollabCount, TicketCollabCount) | |
7 | -from colab.accounts.models import User | |
8 | - | |
9 | - | |
10 | -# def get_wiki_counters(): | |
11 | -# return {author: count for author, count in | |
12 | -# WikiCollabCount.objects.values_list()} | |
13 | - | |
14 | - | |
15 | -# def get_revision_counters(): | |
16 | -# return { | |
17 | -# author: count for author, count in Revision.objects.values_list( | |
18 | -# 'author' | |
19 | -# ).annotate(count=Count('author')) | |
20 | -# } | |
21 | - | |
22 | - | |
23 | -# def get_ticket_counters(): | |
24 | -# return {author: count for author, count in | |
25 | -# TicketCollabCount.objects.values_list()} | |
26 | - | |
27 | - | |
28 | -def get_users_counters(): | |
29 | - # wiki_counters = get_wiki_counters() | |
30 | - # revision_counters = get_revision_counters() | |
31 | - # ticket_counters = get_ticket_counters() | |
32 | - | |
33 | - users_counters = {} | |
34 | - for user in User.objects.annotate(message_count=Count('emails__message')): | |
35 | - users_counters[user.username] = { | |
36 | - 'messages': user.message_count, | |
37 | - # 'wikis': wiki_counters.get(user.username, 0), | |
38 | - # 'revisions': revision_counters.get(user.username, 0), | |
39 | - # 'tickets': ticket_counters.get(user.username, 0), | |
40 | - } | |
41 | - return users_counters |
colab/badger/views.py
colab/home/context_processors.py
colab/locale/en/LC_MESSAGES/django.po
... | ... | @@ -126,12 +126,11 @@ msgstr "" |
126 | 126 | msgid "Register" |
127 | 127 | msgstr "" |
128 | 128 | |
129 | -#: accounts/templates/accounts/user_detail.html:8 badger/models.py:21 | |
129 | +#: accounts/templates/accounts/user_detail.html:8 | |
130 | 130 | msgid "Messages" |
131 | 131 | msgstr "" |
132 | 132 | |
133 | -#: accounts/templates/accounts/user_detail.html:9 badger/models.py:22 | |
134 | -#: templates/home.html:7 | |
133 | +#: accounts/templates/accounts/user_detail.html:9 | |
135 | 134 | msgid "Contributions" |
136 | 135 | msgstr "" |
137 | 136 | |
... | ... | @@ -175,7 +174,7 @@ msgstr "" |
175 | 174 | msgid "Participation by Group" |
176 | 175 | msgstr "" |
177 | 176 | |
178 | -#: accounts/templates/accounts/user_detail.html:132 badger/models.py:69 | |
177 | +#: accounts/templates/accounts/user_detail.html:132 | |
179 | 178 | msgid "Badges" |
180 | 179 | msgstr "" |
181 | 180 | |
... | ... | @@ -291,87 +290,18 @@ msgstr "" |
291 | 290 | msgid "You've changed your password successfully!" |
292 | 291 | msgstr "" |
293 | 292 | |
294 | -#: badger/forms.py:19 badger/models.py:39 settings.py:160 | |
293 | +#: settings.py:160 | |
295 | 294 | msgid "Image" |
296 | 295 | msgstr "" |
297 | 296 | |
298 | -#: badger/forms.py:30 | |
299 | -msgid "You must add an Image" | |
300 | -msgstr "" | |
301 | - | |
302 | -#: badger/models.py:11 | |
303 | -msgid "Greater than or equal" | |
304 | -msgstr "" | |
305 | - | |
306 | -#: badger/models.py:12 | |
307 | -msgid "less than or equal" | |
308 | -msgstr "" | |
309 | - | |
310 | -#: badger/models.py:13 | |
311 | -msgid "Equal" | |
312 | -msgstr "" | |
313 | - | |
314 | -#: badger/models.py:14 | |
315 | -msgid "Biggest" | |
316 | -msgstr "" | |
317 | - | |
318 | -#: badger/models.py:17 | |
319 | -msgid "Automatically" | |
320 | -msgstr "" | |
321 | - | |
322 | -#: badger/models.py:18 | |
323 | -msgid "Manual" | |
324 | -msgstr "" | |
325 | - | |
326 | -#: badger/models.py:23 | |
327 | -msgid "Wikis" | |
328 | -msgstr "" | |
329 | - | |
330 | -#: badger/models.py:24 | |
331 | -msgid "Revisions" | |
332 | -msgstr "" | |
333 | - | |
334 | -#: badger/models.py:25 | |
335 | 297 | #: search/templates/search/includes/search_filters.html:122 |
336 | 298 | msgid "Ticket" |
337 | 299 | msgstr "" |
338 | 300 | |
339 | -#: badger/models.py:35 | |
340 | -msgid "Title" | |
341 | -msgstr "" | |
342 | - | |
343 | -#: badger/models.py:37 | |
344 | -msgid "Description" | |
345 | -msgstr "" | |
346 | - | |
347 | -#: badger/models.py:40 search/forms.py:18 | |
301 | +#: search/forms.py:18 | |
348 | 302 | msgid "Type" |
349 | 303 | msgstr "" |
350 | 304 | |
351 | -#: badger/models.py:42 | |
352 | -msgid "User attribute" | |
353 | -msgstr "" | |
354 | - | |
355 | -#: badger/models.py:48 | |
356 | -msgid "Comparison" | |
357 | -msgstr "" | |
358 | - | |
359 | -#: badger/models.py:55 | |
360 | -msgid "Value" | |
361 | -msgstr "" | |
362 | - | |
363 | -#: badger/models.py:61 | |
364 | -msgid "Awardees" | |
365 | -msgstr "" | |
366 | - | |
367 | -#: badger/models.py:65 | |
368 | -msgid "Order" | |
369 | -msgstr "" | |
370 | - | |
371 | -#: badger/models.py:68 | |
372 | -msgid "Badge" | |
373 | -msgstr "" | |
374 | - | |
375 | 305 | #: home/context_processors.py:15 |
376 | 306 | msgid "Fork me!" |
377 | 307 | msgstr "" | ... | ... |
colab/locale/pt_BR/LC_MESSAGES/django.po
... | ... | @@ -149,12 +149,11 @@ msgid "Register" |
149 | 149 | msgstr "Cadastre-se" |
150 | 150 | |
151 | 151 | #: colab/accounts/templates/accounts/user_detail.html:8 |
152 | -#: colab/badger/models.py:21 | |
153 | 152 | msgid "Messages" |
154 | 153 | msgstr "Mensagens" |
155 | 154 | |
156 | 155 | #: colab/accounts/templates/accounts/user_detail.html:9 |
157 | -#: colab/badger/models.py:22 colab/templates/home.html:7 | |
156 | +#: colab/templates/home.html:7 | |
158 | 157 | msgid "Contributions" |
159 | 158 | msgstr "Contribuições" |
160 | 159 | |
... | ... | @@ -199,7 +198,6 @@ msgid "Participation by Group" |
199 | 198 | msgstr "Participação por grupo" |
200 | 199 | |
201 | 200 | #: colab/accounts/templates/accounts/user_detail.html:132 |
202 | -#: colab/badger/models.py:69 | |
203 | 201 | msgid "Badges" |
204 | 202 | msgstr "Medalhas" |
205 | 203 | |
... | ... | @@ -365,87 +363,18 @@ msgstr "Nos enviamos o email com as intruções para mudança de senha. Em breve |
365 | 363 | msgid "Your password has been set. You may go ahead and log in now." |
366 | 364 | msgstr "Sua senha foi redefinida. Você pode prosseguir e autenticar agora." |
367 | 365 | |
368 | -#: colab/badger/forms.py:19 colab/badger/models.py:39 colab/settings.py:160 | |
366 | +#: colab/settings.py:160 | |
369 | 367 | msgid "Image" |
370 | 368 | msgstr "Imagem" |
371 | 369 | |
372 | -#: colab/badger/forms.py:30 | |
373 | -msgid "You must add an Image" | |
374 | -msgstr "Você deve adicionar uma imagem" | |
375 | - | |
376 | -#: colab/badger/models.py:11 | |
377 | -msgid "Greater than or equal" | |
378 | -msgstr "Maior que ou igual" | |
379 | - | |
380 | -#: colab/badger/models.py:12 | |
381 | -msgid "less than or equal" | |
382 | -msgstr "menor que ou igual" | |
383 | - | |
384 | -#: colab/badger/models.py:13 | |
385 | -msgid "Equal" | |
386 | -msgstr "Igual" | |
387 | - | |
388 | -#: colab/badger/models.py:14 | |
389 | -msgid "Biggest" | |
390 | -msgstr "Maior" | |
391 | - | |
392 | -#: colab/badger/models.py:17 | |
393 | -msgid "Automatically" | |
394 | -msgstr "Automaticamente" | |
395 | - | |
396 | -#: colab/badger/models.py:18 | |
397 | -msgid "Manual" | |
398 | -msgstr "Manual" | |
399 | - | |
400 | -#: colab/badger/models.py:23 | |
401 | -msgid "Wikis" | |
402 | -msgstr "Wikis" | |
403 | - | |
404 | -#: colab/badger/models.py:24 | |
405 | -msgid "Revisions" | |
406 | -msgstr "Conjunto de mudanças" | |
407 | - | |
408 | -#: colab/badger/models.py:25 | |
409 | 370 | #: colab/search/templates/search/includes/search_filters.html:122 |
410 | 371 | msgid "Ticket" |
411 | 372 | msgstr "Tíquetes" |
412 | 373 | |
413 | -#: colab/badger/models.py:35 | |
414 | -msgid "Title" | |
415 | -msgstr "Título" | |
416 | - | |
417 | -#: colab/badger/models.py:37 | |
418 | -msgid "Description" | |
419 | -msgstr "Descrição" | |
420 | - | |
421 | -#: colab/badger/models.py:40 colab/search/forms.py:18 | |
374 | +#: colab/search/forms.py:18 | |
422 | 375 | msgid "Type" |
423 | 376 | msgstr "Tipo" |
424 | 377 | |
425 | -#: colab/badger/models.py:42 | |
426 | -msgid "User attribute" | |
427 | -msgstr "Atributo do usuário" | |
428 | - | |
429 | -#: colab/badger/models.py:48 | |
430 | -msgid "Comparison" | |
431 | -msgstr "Comparação" | |
432 | - | |
433 | -#: colab/badger/models.py:55 | |
434 | -msgid "Value" | |
435 | -msgstr "Valor" | |
436 | - | |
437 | -#: colab/badger/models.py:61 | |
438 | -msgid "Awardees" | |
439 | -msgstr "Premiados" | |
440 | - | |
441 | -#: colab/badger/models.py:65 | |
442 | -msgid "Order" | |
443 | -msgstr "Ordem" | |
444 | - | |
445 | -#: colab/badger/models.py:68 | |
446 | -msgid "Badge" | |
447 | -msgstr "Medalha" | |
448 | - | |
449 | 378 | #: colab/home/context_processors.py:20 |
450 | 379 | msgid "Fork me!" |
451 | 380 | msgstr "Fork me!" | ... | ... |
colab/management/initconfig.py
... | ... | @@ -21,15 +21,6 @@ EMAIL_SUBJECT_PREFIX = '[colab]' |
21 | 21 | |
22 | 22 | SECRET_KEY = '{secret_key}' |
23 | 23 | |
24 | -# Must use it without trailing slash | |
25 | -SITE_URL = 'http://localhost:8000' | |
26 | -BROWSERID_AUDIENCES = [ | |
27 | - 'http://localhost:8000', | |
28 | -# 'http://example.com', | |
29 | -# 'https://example.org', | |
30 | -# 'http://example.net', | |
31 | -] | |
32 | - | |
33 | 24 | ALLOWED_HOSTS = [ |
34 | 25 | 'localhost', |
35 | 26 | # 'example.com', |
... | ... | @@ -37,18 +28,9 @@ ALLOWED_HOSTS = [ |
37 | 28 | # 'example.net', |
38 | 29 | ] |
39 | 30 | |
40 | -### Uncomment to enable Broswer ID protocol for authentication | |
41 | -# BROWSERID_ENABLED = True | |
42 | - | |
43 | 31 | ### Uncomment to enable social networks fields profile |
44 | 32 | # SOCIAL_NETWORK_ENABLED = True |
45 | 33 | |
46 | -### Uncomment to enable Converse.js | |
47 | -# CONVERSEJS_ENABLED = True | |
48 | - | |
49 | -### Uncomment to enable auto-registration | |
50 | -# CONVERSEJS_AUTO_REGISTER = 'xmpp.example.com' | |
51 | - | |
52 | 34 | ## Database settings |
53 | 35 | DATABASES = {{ |
54 | 36 | 'default': {{ | ... | ... |
colab/plugins/jenkins/__init__.py
colab/plugins/jenkins/apps.py
... | ... | @@ -1,16 +0,0 @@ |
1 | - | |
2 | -from django.utils.translation import ugettext_lazy as _ | |
3 | - | |
4 | -from ..utils.apps import ColabProxiedAppConfig | |
5 | - | |
6 | - | |
7 | -class ProxyJenkinsAppConfig(ColabProxiedAppConfig): | |
8 | - name = 'colab.plugins.jenkins' | |
9 | - verbose_name = 'Jenkins Proxy' | |
10 | - | |
11 | - menu = { | |
12 | - 'title': _('Code'), | |
13 | - 'links': ( | |
14 | - (_('Continuos Integration'), ''), | |
15 | - ), | |
16 | - } |
colab/plugins/jenkins/data_api.py
colab/plugins/jenkins/diazo.xml
... | ... | @@ -1,27 +0,0 @@ |
1 | -<rules | |
2 | - xmlns="http://namespaces.plone.org/diazo" | |
3 | - xmlns:css="http://namespaces.plone.org/diazo/css" | |
4 | - xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> | |
5 | - | |
6 | - <before theme-children="/html/head" content-children="/html/head" /> | |
7 | - <before css:theme-children="#main-content" css:content-children="body" /> | |
8 | - | |
9 | - <merge attributes="class" css:theme="body" css:content="body" /> | |
10 | - <drop css:content="#top-panel" /> | |
11 | - | |
12 | - <drop attributes="style" css:content="#main-table" /> | |
13 | - | |
14 | - <after theme-children="/html/head"> | |
15 | - <script>jQuery.noConflict();</script> | |
16 | - <style> | |
17 | - #breadcrumbs { | |
18 | - border: 0 !important; | |
19 | - } | |
20 | - | |
21 | - #right-top-nav { | |
22 | - margin-right: 5em !important; | |
23 | - } | |
24 | - </style> | |
25 | - </after> | |
26 | - | |
27 | -</rules> |
colab/plugins/jenkins/models.py
colab/plugins/jenkins/urls.py
colab/plugins/jenkins/views.py
colab/plugins/redmine/__init__.py
colab/plugins/redmine/apps.py
colab/plugins/redmine/data_api.py
colab/plugins/redmine/diazo.xml
... | ... | @@ -1,11 +0,0 @@ |
1 | -<rules | |
2 | - xmlns="http://namespaces.plone.org/diazo" | |
3 | - xmlns:css="http://namespaces.plone.org/diazo/css" | |
4 | - xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> | |
5 | - | |
6 | - <before theme-children="/html/head" content-children="/html/head" /> | |
7 | - <before css:theme-children="#main-content" css:content-children="body" /> | |
8 | - | |
9 | - <merge attributes="class" css:theme="body" css:content="body" /> | |
10 | - <drop css:content="#top-panel" /> | |
11 | -</rules> |
colab/plugins/redmine/models.py
colab/plugins/redmine/urls.py
colab/plugins/redmine/views.py
colab/plugins/trac/__init__.py
colab/plugins/trac/admin.py
... | ... | @@ -1 +0,0 @@ |
1 | -# from . import signals |
colab/plugins/trac/apps.py
... | ... | @@ -1,24 +0,0 @@ |
1 | - | |
2 | -from django.utils.translation import ugettext_lazy as _ | |
3 | - | |
4 | -from ..utils.apps import ColabProxiedAppConfig | |
5 | - | |
6 | - | |
7 | -class ProxyTracAppConfig(ColabProxiedAppConfig): | |
8 | - name = 'colab.plugins.trac' | |
9 | - verbose_name = 'Trac Proxy' | |
10 | - | |
11 | - menu = { | |
12 | - 'title': _('Code'), | |
13 | - 'links': ( | |
14 | - (_('Timeline'), 'timeline'), | |
15 | - (_('Wiki'), 'wiki'), | |
16 | - (_('View Tickets'), 'report'), | |
17 | - (_('Roadmap'), 'roadmap'), | |
18 | - (_('Browse Source'), 'browser'), | |
19 | - ), | |
20 | - 'auth_links': ( | |
21 | - (_('New Ticket'), 'newticket'), | |
22 | - (_('New Wiki Page'), 'wiki/WikiNewPage'), | |
23 | - ), | |
24 | - } |
colab/plugins/trac/data_api.py
colab/plugins/trac/diazo.xml
... | ... | @@ -1,45 +0,0 @@ |
1 | -<rules | |
2 | - xmlns="http://namespaces.plone.org/diazo" | |
3 | - xmlns:css="http://namespaces.plone.org/diazo/css" | |
4 | - xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> | |
5 | - | |
6 | - <replace css:theme="#trac-css" content="//head/link" /> | |
7 | - <replace css:theme="#trac-js" content="//head/script" /> | |
8 | - <replace theme="//head/title" content="//head/title" /> | |
9 | - | |
10 | - <before css:theme-children="#main-content" css:content="#main" /> | |
11 | - | |
12 | - <after theme-children="/html/head"> | |
13 | - <style> | |
14 | - .navbar .nav ul { font-size: 14px; text-align: left; padding: 5px 0; } | |
15 | - .navbar .nav li { border: 0; padding: 0; white-space: normal; display: list-item;} | |
16 | - :link:not(.btn), | |
17 | - :visited:not(.btn) { border: 0; color: rgb(66, 139, 202); } | |
18 | - h1 { font-size: 24px; margin: 0.15em 1em 0.5em 0px; } | |
19 | - h2 { font-size: 20px } | |
20 | - h3 { font-size: 16px } | |
21 | - h4 { font-size: 14px } | |
22 | - input[type="checkbox"], input[type="radio"] { margin: 0 4px; } | |
23 | - fieldset { padding: 1em; margin: 1em 0; border: 1px solid rgb(215, 215, 215); } | |
24 | - label { font-weight: 400; } | |
25 | - legend { margin-bottom: 0; width: auto; } | |
26 | - input, textarea, select { margin: 2px; } | |
27 | - | |
28 | - .wikitoolbar, | |
29 | - .wikitoolbar:before, | |
30 | - .wikitoolbar:after { | |
31 | - -moz-box-sizing: content-box; | |
32 | - -webkit-box-sizing: content-box; | |
33 | - } | |
34 | - .wikitoolbar :link, | |
35 | - .wikitoolbar :visited { | |
36 | - border-width: 1px; | |
37 | - border-style: solid; | |
38 | - border-color: #fff #fff #fff #ccc; | |
39 | - -moz-box-sizing: content-box; | |
40 | - -webkit-box-sizing: content-box; | |
41 | - } | |
42 | - </style> | |
43 | - </after> | |
44 | - | |
45 | -</rules> |
colab/plugins/trac/migrations/0001_initial.py
... | ... | @@ -1,141 +0,0 @@ |
1 | -# -*- coding: utf-8 -*- | |
2 | -from __future__ import unicode_literals | |
3 | - | |
4 | -from django.db import models, migrations, connections | |
5 | - | |
6 | - | |
7 | -def create_views(apps, schema_editor): | |
8 | - connection = connections['trac'] | |
9 | - | |
10 | - cursor = connection.cursor() | |
11 | - | |
12 | - # revision_view | |
13 | - cursor.execute(''' | |
14 | - CREATE OR REPLACE VIEW revision_view AS SELECT | |
15 | - revision.rev, | |
16 | - revision.author, | |
17 | - revision.message, | |
18 | - repository.value AS repository_name, | |
19 | - TIMESTAMP WITH TIME ZONE 'epoch' + (revision.time/1000000) * INTERVAL '1s' AS created, | |
20 | - CONCAT(revision.repos, '-', revision.rev) AS key | |
21 | - FROM revision | |
22 | - INNER JOIN repository ON( | |
23 | - repository.id = revision.repos | |
24 | - AND repository.name = 'name' | |
25 | - AND repository.value != '' | |
26 | - ); | |
27 | - ''') | |
28 | - | |
29 | - # attachment_view | |
30 | - cursor.execute(''' | |
31 | - CREATE OR REPLACE VIEW attachment_view AS SELECT | |
32 | - CONCAT(attachment.type, '/' , attachment.id, '/', attachment.filename) AS url, | |
33 | - attachment.type AS used_by, | |
34 | - attachment.filename AS filename, | |
35 | - attachment.id as attach_id, | |
36 | - (SELECT LOWER(SUBSTRING(attachment.filename FROM '\.(\w+)$'))) AS mimetype, | |
37 | - attachment.author AS author, | |
38 | - attachment.description AS description, | |
39 | - attachment.size AS size, | |
40 | - TIMESTAMP WITH TIME ZONE 'epoch' + (attachment.time/1000000)* INTERVAL '1s' AS created | |
41 | - FROM attachment; | |
42 | - ''') | |
43 | - | |
44 | - # wiki_view | |
45 | - cursor.execute(''' | |
46 | - CREATE OR REPLACE VIEW wiki_view AS SELECT | |
47 | - wiki.name AS name, | |
48 | - (SELECT wiki2.text FROM wiki AS wiki2 WHERE wiki2.name = wiki.name | |
49 | - AND wiki2.version = MAX(wiki.version)) AS wiki_text, | |
50 | - (SELECT wiki3.author FROM wiki AS wiki3 WHERE wiki3.name = wiki.name | |
51 | - AND wiki3.version = 1) AS author, | |
52 | - string_agg(DISTINCT wiki.author, ', ') AS collaborators, | |
53 | - TIMESTAMP WITH TIME ZONE 'epoch' + (MIN(wiki.time)/1000000) * INTERVAL '1s' AS created, | |
54 | - TIMESTAMP WITH TIME ZONE 'epoch' + (MAX(wiki.time)/1000000) * INTERVAL '1s' AS modified, | |
55 | - (SELECT wiki4.author FROM wiki AS wiki4 WHERE wiki4.name = wiki.name | |
56 | - AND wiki4.version = MAX(wiki.version)) AS modified_by | |
57 | - FROM wiki | |
58 | - GROUP BY wiki.name; | |
59 | - ''') | |
60 | - | |
61 | - # ticket_view | |
62 | - cursor.execute(''' | |
63 | - CREATE OR REPLACE VIEW ticket_view AS SELECT | |
64 | - ticket.id AS id, | |
65 | - ticket.summary as summary, | |
66 | - ticket.description as description, | |
67 | - ticket.milestone as milestone, | |
68 | - ticket.priority as priority, | |
69 | - ticket.component as component, | |
70 | - ticket.version as version, | |
71 | - ticket.severity as severity, | |
72 | - ticket.reporter as reporter, | |
73 | - ticket.reporter as author, | |
74 | - ticket.status as status, | |
75 | - ticket.keywords as keywords, | |
76 | - (SELECT | |
77 | - string_agg(DISTINCT ticket_change.author, ', ') | |
78 | - FROM ticket_change WHERE ticket_change.ticket = ticket.id | |
79 | - GROUP BY ticket_change.ticket) as collaborators, | |
80 | - TIMESTAMP WITH TIME ZONE 'epoch' + (time/1000000)* INTERVAL '1s' AS created, | |
81 | - TIMESTAMP WITH TIME ZONE 'epoch' + (changetime/1000000) * INTERVAL '1s' AS modified, | |
82 | - (SELECT | |
83 | - ticket_change.author | |
84 | - FROM ticket_change | |
85 | - WHERE ticket_change.ticket = ticket.id | |
86 | - AND ticket_change.time = ticket.changetime | |
87 | - LIMIT 1 | |
88 | - ) AS modified_by | |
89 | - FROM ticket; | |
90 | - ''') | |
91 | - | |
92 | - # ticket_collab_count_view | |
93 | - cursor.execute(''' | |
94 | - CREATE OR REPLACE VIEW ticket_collab_count_view AS | |
95 | - SELECT | |
96 | - COALESCE (t1.author, t2.author) as author, | |
97 | - (COALESCE(t1.count, 0) + COALESCE(t2.count, 0)) as count | |
98 | - FROM | |
99 | - (SELECT author, count(*) as count | |
100 | - FROM ticket_change | |
101 | - GROUP BY author | |
102 | - ORDER BY author | |
103 | - ) AS t1 | |
104 | - FULL OUTER JOIN | |
105 | - (SELECT reporter as author, count(*) as count | |
106 | - FROM ticket | |
107 | - GROUP BY reporter | |
108 | - ORDER BY reporter | |
109 | - ) AS t2 | |
110 | - ON t1.author = t2.author; | |
111 | - ''') | |
112 | - | |
113 | - # wiki_collab_count_view | |
114 | - cursor.execute(''' | |
115 | - CREATE OR REPLACE VIEW wiki_collab_count_view AS | |
116 | - SELECT author, count(*) from wiki GROUP BY author; | |
117 | - ''') | |
118 | - | |
119 | - | |
120 | -def drop_views(apps, schema_editor): | |
121 | - connection = connections['trac'] | |
122 | - | |
123 | - cursor = connection.cursor() | |
124 | - cursor.execute(''' | |
125 | - DROP VIEW IF EXISTS revision_view; | |
126 | - DROP VIEW IF EXISTS ticket_view; | |
127 | - DROP VIEW IF EXISTS wiki_view; | |
128 | - DROP VIEW IF EXISTS ticket_collab_count_view; | |
129 | - DROP VIEW IF EXISTS wiki_collab_count_view; | |
130 | - DROP VIEW IF EXISTS attachment_view; | |
131 | - ''') | |
132 | - | |
133 | - | |
134 | -class Migration(migrations.Migration): | |
135 | - | |
136 | - dependencies = [ | |
137 | - ] | |
138 | - | |
139 | - operations = [ | |
140 | - migrations.RunPython(code=create_views, reverse_code=drop_views) | |
141 | - ] |
colab/plugins/trac/migrations/__init__.py
colab/plugins/trac/models.py
... | ... | @@ -1,133 +0,0 @@ |
1 | -# -*- coding: utf-8 -*- | |
2 | -import os | |
3 | -import urllib2 | |
4 | - | |
5 | -from django.db import models | |
6 | -from django.conf import settings | |
7 | - | |
8 | -from hitcounter.models import HitCounterModelMixin | |
9 | - | |
10 | -from colab.accounts.models import User | |
11 | - | |
12 | - | |
13 | -class Attachment(models.Model, HitCounterModelMixin): | |
14 | - url = models.TextField(primary_key=True) | |
15 | - attach_id = models.TextField() | |
16 | - used_by = models.TextField() | |
17 | - filename = models.TextField() | |
18 | - author = models.TextField(blank=True) | |
19 | - description = models.TextField(blank=True) | |
20 | - created = models.DateTimeField(blank=True) | |
21 | - mimetype = models.TextField(blank=True) | |
22 | - size = models.IntegerField(blank=True) | |
23 | - | |
24 | - class Meta: | |
25 | - managed = False | |
26 | - db_table = 'attachment_view' | |
27 | - | |
28 | - @property | |
29 | - def filepath(self): | |
30 | - return os.path.join( | |
31 | - settings.ATTACHMENTS_FOLDER_PATH, | |
32 | - self.used_by, | |
33 | - self.attach_id, | |
34 | - urllib2.quote(self.filename.encode('utf8')) | |
35 | - ) | |
36 | - | |
37 | - def get_absolute_url(self): | |
38 | - return u'/raw-attachment/{}'.format(self.url) | |
39 | - | |
40 | - def get_author(self): | |
41 | - try: | |
42 | - return User.objects.get(username=self.author) | |
43 | - except User.DoesNotExist: | |
44 | - return None | |
45 | - | |
46 | - | |
47 | -class Revision(models.Model, HitCounterModelMixin): | |
48 | - key = models.TextField(blank=True, primary_key=True) | |
49 | - rev = models.TextField(blank=True) | |
50 | - author = models.TextField(blank=True) | |
51 | - message = models.TextField(blank=True) | |
52 | - repository_name = models.TextField(blank=True) | |
53 | - created = models.DateTimeField(blank=True, null=True) | |
54 | - | |
55 | - class Meta: | |
56 | - managed = False | |
57 | - db_table = 'revision_view' | |
58 | - | |
59 | - def get_absolute_url(self): | |
60 | - return u'/changeset/{}/{}'.format(self.rev, self.repository_name) | |
61 | - | |
62 | - def get_author(self): | |
63 | - try: | |
64 | - return User.objects.get(username=self.author) | |
65 | - except User.DoesNotExist: | |
66 | - return None | |
67 | - | |
68 | - | |
69 | -class Ticket(models.Model, HitCounterModelMixin): | |
70 | - id = models.IntegerField(primary_key=True) | |
71 | - summary = models.TextField(blank=True) | |
72 | - description = models.TextField(blank=True) | |
73 | - milestone = models.TextField(blank=True) | |
74 | - priority = models.TextField(blank=True) | |
75 | - component = models.TextField(blank=True) | |
76 | - version = models.TextField(blank=True) | |
77 | - severity = models.TextField(blank=True) | |
78 | - reporter = models.TextField(blank=True) | |
79 | - author = models.TextField(blank=True) | |
80 | - status = models.TextField(blank=True) | |
81 | - keywords = models.TextField(blank=True) | |
82 | - collaborators = models.TextField(blank=True) | |
83 | - created = models.DateTimeField(blank=True, null=True) | |
84 | - modified = models.DateTimeField(blank=True, null=True) | |
85 | - modified_by = models.TextField(blank=True) | |
86 | - | |
87 | - class Meta: | |
88 | - managed = False | |
89 | - db_table = 'ticket_view' | |
90 | - | |
91 | - def get_absolute_url(self): | |
92 | - return u'/ticket/{}'.format(self.id) | |
93 | - | |
94 | - def get_author(self): | |
95 | - try: | |
96 | - return User.objects.get(username=self.author) | |
97 | - except User.DoesNotExist: | |
98 | - return None | |
99 | - | |
100 | - def get_modified_by(self): | |
101 | - try: | |
102 | - return User.objects.get(username=self.modified_by) | |
103 | - except User.DoesNotExist: | |
104 | - return None | |
105 | - | |
106 | - | |
107 | -class Wiki(models.Model, HitCounterModelMixin): | |
108 | - name = models.TextField(primary_key=True) | |
109 | - wiki_text = models.TextField(blank=True) | |
110 | - author = models.TextField(blank=True) | |
111 | - collaborators = models.TextField(blank=True) | |
112 | - created = models.DateTimeField(blank=True, null=True) | |
113 | - modified = models.DateTimeField(blank=True, null=True) | |
114 | - modified_by = models.TextField(blank=True) | |
115 | - | |
116 | - class Meta: | |
117 | - managed = False | |
118 | - db_table = 'wiki_view' | |
119 | - | |
120 | - def get_absolute_url(self): | |
121 | - return u'/wiki/{}'.format(self.name) | |
122 | - | |
123 | - def get_author(self): | |
124 | - try: | |
125 | - return User.objects.get(username=self.author) | |
126 | - except User.DoesNotExist: | |
127 | - return None | |
128 | - | |
129 | - def get_modified_by(self): | |
130 | - try: | |
131 | - return User.objects.get(username=self.modified_by) | |
132 | - except User.DoesNotExist: | |
133 | - return None |
colab/plugins/trac/routers.py
... | ... | @@ -1,23 +0,0 @@ |
1 | -class TracRouter(object): | |
2 | - def db_for_read(self, model, **hints): | |
3 | - if model._meta.app_label == 'proxy': | |
4 | - return 'trac' | |
5 | - return None | |
6 | - | |
7 | - def db_for_write(self, model, **hints): | |
8 | - if model._meta.app_label == 'proxy': | |
9 | - return 'trac' | |
10 | - return None | |
11 | - | |
12 | - def allow_relation(self, obj1, obj2, **hints): | |
13 | - if obj1._meta.app_label == 'proxy' or \ | |
14 | - obj2._meta.app_label == 'proxy': | |
15 | - return True | |
16 | - return None | |
17 | - | |
18 | - def allow_migrate(self, db, model): | |
19 | - if db == 'trac': | |
20 | - return model._meta.app_label == 'proxy' | |
21 | - elif model._meta.app_label == 'proxy': | |
22 | - False | |
23 | - return None |
colab/plugins/trac/search_indexes.py
... | ... | @@ -1,155 +0,0 @@ |
1 | -# -*- coding: utf-8 -*- | |
2 | - | |
3 | -import string | |
4 | - | |
5 | -from django.template import loader, Context | |
6 | -from haystack import indexes | |
7 | -from haystack.utils import log as logging | |
8 | - | |
9 | -from colab.search.base_indexes import BaseIndex | |
10 | -from .models import Attachment, Ticket, Wiki, Revision | |
11 | - | |
12 | - | |
13 | -logger = logging.getLogger('haystack') | |
14 | - | |
15 | -# the string maketrans always return a string encoded with latin1 | |
16 | -# http://stackoverflow.com/questions/1324067/how-do-i-get-str-translate-to-work-with-unicode-strings # noqa | |
17 | -table = string.maketrans( | |
18 | - string.punctuation, | |
19 | - '.' * len(string.punctuation) | |
20 | -).decode('latin1') | |
21 | - | |
22 | - | |
23 | -class AttachmentIndex(BaseIndex, indexes.Indexable): | |
24 | - title = indexes.CharField(model_attr='filename') | |
25 | - description = indexes.CharField(model_attr='description', null=True) | |
26 | - modified = indexes.DateTimeField(model_attr='created', null=True) | |
27 | - used_by = indexes.CharField(model_attr='used_by', null=True, stored=False) | |
28 | - mimetype = indexes.CharField( | |
29 | - model_attr='mimetype', | |
30 | - null=True, | |
31 | - stored=False | |
32 | - ) | |
33 | - size = indexes.IntegerField(model_attr='size', null=True, stored=False) | |
34 | - filename = indexes.CharField(stored=False) | |
35 | - | |
36 | - def get_model(self): | |
37 | - return Attachment | |
38 | - | |
39 | - def get_updated_field(self): | |
40 | - return 'created' | |
41 | - | |
42 | - def prepare(self, obj): | |
43 | - data = super(AttachmentIndex, self).prepare(obj) | |
44 | - | |
45 | - try: | |
46 | - file_obj = open(obj.filepath) | |
47 | - except IOError as e: | |
48 | - logger.warning(u'IOError: %s - %s', e.strerror, e.filename) | |
49 | - return data | |
50 | - backend = self._get_backend(None) | |
51 | - | |
52 | - extracted_data = backend.extract_file_contents(file_obj) | |
53 | - file_obj.close() | |
54 | - | |
55 | - if not extracted_data: | |
56 | - return data | |
57 | - | |
58 | - t = loader.select_template( | |
59 | - ('search/indexes/proxy/attachment_text.txt', ) | |
60 | - ) | |
61 | - data['text'] = t.render(Context({ | |
62 | - 'object': obj, | |
63 | - 'extracted': extracted_data, | |
64 | - })) | |
65 | - return data | |
66 | - | |
67 | - def prepare_filename(self, obj): | |
68 | - return obj.filename.translate(table).replace('.', ' ') | |
69 | - | |
70 | - def prepare_icon_name(self, obj): | |
71 | - return u'file' | |
72 | - | |
73 | - def prepare_type(self, obj): | |
74 | - return u'attachment' | |
75 | - | |
76 | - | |
77 | -class WikiIndex(BaseIndex, indexes.Indexable): | |
78 | - title = indexes.CharField(model_attr='name') | |
79 | - collaborators = indexes.CharField( | |
80 | - model_attr='collaborators', | |
81 | - null=True, | |
82 | - stored=False, | |
83 | - ) | |
84 | - | |
85 | - def get_model(self): | |
86 | - return Wiki | |
87 | - | |
88 | - def prepare_description(self, obj): | |
89 | - return u'{}\n{}'.format(obj.wiki_text, obj.collaborators) | |
90 | - | |
91 | - def prepare_icon_name(self, obj): | |
92 | - return u'book' | |
93 | - | |
94 | - def prepare_type(self, obj): | |
95 | - return u'wiki' | |
96 | - | |
97 | - | |
98 | -class TicketIndex(BaseIndex, indexes.Indexable): | |
99 | - tag = indexes.CharField(model_attr='status', null=True) | |
100 | - milestone = indexes.CharField(model_attr='milestone', null=True) | |
101 | - component = indexes.CharField(model_attr='component', null=True) | |
102 | - severity = indexes.CharField(model_attr='severity', null=True) | |
103 | - reporter = indexes.CharField(model_attr='reporter', null=True) | |
104 | - keywords = indexes.CharField(model_attr='keywords', null=True) | |
105 | - collaborators = indexes.CharField( | |
106 | - model_attr='collaborators', | |
107 | - null=True, | |
108 | - stored=False, | |
109 | - ) | |
110 | - | |
111 | - def get_model(self): | |
112 | - return Ticket | |
113 | - | |
114 | - def prepare_description(self, obj): | |
115 | - return u'{}\n{}\n{}\n{}\n{}\n{}\n{}'.format( | |
116 | - obj.description, obj.milestone, obj.component, obj.severity, | |
117 | - obj.reporter, obj.keywords, obj.collaborators | |
118 | - ) | |
119 | - | |
120 | - def prepare_icon_name(self, obj): | |
121 | - return u'tag' | |
122 | - | |
123 | - def prepare_title(self, obj): | |
124 | - return u'#{} - {}'.format(obj.pk, obj.summary) | |
125 | - | |
126 | - def prepare_type(self, obj): | |
127 | - return 'ticket' | |
128 | - | |
129 | - | |
130 | -class RevisionIndex(BaseIndex, indexes.Indexable): | |
131 | - description = indexes.CharField(model_attr='message', null=True) | |
132 | - modified = indexes.DateTimeField(model_attr='created', null=True) | |
133 | - repository_name = indexes.CharField( | |
134 | - model_attr='repository_name', | |
135 | - stored=False | |
136 | - ) | |
137 | - | |
138 | - def get_model(self): | |
139 | - return Revision | |
140 | - | |
141 | - def get_updated_field(self): | |
142 | - return 'created' | |
143 | - | |
144 | - def get_boost(self, obj): | |
145 | - boost = super(RevisionIndex, self).get_boost(obj) | |
146 | - return boost * 0.8 | |
147 | - | |
148 | - def prepare_icon_name(self, obj): | |
149 | - return u'align-right' | |
150 | - | |
151 | - def prepare_title(self, obj): | |
152 | - return u'{} [{}]'.format(obj.repository_name, obj.rev) | |
153 | - | |
154 | - def prepare_type(self, obj): | |
155 | - return 'changeset' |
colab/plugins/trac/signals.py
... | ... | @@ -1,33 +0,0 @@ |
1 | - | |
2 | -from django.db import connections | |
3 | -from django.dispatch import receiver | |
4 | -from django.db.models.signals import post_save | |
5 | - | |
6 | -from colab.accounts.models import User | |
7 | - | |
8 | - | |
9 | -@receiver(post_save, sender=User) | |
10 | -def change_session_attribute_email(sender, instance, **kwargs): | |
11 | - cursor = connections['trac'].cursor() | |
12 | - | |
13 | - cursor.execute(("UPDATE session_attribute SET value=%s " | |
14 | - "WHERE name='email' AND sid=%s"), | |
15 | - [instance.email, instance.username]) | |
16 | - cursor.execute(("UPDATE session_attribute SET value=%s " | |
17 | - "WHERE name='name' AND sid=%s"), | |
18 | - [instance.get_full_name(), instance.username]) | |
19 | - | |
20 | - cursor.execute(("INSERT INTO session_attribute " | |
21 | - "(sid, authenticated, name, value) " | |
22 | - "SELECT %s, '1', 'email', %s WHERE NOT EXISTS " | |
23 | - "(SELECT 1 FROM session_attribute WHERE sid=%s " | |
24 | - "AND name='email')"), | |
25 | - [instance.username, instance.email, instance.username]) | |
26 | - | |
27 | - cursor.execute(("INSERT INTO session_attribute " | |
28 | - "(sid, authenticated, name, value) " | |
29 | - "SELECT %s, '1', 'name', %s WHERE NOT EXISTS " | |
30 | - "(SELECT 1 FROM session_attribute WHERE sid=%s " | |
31 | - "AND name='name')"), | |
32 | - [instance.username, instance.get_full_name(), | |
33 | - instance.username]) |
colab/plugins/trac/templates/proxy/trac.html
colab/plugins/trac/templates/search/indexes/proxy/attachment_text.txt
... | ... | @@ -1,15 +0,0 @@ |
1 | -{{ object.filename }} | |
2 | -{{ object.filename|slugify }} | |
3 | -{{ object.description }} | |
4 | -{{ object.description|slugify }} | |
5 | -{{ object.used_by }} | |
6 | -{{ object.mimetype }} | |
7 | -{{ object.get_author.get_full_name }} | |
8 | - | |
9 | -{% for k, v in extracted.metadata.items %} | |
10 | - {% for val in v %} | |
11 | - {{ k }}: {{ val|safe }} | |
12 | - {% endfor %} | |
13 | -{% endfor %} | |
14 | - | |
15 | -{{ extracted.contents|striptags|safe }} |
colab/plugins/trac/templates/search/indexes/proxy/revision_text.txt
... | ... | @@ -1,8 +0,0 @@ |
1 | -{{ object.repository_name }} | |
2 | -{{ object.repository_name|slugify }} | |
3 | -{{ object.rev }} | |
4 | -{{ object.rev|slugify }} | |
5 | -{% firstof object.get_author.get_full_name object.author %} | |
6 | -{% firstof object.get_author.get_full_name|slugify object.author|slugify %} | |
7 | -{{ object.message }} | |
8 | -{{ object.message|slugify }} |
colab/plugins/trac/templates/search/indexes/proxy/ticket_text.txt
... | ... | @@ -1,20 +0,0 @@ |
1 | -{{ object.summary }} | |
2 | -{{ object.summary|slugify }} | |
3 | -{{ object.description }} | |
4 | -{{ object.description|slugify }} | |
5 | -{{ object.milestone }} | |
6 | -{{ object.milestone|slugify }} | |
7 | -{{ object.component|slugify }} | |
8 | -{{ object.version }} | |
9 | -{{ object.severity }} | |
10 | -{{ object.severity|slugify }} | |
11 | -{{ object.reporter }} | |
12 | -{{ object.reporter|slugify }} | |
13 | -{% firstof object.get_author.get_fullname or object.author %} | |
14 | -{% firstof object.get_author.get_fullname|slugify or object.author|slugify %} | |
15 | -{{ object.status }} | |
16 | -{{ object.status|slugify }} | |
17 | -{{ object.keywords }} | |
18 | -{{ object.keywords|slugify }} | |
19 | -{{ object.collaborators }} | |
20 | -{{ object.collaborators|slugify }} |
colab/plugins/trac/templates/search/indexes/proxy/wiki_text.txt
... | ... | @@ -1,9 +0,0 @@ |
1 | -{{ object.author }} | |
2 | -{{ object.get_author.get_full_name }} | |
3 | -{{ object.get_author.get_full_name|slugify }} | |
4 | -{{ object.name }} | |
5 | -{{ object.name|slugify }} | |
6 | -{{ object.collaborators }} | |
7 | -{{ object.collaborators|slugify }} | |
8 | -{{ object.wiki_text }} | |
9 | -{{ object.wiki_text|slugify }} |
colab/plugins/trac/urls.py
colab/plugins/trac/views.py
... | ... | @@ -1,40 +0,0 @@ |
1 | - | |
2 | -from hitcounter.views import HitCounterViewMixin | |
3 | - | |
4 | -from ..utils.views import ColabProxyView | |
5 | -from .models import Wiki, Ticket, Revision | |
6 | - | |
7 | - | |
8 | -class TracProxyView(HitCounterViewMixin, ColabProxyView): | |
9 | - app_label = 'trac' | |
10 | - diazo_theme_template = 'proxy/trac.html' | |
11 | - | |
12 | - def get_object(self): | |
13 | - obj = None | |
14 | - | |
15 | - if self.request.path_info.startswith('/wiki'): | |
16 | - wiki_name = self.request.path_info.split('/', 2)[-1] | |
17 | - if not wiki_name: | |
18 | - wiki_name = 'WikiStart' | |
19 | - try: | |
20 | - obj = Wiki.objects.get(name=wiki_name) | |
21 | - except Wiki.DoesNotExist: | |
22 | - return None | |
23 | - elif self.request.path_info.startswith('/ticket'): | |
24 | - ticket_id = self.request.path_info.split('/')[2] | |
25 | - try: | |
26 | - obj = Ticket.objects.get(id=ticket_id) | |
27 | - except (Ticket.DoesNotExist, ValueError): | |
28 | - return None | |
29 | - elif self.request.path_info.startswith('/changeset'): | |
30 | - try: | |
31 | - changeset, repo = self.request.path_info.split('/')[2:4] | |
32 | - except ValueError: | |
33 | - return None | |
34 | - try: | |
35 | - obj = Revision.objects.get(rev=changeset, | |
36 | - repository_name=repo) | |
37 | - except Revision.DoesNotExist: | |
38 | - return None | |
39 | - | |
40 | - return obj |
colab/settings.py
... | ... | @@ -44,8 +44,6 @@ INSTALLED_APPS = ( |
44 | 44 | # Not standard apps |
45 | 45 | 'cliauth', |
46 | 46 | 'django_mobile', |
47 | - 'django_browserid', | |
48 | - 'conversejs', | |
49 | 47 | 'haystack', |
50 | 48 | 'hitcounter', |
51 | 49 | 'i18n_model', |
... | ... | @@ -58,7 +56,6 @@ INSTALLED_APPS = ( |
58 | 56 | 'colab.api', |
59 | 57 | 'colab.rss', |
60 | 58 | 'colab.search', |
61 | - 'colab.badger', | |
62 | 59 | 'colab.tz', |
63 | 60 | ) |
64 | 61 | |
... | ... | @@ -198,7 +195,6 @@ TEMPLATE_CONTEXT_PROCESSORS = ( |
198 | 195 | 'colab.home.context_processors.robots', |
199 | 196 | 'colab.home.context_processors.ribbon', |
200 | 197 | 'colab.home.context_processors.google_analytics', |
201 | - 'colab.home.context_processors.browserid_enabled', | |
202 | 198 | ) |
203 | 199 | |
204 | 200 | MIDDLEWARE_CLASSES = ( |
... | ... | @@ -213,13 +209,10 @@ MIDDLEWARE_CLASSES = ( |
213 | 209 | 'django_mobile.middleware.MobileDetectionMiddleware', |
214 | 210 | 'django_mobile.middleware.SetFlavourMiddleware', |
215 | 211 | 'colab.tz.middleware.TimezoneMiddleware', |
216 | - 'colab.accounts.middleware.UserRegisterMiddleware', | |
217 | 212 | ) |
218 | 213 | |
219 | -# Add the django_browserid authentication backend. | |
220 | 214 | AUTHENTICATION_BACKENDS = ( |
221 | 215 | 'django.contrib.auth.backends.ModelBackend', |
222 | - 'colab.accounts.auth.ColabBrowserIDBackend', | |
223 | 216 | ) |
224 | 217 | |
225 | 218 | LOCALE_PATHS = ( |
... | ... | @@ -247,27 +240,13 @@ SUPER_ARCHIVES_LOCK_FILE = '/var/lock/colab/import_emails.lock' |
247 | 240 | # Mailman API settings |
248 | 241 | MAILMAN_API_URL = 'http://localhost:8124' |
249 | 242 | |
250 | -# BrowserID / Persona | |
251 | -SITE_URL = 'http://localhost:8000' | |
252 | -BROWSERID_AUDIENCES = [SITE_URL, SITE_URL.replace('https', 'http')] | |
253 | - | |
254 | - | |
255 | 243 | LOGIN_URL = '/user/login' |
256 | 244 | LOGIN_REDIRECT_URL = '/' |
257 | 245 | LOGIN_REDIRECT_URL_FAILURE = '/?bid_login_failed=true' |
258 | 246 | LOGOUT_REDIRECT_URL = '/' |
259 | -BROWSERID_CREATE_USER = True | |
260 | 247 | |
261 | 248 | REVPROXY_ADD_REMOTE_USER = True |
262 | 249 | |
263 | -# Converse.js settings | |
264 | -# This URL must use SSL in order to keep chat sessions secure | |
265 | -CONVERSEJS_ENABLED = False | |
266 | -CONVERSEJS_BOSH_SERVICE_URL = SITE_URL + '/http-bind' | |
267 | - | |
268 | -CONVERSEJS_ALLOW_CONTACT_REQUESTS = False | |
269 | -CONVERSEJS_SHOW_ONLY_ONLINE_USERS = True | |
270 | - | |
271 | 250 | # Tastypie settings |
272 | 251 | TASTYPIE_DEFAULT_FORMATS = ['json', ] |
273 | 252 | |
... | ... | @@ -279,7 +258,6 @@ if locals().get('RAVEN_DSN', False): |
279 | 258 | } |
280 | 259 | INSTALLED_APPS += ('raven.contrib.django.raven_compat',) |
281 | 260 | |
282 | -BROWSERID_ENABLED = locals().get('BROWSERID_ENABLED') or False | |
283 | 261 | SOCIAL_NETWORK_ENABLED = locals().get('SOCIAL_NETWORK_ENABLED') or False |
284 | 262 | |
285 | 263 | locals().update(load_colab_apps()) | ... | ... |
colab/templates/base.html
1 | 1 | <!DOCTYPE html> |
2 | -{% load i18n browserid conversejs gravatar %} | |
2 | +{% load i18n gravatar plugins %} | |
3 | 3 | {% load static from staticfiles %} |
4 | 4 | |
5 | 5 | <html> |
... | ... | @@ -43,10 +43,6 @@ |
43 | 43 | {% block head_js %}{% endblock %} |
44 | 44 | {% block head_css %}{% endblock %} |
45 | 45 | |
46 | - {% if not is_mobile %} | |
47 | - {% conversejs_static %} | |
48 | - {% endif %} | |
49 | - | |
50 | 46 | <link rel="stylesheet" href="{% static 'css/screen.css' %}" |
51 | 47 | type="text/css" media="screen" /> |
52 | 48 | |
... | ... | @@ -54,10 +50,7 @@ |
54 | 50 | </head> |
55 | 51 | |
56 | 52 | <!-- data-no-turbolink will disable Rails TurboLinks for all pages under Colab --> |
57 | - <body data-no-turbolink> | |
58 | - {% if BROWSERID_ENABLED %} | |
59 | - {% browserid_info %} | |
60 | - {% endif %} | |
53 | + <body class="container" data-no-turbolink> | |
61 | 54 | |
62 | 55 | {% block ribbon %} |
63 | 56 | {% if ribbon %} |
... | ... | @@ -70,8 +63,82 @@ |
70 | 63 | {% endblock %} |
71 | 64 | |
72 | 65 | {% block navbar %} |
73 | - | |
74 | - {% include "header.html" %} | |
66 | + <nav class="navbar navbar-default navbar-fixed-top" role="navigation"> | |
67 | + <div class="container"> | |
68 | + <div class="navbar-header"> | |
69 | + | |
70 | + <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-main"> | |
71 | + <span class="sr-only">Toggle navigation</span> | |
72 | + <span class="icon-bar"></span> | |
73 | + <span class="icon-bar"></span> | |
74 | + <span class="icon-bar"></span> | |
75 | + <span class="icon-bar"></span> | |
76 | + </button> | |
77 | + <a class="navbar-brand" href="/"><img alt="Colab" src="{% static 'img/logo.svg' %}"></a> | |
78 | + </div> | |
79 | + <div class="collapse navbar-collapse navbar-main"> | |
80 | + <ul class="nav navbar-nav"> | |
81 | + | |
82 | + <li> | |
83 | + <a href="{% url 'thread_list' %}">{% trans "Groups" %}</a> | |
84 | + </li> | |
85 | + | |
86 | + {% plugins_menu %} | |
87 | + | |
88 | + <li class="hidden-lg hidden-md"> | |
89 | + <a href="{% url 'haystack_search' %}?q=">{% trans "Search" %}</a> | |
90 | + </li> | |
91 | + </ul> | |
92 | + | |
93 | + <ul class="nav navbar-nav navbar-right"> | |
94 | + {% if not user.is_authenticated %} | |
95 | + | |
96 | + <li class="dropdown hidden-xs hidden-lg"> | |
97 | + <a href="#" class="dropdown-toggle" data-toggle="dropdown">Acesso <b class="caret"></b></a> | |
98 | + <ul class="dropdown-menu"> | |
99 | + {% trans 'Login' as login_text %} | |
100 | + <li><a href="{% url 'signup' %}">{% trans "Register" %}</a></li> | |
101 | + <li><a href="{% url 'login' %}">{% trans "Login" %}</a></li> | |
102 | + </ul> | |
103 | + </li> | |
104 | + {% trans 'Login' as login_text %} | |
105 | + <li class="visible-xs hidden-sm hidden-md"><a href="{% url 'signup' %}">{% trans "Register" %}</a></li> | |
106 | + <li class="visible-xs hidden-sm hidden-md"><a href="{% url 'login' %}">{% trans "Login" %}</a></li> | |
107 | + {% else %} | |
108 | + <li id="user-menu" class="dropdown"> | |
109 | + <a href="#" class="dropdown-toggle user" data-toggle="dropdown">{% gravatar user.email 40 %} <b class="caret"></b> </a> | |
110 | + <ul class="dropdown-menu" role="menu"> | |
111 | + <li> | |
112 | + <div class="wrapper"> | |
113 | + <div class="thumbnail">{% gravatar user.email 100 %}</div> | |
114 | + <div class="user-info"> | |
115 | + <span><b>{{ user.get_full_name }}</b></span> | |
116 | + <span class="quiet">{{ user.email }}</span> | |
117 | + </div> | |
118 | + <div> | |
119 | + <a class="btn btn-info pull-left" href="{% url 'user_profile' user.username %}">{% trans "My Profile" %}</a> | |
120 | + {% trans 'Logout' as logout_text %} | |
121 | + <a class="btn btn-default pull-right" href="{% url 'logout' %}"> {% trans "Logout" %}</a> | |
122 | + </div> | |
123 | + </div> | |
124 | + </li> | |
125 | + </ul> | |
126 | + </li> | |
127 | + {% endif %} | |
128 | + </ul> | |
129 | + | |
130 | + <form action="{% url 'haystack_search' %}" method="GET" id="search-form" class="navbar-form navbar-right hidden-xs hidden-sm" role="search"> | |
131 | + <div class="form-group"> | |
132 | + <label class="sr-only" for="header-searchbox">{% trans 'Search here...' %}</label> | |
133 | + <input name="q" id="header-searchbox" | |
134 | + class="form-control" value="{{ request.GET.q }}" | |
135 | + type="search" placeholder="{% trans 'Search here...' %}" /> | |
136 | + </div> | |
137 | + <button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-search"></span></button> | |
138 | + </form> | |
139 | + </div> | |
140 | + </div> | |
141 | + </nav> | |
75 | 142 | |
76 | 143 | {% endblock %} |
77 | 144 | |
... | ... | @@ -107,19 +174,8 @@ |
107 | 174 | |
108 | 175 | {% endblock %} |
109 | 176 | |
110 | - {% if not is_mobile %} | |
111 | - {% conversejs_chatpanel %} | |
112 | - {% conversejs_initialize %} | |
113 | - {% endif %} | |
114 | - | |
115 | 177 | {% include "tz/set_utc_offset.html" %} |
116 | 178 | |
117 | - {% if BROWSERID_ENABLED %} | |
118 | - <script src="https://login.persona.org/include.js"></script> | |
119 | - <script src="{% static 'browserid/api.js' %}"></script> | |
120 | - <script src="{% static 'browserid/browserid.js' %}"></script> | |
121 | - {% endif %} | |
122 | - | |
123 | 179 | {% block footer_js %}{% endblock %} |
124 | 180 | </body> |
125 | 181 | </html> | ... | ... |
colab/templates/footer.html
colab/templates/header.html
1 | -{% load i18n browserid conversejs gravatar plugins %} | |
1 | +{% load i18n gravatar plugins %} | |
2 | 2 | {% load static from staticfiles %} |
3 | 3 | |
4 | 4 | <nav class="navbar navbar-default navbar-fixed-top" role="navigation"> |
... | ... | @@ -21,12 +21,6 @@ |
21 | 21 | <a href="{% url 'thread_list' %}">{% trans "Groups" %}</a> |
22 | 22 | </li> |
23 | 23 | |
24 | - {% if feedzilla %} | |
25 | - <li> | |
26 | - <a href="{% url "feedzilla_index" %}">{% trans "Blogs" %}</a> | |
27 | - </li> | |
28 | - {% endif %} | |
29 | - | |
30 | 24 | {% plugins_menu %} |
31 | 25 | |
32 | 26 | <li><a href="/paste">{% trans "Paste" %}</a></li> | ... | ... |
colab/urls.py
... | ... | @@ -30,16 +30,12 @@ urlpatterns = patterns('', |
30 | 30 | url(r'^myaccount/(?P<route>.*)$', |
31 | 31 | 'colab.accounts.views.myaccount_redirect', name='myaccount'), |
32 | 32 | |
33 | - url(r'', include('django_browserid.urls')), | |
34 | - | |
35 | 33 | # Uncomment the next line to enable the admin: |
36 | 34 | url(r'^colab/admin/', include(admin.site.urls)), |
37 | 35 | |
38 | - url(r'^trac/', include('colab.plugins.trac.urls')), | |
39 | 36 | url(r'^gitlab/', include('colab.plugins.gitlab.urls')), |
40 | 37 | url(r'^mezuro/', include('colab.plugins.mezuro.urls')), |
41 | 38 | url(r'^social/', include('colab.plugins.noosfero.urls')), |
42 | - url(r'^ci/', include('colab.plugins.jenkins.urls')), | |
43 | 39 | |
44 | 40 | url(r'', include('colab.plugins.urls')), |
45 | 41 | ) | ... | ... |
docs/source/user.rst
... | ... | @@ -139,31 +139,6 @@ Social Networks |
139 | 139 | When this variable is True, the social networks fields, like Facebook and |
140 | 140 | Twitter, are added in user profile. By default, this fields are disabled. |
141 | 141 | |
142 | -Auth | |
143 | -++++ | |
144 | -.. attribute:: BROWSERID_ENABLED | |
145 | - | |
146 | - :default: False | |
147 | - | |
148 | - When this variable is True, Colab use BrowserID authentication. By default, | |
149 | - django authentication system is used. | |
150 | - | |
151 | -.. attribute:: BROWSERID_AUDIENCES | |
152 | - | |
153 | - :default: No default | |
154 | - | |
155 | - List of audiences that your site accepts. An audience is the protocol, | |
156 | - domain name, and (optionally) port that users access your site from. This | |
157 | - list is used to determine the audience a user is part of (how they are | |
158 | - accessing your site), which is used during verification to ensure that the | |
159 | - assertion given to you by the user was intended for your site. | |
160 | - | |
161 | - Without this, other sites that the user has authenticated with via Persona | |
162 | - could use their assertions to impersonate the user on your site. | |
163 | - | |
164 | - Note that this does not have to be a publicly accessible URL, so local URLs | |
165 | - like ``http://localhost:8000`` or ``http://127.0.0.1`` are acceptable as | |
166 | - long as they match what you are using to access your site. | |
167 | 142 | |
168 | 143 | Customization |
169 | 144 | ------------- | ... | ... |
setup.py
... | ... | @@ -29,20 +29,8 @@ REQUIREMENTS = [ |
29 | 29 | 'raven==3.5.2', |
30 | 30 | 'tornado==3.1.1', |
31 | 31 | |
32 | - # Deps for Single SignOn (SSO) - Replaced with django-browserid==0.9 | |
33 | - 'django-browserid==0.11', | |
34 | 32 | 'django-revproxy==0.9.3', |
35 | 33 | |
36 | - # Converse.js (XMPP client) | |
37 | - 'django-conversejs==0.3.4', | |
38 | - | |
39 | - # Feedzilla (planet) and deps | |
40 | - 'django-common==0.1.51', | |
41 | - 'feedparser==5.1.3', | |
42 | - 'lxml==3.2.4', | |
43 | - 'grab==0.4.13', | |
44 | - 'transliterate==1.5', | |
45 | - | |
46 | 34 | # Diazo |
47 | 35 | 'diazo==1.0.5', |
48 | 36 | ... | ... |