diff --git a/askbot/management/commands/askbot_create_per_email_domain_groups.py b/askbot/management/commands/askbot_create_per_email_domain_groups.py index 635029b98e..e51078d13f 100644 --- a/askbot/management/commands/askbot_create_per_email_domain_groups.py +++ b/askbot/management/commands/askbot_create_per_email_domain_groups.py @@ -1,8 +1,8 @@ """A management command that creates groups for each email domain in the database.""" from django.core.management.base import BaseCommand -from askbot.conf import settings -from askbot.models import User -from askbot.models.analytics import get_organization_domains +from askbot.conf import settings as askbot_settings +from askbot.models import Group, User +from askbot.models.analytics import get_unique_user_email_domains_qs from askbot.models.user import get_organization_name_from_domain from askbot.utils.console import ProgressBar @@ -14,14 +14,31 @@ def handle(self, *args, **options): # pylint: disable=missing-docstring, unused- Creates a group for each domain name, if such group does not exist. Group visibility is set to the value of settings.PER_EMAIL_DOMAIN_GROUP_DEFAULT_VISIBILITY. """ - domains = get_organization_domains() + domains = get_unique_user_email_domains_qs() count = len(domains) - message = 'Initializing groups by the email address domain names' - for domain in ProgressBar(domains, count, message): - organization_name = get_organization_name_from_domain(domain) - group = User.objects.get_or_create_group( - organization_name, - visibility=settings.PER_EMAIL_DOMAIN_GROUP_DEFAULT_VISIBILITY + message = 'Creating groups by the email address domain names' + created_groups = [] + unchanged_groups = [] + done_lowercased_domains = [] + for domain in ProgressBar(domains.iterator(), count, message): + + domain_name = domain['domain'] + if domain_name.lower in done_lowercased_domains: + continue + else: + done_lowercased_domains.append(domain_name.lower()) + + organization_name = get_organization_name_from_domain(domain_name) + group, created = Group.objects.get_or_create( + name=organization_name, + visibility=askbot_settings.PER_EMAIL_DOMAIN_GROUP_DEFAULT_VISIBILITY ) - print('Group {0} created.'.format(group.name)) + users = User.objects.filter(email__endswith='@' + domain_name) + for user in users.iterator(): + user.join_group(group, force=True) + + if created: + created_groups.append(group) + else: + unchanged_groups.append(group) diff --git a/askbot/media/js/utils/lang_nav.js b/askbot/media/js/utils/lang_nav.js index ee3e851c34..178bd965d2 100644 --- a/askbot/media/js/utils/lang_nav.js +++ b/askbot/media/js/utils/lang_nav.js @@ -13,7 +13,7 @@ LangNav.prototype.translateUrl = function(url, lang) { type: 'GET', url: askbot['urls']['translateUrl'], data: {'url': url, 'language': lang }, - async: false, + async: false, //important! cache: false, dataType: 'json', success: function(data) { diff --git a/askbot/models/__init__.py b/askbot/models/__init__.py index 7b02b63584..d69fd7bdfc 100644 --- a/askbot/models/__init__.py +++ b/askbot/models/__init__.py @@ -2946,7 +2946,7 @@ def user_join_default_groups(self): group = Group.objects.get_global_group() self.join_group(group, force=True) group_name = format_personal_group_name(self) - group = Group.objects.get_or_create(name=group_name, user=self) + group, _ = Group.objects.get_or_create(name=group_name, user=self) self.join_group(group, force=True) def user_get_personal_group(self): diff --git a/askbot/models/analytics.py b/askbot/models/analytics.py index e1ff49d7f2..7d029d51be 100644 --- a/askbot/models/analytics.py +++ b/askbot/models/analytics.py @@ -90,7 +90,7 @@ def get_non_admins_count(): return non_admins.count() -def get_organization_domains(): +def get_unique_user_email_domains_qs(): """Returns the query set of organization domain names""" domain_annotation = Substr('email', StrIndex('email', Value('@')) + 1) return User.objects.annotate(domain=domain_annotation).values('domain').distinct() @@ -102,7 +102,12 @@ def get_organizations_count(): """ if not django_settings.ASKBOT_ANALYTICS_EMAIL_DOMAIN_ORGANIZATIONS_ENABLED: return 0 - return get_organization_domains().count() + return get_unique_user_email_domains_qs().count() + + +def get_unique_user_email_domains(): + """Returns a list of unique email domain names""" + return list(get_user_organization_domains_qs().values_list('domain', flat=True)) class Session(models.Model): diff --git a/askbot/models/user.py b/askbot/models/user.py index 6a87cb2dce..8c69a8c3fe 100644 --- a/askbot/models/user.py +++ b/askbot/models/user.py @@ -89,7 +89,7 @@ def remove_email_from_invited_moderators(email): """Update the `INVITED_MODERATORS` setting by removing the matching email entry""" lines = askbot_settings.INVITED_MODERATORS.strip().split('\n') - clean_lines = list() + clean_lines = [] prefix = email + ' ' for line in lines: if not line.startswith(prefix): @@ -157,7 +157,7 @@ def fetch_content_objects_dict(self): """return a dictionary where keys are activity ids and values - content objects""" content_object_ids = defaultdict(list)# lists of c.object ids by c.types - activity_type_ids = dict()#links c.objects back to activity objects + activity_type_ids = {} #links c.objects back to activity objects for act in self: content_type_id = act.content_type_id object_id = act.object_id @@ -165,7 +165,7 @@ def fetch_content_objects_dict(self): activity_type_ids[(content_type_id, object_id)] = act.id #3) get links from activity objects to content objects - objects_by_activity = dict() + objects_by_activity = {} for content_type_id, object_id_list in list(content_object_ids.items()): content_type = ContentType.objects.get_for_id(content_type_id) model_class = content_type.model_class() @@ -193,7 +193,7 @@ def create_new_mention( ): #todo: automate this using python inspect module - kwargs = dict() + kwargs = {} kwargs['activity_type'] = const.TYPE_ACTIVITY_MENTION @@ -241,7 +241,7 @@ def get_mentions( todo: implement better rich field lookups """ - kwargs = dict() + kwargs = {} kwargs['activity_type'] = const.TYPE_ACTIVITY_MENTION @@ -571,21 +571,26 @@ def create(self, **kwargs): kwargs['group_ptr'] = group_ptr except AuthGroup.DoesNotExist: pass - return super(GroupManager, self).create(**kwargs) + return super().create(**kwargs) - def get_or_create(self, name=None, user=None, openness=None): + def get_or_create(self, name=None, user=None, openness=None, visibility=None): """creates a group tag or finds one, if exists""" #todo: here we might fill out the group profile try: - #iexact is important!!! b/c we don't want case variants - #of tags + #iexact is important!!! b/c we don't want case variants of groups group = self.get(name__iexact = name) + created = False except self.model.DoesNotExist: + default_visibility = askbot_settings.PER_EMAIL_DOMAIN_GROUP_DEFAULT_VISIBILITY + if visibility is None: + visibility = default_visibility + if openness is None: - group = self.create(name=name) - else: - group = self.create(name=name, openness=openness) - return group + openness = self.model.DEFAULT_OPENNESS + + group = self.create(name=name, openness=openness, visibility=visibility) + created = True + return group, created class Group(AuthGroup): @@ -593,6 +598,7 @@ class Group(AuthGroup): OPEN = 0 MODERATED = 1 CLOSED = 2 + DEFAULT_OPENNESS = CLOSED OPENNESS_CHOICES = ( (OPEN, 'open'), (MODERATED, 'moderated'), @@ -610,7 +616,7 @@ class Group(AuthGroup): can_upload_attachments = models.BooleanField(default=False) can_upload_images = models.BooleanField(default=False) - openness = models.SmallIntegerField(default=CLOSED, choices=OPENNESS_CHOICES) + openness = models.SmallIntegerField(default=DEFAULT_OPENNESS, choices=OPENNESS_CHOICES) visibility = models.SmallIntegerField(default=const.GROUP_VISIBILITY_PUBLIC, choices=const.GROUP_VISIBILITY_CHOICES) @@ -695,27 +701,27 @@ def clean(self): emails = functions.split_list(self.preapproved_emails) email_field = EmailField() try: - list(map(lambda v: email_field.clean(v), emails)) - except exceptions.ValidationError: + list(map(email_field.clean, emails)) + except exceptions.ValidationError as exc: raise exceptions.ValidationError( _('Please give a list of valid email addresses.') - ) + ) from exc self.preapproved_emails = ' ' + '\n'.join(emails) + ' ' domains = functions.split_list(self.preapproved_email_domains) from askbot.forms import DomainNameField domain_field = DomainNameField() try: - list(map(lambda v: domain_field.clean(v), domains)) - except exceptions.ValidationError: + list(map(domain_field.clean, domains)) + except exceptions.ValidationError as exc: raise exceptions.ValidationError( _('Please give a list of valid email domain names.') - ) + ) from exc self.preapproved_email_domains = ' ' + '\n'.join(domains) + ' ' def save(self, *args, **kwargs): self.clean() - super(Group, self).save(*args, **kwargs) + super().save(*args, **kwargs) class BulkTagSubscriptionManager(BaseQuerySetManager): # pylint: disable=too-few-public-methods @@ -735,7 +741,7 @@ def create( user_list = user_list or [] group_list = group_list or [] - new_object = super(BulkTagSubscriptionManager, self).create(**kwargs) + new_object = super().create(**kwargs) tag_name_list = [] if tag_names: diff --git a/askbot/tests/test_management_commands.py b/askbot/tests/test_management_commands.py index 855c3ba32c..c44d59813c 100644 --- a/askbot/tests/test_management_commands.py +++ b/askbot/tests/test_management_commands.py @@ -376,3 +376,15 @@ def test_askbot_send_moderation_alerts1(self): #command sends alerts to three moderators at a time self.assertEqual(len(mail.outbox), 2) self.assertTrue('moderation' in mail.outbox[0].subject) + + + def test_askbot_create_per_email_domain_groups(self): + user1 = self.create_user('org1', 'user@org1.com') + user2 = self.create_user('org2', 'user@org2.com') + count = models.Group.objects.filter(name__in=('Org1', 'Org2')).count() + self.assertEqual(count, 0) + management.call_command('askbot_create_per_email_domain_groups') + count = models.Group.objects.filter(name__in=('Org1', 'Org2')).count() + self.assertEqual(count, 2) + + diff --git a/askbot/tests/test_markup.py b/askbot/tests/test_markup.py index 55d09a0546..02fb05de1a 100644 --- a/askbot/tests/test_markup.py +++ b/askbot/tests/test_markup.py @@ -130,7 +130,5 @@ def test_convert_mixed_text(self): """ """
http://example.com
""" - import pdb - pdb.set_trace() converted = self.conv(text) self.assertHTMLEqual(converted, expected) diff --git a/askbot/tests/test_thread_model.py b/askbot/tests/test_thread_model.py index 1983207829..93d11988c7 100644 --- a/askbot/tests/test_thread_model.py +++ b/askbot/tests/test_thread_model.py @@ -29,7 +29,7 @@ def setUp(self): self.user.new_response_count = 0 self.user.seen_response_count = 0 self.user.save() - self.group = models.Group.objects.get_or_create(name='jockeys') + self.group = models.Group.objects.get_or_create(name='jockeys')[0] self.group.can_post_questions = True self.group.can_post_answers = True self.group.can_post_comments = True diff --git a/askbot/tests/utils.py b/askbot/tests/utils.py index a2b8945ed3..01bf336966 100644 --- a/askbot/tests/utils.py +++ b/askbot/tests/utils.py @@ -316,9 +316,7 @@ def create_tag(self, tag_name, user = None): return tag def create_group(self, group_name=None, openness=models.Group.OPEN): - return models.Group.objects.get_or_create( - name='private', openness=openness - ) + return models.Group.objects.get_or_create(name='private', openness=openness)[0] def post_comment( self, diff --git a/askbot/utils/decorators.py b/askbot/utils/decorators.py index 57bae7c5e0..3578b80306 100644 --- a/askbot/utils/decorators.py +++ b/askbot/utils/decorators.py @@ -87,7 +87,7 @@ def wrapper(request, *args, **kwargs): data = view_func(request, *args, **kwargs) if data is None: data = {} - except Exception as e: + except Exception as e: # pylint: disable=broad-except #todo: also check field called "message" if hasattr(e, 'messages'): if len(e.messages) > 1: diff --git a/askbot/utils/http.py b/askbot/utils/http.py index 19be07b34f..dfaf2024da 100644 --- a/askbot/utils/http.py +++ b/askbot/utils/http.py @@ -1,12 +1,25 @@ """http-related utilities for askbot """ from copy import copy +from askbot.conf import settings as askbot_settings def is_ajax(request): """Returns `True` if request is ajax""" return request.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest' +def can_save_draft(request): + """Returns `True` if the user is allowed to save drafts""" + return not any(( + request.user.is_anonymous, + request.user.is_read_only(), + not request.user.is_active, + request.user.is_blocked(), + request.user.is_suspended(), + askbot_settings.READ_ONLY_MODE_ENABLED, + )) + + def hide_passwords(data): """replaces content of values that may contain passsword with XXXXXX for better security""" diff --git a/askbot/views/commands.py b/askbot/views/commands.py index 9eca744500..7e858cd9d7 100644 --- a/askbot/views/commands.py +++ b/askbot/views/commands.py @@ -5,36 +5,32 @@ Not so clear if this subdivision was necessary as separation of Ajax and non-ajax views is not always very clean. """ +import json import logging from bs4 import BeautifulSoup -from django.conf import settings as django_settings from django.core import exceptions #from django.core.management import call_command from django.urls import reverse from django.contrib.auth.decorators import login_required from django.http import Http404 from django.http import HttpResponse -from django.http import HttpResponseBadRequest from django.http import HttpResponseRedirect from django.http import HttpResponseForbidden -from django.forms import ValidationError, IntegerField, CharField +from django.forms import IntegerField, CharField, ValidationError from django.shortcuts import get_object_or_404 from django.shortcuts import render from django.template.loader import get_template from django.views.decorators import csrf -import json +from django.urls import resolve, Resolver404, NoReverseMatch from django.utils import timezone from django.utils import translation -from django.utils.encoding import force_str from django.utils.html import escape from django.utils.translation import gettext as _ -from django.utils.translation import ngettext from askbot.utils.slug import slugify from askbot import models from askbot import forms from askbot import conf from askbot import const -from askbot import mail from askbot.conf import settings as askbot_settings from askbot.utils import category_tree from askbot.utils import decorators @@ -42,9 +38,8 @@ from askbot.utils.forms import get_db_object_or_404 from askbot.utils.functions import decode_and_loads from askbot.utils.html import get_login_link -from askbot.utils.http import is_ajax +from askbot.utils.http import is_ajax, can_save_draft from askbot import spam_checker -from django.template import RequestContext from askbot.skins.shortcuts import render_into_skin_as_string from askbot.skins.shortcuts import render_text_into_skin from askbot.models.tag import get_tags_by_names @@ -511,7 +506,7 @@ def subscribe_for_tags(request): def list_bulk_tag_subscription(request): if askbot_settings.SUBSCRIBED_TAG_SELECTOR_ENABLED is False: raise Http404 - object_list = models.BulkTagSubscription.objects.all() + object_list = models.BulkTagSubscription.objects.all() # pylint: disable=no-member data = {'object_list': object_list} return render(request, 'tags/list_bulk_tag_subscription.html', data) @@ -718,7 +713,7 @@ def api_get_questions(request): if askbot_settings.GROUPS_ENABLED: threads = models.Thread.objects.get_visible(user=request.user) else: - threads = models.Thread.objects.all() + threads = models.Thread.objects.all() # pylint: disable=no-member if tag_name: threads = threads.filter(tags__name=tag_name) @@ -729,7 +724,7 @@ def api_get_questions(request): #todo: filter out deleted threads, for now there is no way threads = threads.distinct()[:30] - thread_list = list() + thread_list = [] for thread in threads:#todo: this is a temp hack until thread model is fixed try: thread_list.append({ @@ -941,7 +936,7 @@ def save_group_logo_url(request): if form.is_valid(): group_id = form.cleaned_data['group_id'] image_url = form.cleaned_data['image_url'] - group = models.Group.objects.get(id = group_id) + group = models.Group.objects.get(id=group_id) group.logo_url = image_url group.save() else: @@ -954,7 +949,7 @@ def save_group_logo_url(request): def add_group(request): group_name = request.POST.get('group') if group_name: - group = models.Group.objects.get_or_create( + group, _ = models.Group.objects.get_or_create( name=group_name, openness=models.Group.OPEN, user=request.user, @@ -972,7 +967,7 @@ def add_group(request): @decorators.moderators_only def delete_group_logo(request): group_id = IntegerField().clean(int(request.POST['group_id'])) - group = models.Group.objects.get(id = group_id) + group = models.Group.objects.get(id=group_id) # pylint: disable=no-member group.logo_url = None group.save() @@ -983,7 +978,7 @@ def delete_group_logo(request): @decorators.moderators_only def delete_post_reject_reason(request): reason_id = IntegerField().clean(int(request.POST['reason_id'])) - reason = models.PostFlagReason.objects.get(id = reason_id) + reason = models.PostFlagReason.objects.get(id=reason_id) # pylint: disable=no-member reason.delete() @@ -1090,26 +1085,27 @@ def save_post_reject_reason(request): otherwise a reason with the given id is edited and saved """ form = forms.EditRejectReasonForm(request.POST) + if form.is_valid(): - title = form.cleaned_data['title'] - details = form.cleaned_data['details'] - if form.cleaned_data['reason_id'] is None: - reason = request.user.create_post_reject_reason( - title = title, details = details - ) - else: - reason_id = form.cleaned_data['reason_id'] - reason = models.PostFlagReason.objects.get(id = reason_id) - request.user.edit_post_reject_reason( - reason, title = title, details = details - ) - return { - 'reason_id': reason.id, - 'title': title, - 'details': details - } + raise ValidationError(forms.format_form_errors(form)) + + title = form.cleaned_data['title'] + details = form.cleaned_data['details'] + if form.cleaned_data['reason_id'] is None: + reason = request.user.create_post_reject_reason( + title = title, details = details + ) else: - raise Exception(forms.format_form_errors(form)) + reason_id = form.cleaned_data['reason_id'] + reason = models.PostFlagReason.objects.get(id = reason_id) # pylint: disable=no-member + request.user.edit_post_reject_reason( + reason, title = title, details = details + ) + return { + 'reason_id': reason.id, + 'title': title, + 'details': details + } @csrf.csrf_protect @decorators.ajax_only @@ -1122,51 +1118,52 @@ def moderate_suggested_tag(request): otherwise the decision applies to all threads """ form = forms.ModerateTagForm(request.POST) + if form.is_valid(): - tag_id = form.cleaned_data['tag_id'] - thread_id = form.cleaned_data.get('thread_id', None) + raise ValidationError(forms.format_form_errors(form)) - lang = translation.get_language() + tag_id = form.cleaned_data['tag_id'] + thread_id = form.cleaned_data.get('thread_id', None) - try: - tag = models.Tag.objects.get( - id=tag_id, - language_code=lang - )#can tag not exist? - except models.Tag.DoesNotExist: - return - - if thread_id: - threads = models.Thread.objects.filter( - id=thread_id, - language_code=lang - ) - else: - threads = tag.threads.none() + lang = translation.get_language() - if form.cleaned_data['action'] == 'accept': - #todo: here we lose ability to come back - #to the tag moderation and approve tag to - #other threads later for the case where tag.used_count > 1 - tag.status = models.Tag.STATUS_ACCEPTED - tag.save() - for thread in threads: - thread.add_tag( - tag_name=tag.name, - user=tag.created_by, - timestamp=timezone.now(), - silent=True - ) - else: - if tag.threads.count() > len(threads): - for thread in threads: - thread.tags.remove(tag) - tag.used_count = tag.threads.count() - tag.save() - elif tag.status == models.Tag.STATUS_SUGGESTED: - tag.delete() + try: + tag = models.Tag.objects.get( # pylint: disable=no-member + id=tag_id, + language_code=lang + )#can tag not exist? + except models.Tag.DoesNotExist: # pylint: disable=no-member + return + + if thread_id: + threads = models.Thread.objects.filter( # pylint: disable=no-member + id=thread_id, + language_code=lang + ) else: - raise Exception(forms.format_form_errors(form)) + threads = tag.threads.none() + + if form.cleaned_data['action'] == 'accept': + #todo: here we lose ability to come back + #to the tag moderation and approve tag to + #other threads later for the case where tag.used_count > 1 + tag.status = models.Tag.STATUS_ACCEPTED + tag.save() + for thread in threads: + thread.add_tag( + tag_name=tag.name, + user=tag.created_by, + timestamp=timezone.now(), + silent=True + ) + else: + if tag.threads.count() > len(threads): + for thread in threads: + thread.tags.remove(tag) + tag.used_count = tag.threads.count() + tag.save() + elif tag.status == models.Tag.STATUS_SUGGESTED: + tag.delete() @csrf.csrf_protect @@ -1174,31 +1171,27 @@ def moderate_suggested_tag(request): @decorators.post_only def save_draft_question(request): """saves draft questions""" - #todo: maybe allow drafts for anonymous users - if request.user.is_anonymous \ - or request.user.is_read_only() \ - or askbot_settings.READ_ONLY_MODE_ENABLED \ - or request.user.is_active == False \ - or request.user.is_blocked() \ - or request.user.is_suspended(): + if not can_save_draft(request): return form = forms.DraftQuestionForm(request.POST) - if form.is_valid(): - title = form.cleaned_data.get('title', '') - text = form.cleaned_data.get('text', '') - tagnames = form.cleaned_data.get('tagnames', '') - if title or text or tagnames: - try: - draft = models.DraftQuestion.objects.get(author=request.user) - except models.DraftQuestion.DoesNotExist: - draft = models.DraftQuestion() + if not form.is_valid(): + return + + title = form.cleaned_data.get('title', '') + text = form.cleaned_data.get('text', '') + tagnames = form.cleaned_data.get('tagnames', '') + if title or text or tagnames: + try: + draft = models.DraftQuestion.objects.get(author=request.user) # pylint: disable=no-member + except models.DraftQuestion.DoesNotExist: # pylint: disable=no-member + draft = models.DraftQuestion() - draft.title = title - draft.text = text - draft.tagnames = tagnames - draft.author = request.user - draft.save() + draft.title = title + draft.text = text + draft.tagnames = tagnames + draft.author = request.user + draft.save() @csrf.csrf_protect @@ -1207,33 +1200,30 @@ def save_draft_question(request): def save_draft_answer(request): """saves draft answers""" #todo: maybe allow drafts for anonymous users - if request.user.is_anonymous \ - or request.user.is_read_only() \ - or askbot_settings.READ_ONLY_MODE_ENABLED \ - or request.user.is_active == False \ - or request.user.is_blocked() \ - or request.user.is_suspended(): + if not can_save_draft(request.user): return form = forms.DraftAnswerForm(request.POST) - if form.is_valid(): - thread_id = form.cleaned_data['thread_id'] - try: - thread = models.Thread.objects.get(id=thread_id) - except models.Thread.DoesNotExist: - return - try: - draft = models.DraftAnswer.objects.get( - thread=thread, - author=request.user - ) - except models.DraftAnswer.DoesNotExist: - draft = models.DraftAnswer() + if not form.is_valid(): + return - draft.author = request.user - draft.thread = thread - draft.text = form.cleaned_data.get('text', '') - draft.save() + thread_id = form.cleaned_data['thread_id'] + try: + thread = models.Thread.objects.get(id=thread_id) # pylint: disable=no-member + except models.Thread.DoesNotExist: # pylint: disable=no-member + return + try: + draft = models.DraftAnswer.objects.get( # pylint: disable=no-member + thread=thread, + author=request.user + ) + except models.DraftAnswer.DoesNotExist: # pylint: disable=no-member + draft = models.DraftAnswer() + + draft.author = request.user + draft.thread = thread + draft.text = form.cleaned_data.get('text', '') + draft.save() @decorators.get_only def get_users_info(request): @@ -1261,84 +1251,86 @@ def get_users_info(request): def share_question_with_group(request): form = forms.ShareQuestionForm(request.POST) try: - if form.is_valid(): - - thread_id = form.cleaned_data['thread_id'] - group_name = form.cleaned_data['recipient_name'] - - thread = models.Thread.objects.get(id=thread_id) - question_post = thread._question_post() + if not form.is_valid(): + raise ValueError('invalid form data') - #get notif set before - sets1 = question_post.get_notify_sets( - mentioned_users=list(), - exclude_list=[request.user,] - ) + thread_id = form.cleaned_data['thread_id'] + group_name = form.cleaned_data['recipient_name'] - #share the post - if group_name == askbot_settings.GLOBAL_GROUP_NAME: - thread.make_public(recursive=True) - else: - group = models.Group.objects.get(name=group_name) - thread.add_to_groups((group,), recursive=True) + thread = models.Thread.objects.get(id=thread_id) + question_post = thread._question_post() # pylint: disable=protected-access - #get notif sets after - sets2 = question_post.get_notify_sets( - mentioned_users=list(), - exclude_list=[request.user,] - ) + #get notif set before + sets1 = question_post.get_notify_sets( + mentioned_users=[], + exclude_list=[request.user,] + ) - notify_sets = { - 'for_mentions': sets2['for_mentions'] - sets1['for_mentions'], - 'for_email': sets2['for_email'] - sets1['for_email'], - 'for_inbox': sets2['for_inbox'] - sets1['for_inbox'] - } + #share the post + if group_name == askbot_settings.GLOBAL_GROUP_NAME: + thread.make_public(recursive=True) + else: + group = models.Group.objects.get(name=group_name) + thread.add_to_groups((group,), recursive=True) + + #get notif sets after + sets2 = question_post.get_notify_sets( + mentioned_users=[], + exclude_list=[request.user,] + ) + + notify_sets = { + 'for_mentions': sets2['for_mentions'] - sets1['for_mentions'], + 'for_email': sets2['for_email'] - sets1['for_email'], + 'for_inbox': sets2['for_inbox'] - sets1['for_inbox'] + } - question_post.issue_update_notifications( - updated_by=request.user, - notify_sets=notify_sets, - activity_type=const.TYPE_ACTIVITY_POST_SHARED, - timestamp=timezone.now() - ) + question_post.issue_update_notifications( + updated_by=request.user, + notify_sets=notify_sets, + activity_type=const.TYPE_ACTIVITY_POST_SHARED, + timestamp=timezone.now() + ) - return HttpResponseRedirect(thread.get_absolute_url()) - except Exception: + except Exception: # pylint: disable=broad-except error_message = _('Sorry, looks like sharing request was invalid') request.user.message_set.create(message=error_message) - return HttpResponseRedirect(thread.get_absolute_url()) + + return HttpResponseRedirect(thread.get_absolute_url()) @csrf.csrf_protect def share_question_with_user(request): form = forms.ShareQuestionForm(request.POST) try: - if form.is_valid(): + if not form.is_valid(): + raise ValueError('invalid form data') - thread_id = form.cleaned_data['thread_id'] - username = form.cleaned_data['recipient_name'] - - thread = models.Thread.objects.get(id=thread_id) - user = models.User.objects.get(username=username) - group = user.get_personal_group() - thread.add_to_groups([group], recursive=True) - #notify the person - #todo: see if user could already see the post - b/f the sharing - notify_sets = { - 'for_inbox': set([user]), - 'for_mentions': set([user]), - 'for_email': set([user]) - } - thread._question_post().issue_update_notifications( - updated_by=request.user, - notify_sets=notify_sets, - activity_type=const.TYPE_ACTIVITY_POST_SHARED, - timestamp=timezone.now() - ) + thread_id = form.cleaned_data['thread_id'] + username = form.cleaned_data['recipient_name'] + + thread = models.Thread.objects.get(id=thread_id) + user = models.User.objects.get(username=username) + group = user.get_personal_group() + thread.add_to_groups([group], recursive=True) + #notify the person + #todo: see if user could already see the post - b/f the sharing + notify_sets = { + 'for_inbox': set([user]), + 'for_mentions': set([user]), + 'for_email': set([user]) + } + thread._question_post().issue_update_notifications( # pylint: disable=protected-access + updated_by=request.user, + notify_sets=notify_sets, + activity_type=const.TYPE_ACTIVITY_POST_SHARED, + timestamp=timezone.now() + ) - return HttpResponseRedirect(thread.get_absolute_url()) - except Exception: + except Exception: # pylint: disable=broad-except error_message = _('Sorry, looks like sharing request was invalid') request.user.message_set.create(message=error_message) - return HttpResponseRedirect(thread.get_absolute_url()) + + return HttpResponseRedirect(thread.get_absolute_url()) @csrf.csrf_protect def moderate_group_join_request(request): @@ -1352,7 +1344,7 @@ def moderate_group_join_request(request): applicant = activity.user if group.has_moderator(request.user): - group_membership = models.GroupMembership.objects.get( + group_membership = models.GroupMembership.objects.get( # pylint: disable=no-member user=applicant, group=group ) if action == 'approve': @@ -1394,7 +1386,7 @@ def get_editor(request): #we need that, because js needs to be added in a special way html_soup = BeautifulSoup(editor_html, 'html5lib') - parsed_scripts = list() + parsed_scripts = [] for script in html_soup.find_all('script'): parsed_scripts.append({ 'contents': script.string, @@ -1479,10 +1471,10 @@ def merge_questions(request): @decorators.ajax_only @decorators.get_only def translate_url(request): + """Attempts to return url specific to the requested language""" form = forms.TranslateUrlForm(request.GET) match = None if form.is_valid(): - from django.urls import resolve, Resolver404, NoReverseMatch try: match = resolve(form.cleaned_data['url']) except Resolver404: @@ -1494,14 +1486,11 @@ def translate_url(request): site_lang = translation.get_language() translation.activate(lang) - if match.url_name == 'questions' and None in list(match.kwargs.values()): - #??? - url = models.get_feed_url(match.kwargs['feed']) - else: - try: - url = reverse(match.url_name, args=match.args, kwargs=match.kwargs) - except: - pass + try: + url = reverse(match.url_name, args=match.args, kwargs=match.kwargs) + except NoReverseMatch: + pass + translation.activate(site_lang) return {'url': url} @@ -1520,8 +1509,8 @@ def reorder_badges(request): if form.is_valid(): badge_id = form.cleaned_data['badge_id'] position = form.cleaned_data['position'] - badge = models.BadgeData.objects.get(id=badge_id) - badges = list(models.BadgeData.objects.all()) + badge = models.BadgeData.objects.get(id=badge_id) # pylint: disable=no-member + badges = list(models.BadgeData.objects.all()) # pylint: disable=no-member badges = [v for v in badges if v.is_enabled()] badges.remove(badge) badges.insert(position, badge)