def flag(self, request, object, flag_type, explanation, recipients=None): """Create a flag for a content item, if the unique request hasn't already done so before.""" if flag_type not in dict(FLAG_REASONS): return (None, False) content_type = ContentType.objects.get_for_model(object) user, ip, user_agent, unique_hash = get_unique(content_type, object.pk, request=request) defaults = dict(content_type=content_type, object_pk=object.pk, ip=ip, user_agent=user_agent, user=user, flag_type=flag_type, explanation=explanation) cf = ContentFlag.objects.get_or_create(unique_hash=unique_hash, defaults=defaults) if recipients: subject = _("%(object)s Flagged") % {'object': object} # Note: This returns a Jinja2 template b/c of jingo.Loader. t = loader.get_template('contentflagging/email/flagged.ltxt') url = '/admin/contentflagging/contentflag/%s' % object.pk content = t.render({'url': url, 'object': object, 'flag_type': flag_type}) send_mail(subject, content, settings.DEFAULT_FROM_EMAIL, recipients) return cf
def flag(self, request, object, flag_type, explanation, recipients=None): """Create a flag for a content item, if the unique request hasn't already done so before.""" if flag_type not in dict(FLAG_REASONS): return (None, False) content_type = ContentType.objects.get_for_model(object) user, ip, user_agent, unique_hash = get_unique(content_type, object.pk, request=request) defaults = dict(content_type=content_type, object_pk=object.pk, ip=ip, user_agent=user_agent, user=user, flag_type=flag_type, explanation=explanation) cf = ContentFlag.objects.get_or_create(unique_hash=unique_hash, defaults=defaults) if recipients: subject = _("%(object)s Flagged") % {'object': object} # Note: This returns a Jinja2 template b/c of jingo.Loader. t = loader.get_template('contentflagging/email/flagged.ltxt') url = '/admin/contentflagging/contentflag/%s' % object.pk content = t.render({ 'url': url, 'object': object, 'flag_type': flag_type }) send_mail(subject, content, settings.DEFAULT_FROM_EMAIL, recipients) return cf
def save(self, *args, **kwargs): # Ensure unique_hash is updated whenever the object is saved user, ip, user_agent, unique_hash = get_unique( self.content_type, self.object_pk, ip=self.ip, user_agent=self.user_agent, user=self.user) self.unique_hash = unique_hash super(ContentFlag, self).save(*args, **kwargs)
def save(self, *args, **kwargs): # Ensure unique_hash is updated whenever the object is saved user, ip, user_agent, unique_hash = get_unique( self.content_type, self.object_pk, name=self.name, ip=self.ip, user_agent=self.user_agent, user=self.user) self.unique_hash = unique_hash super(ActionCounterUnique, self).save(*args, **kwargs)
def get_unique_for_request(self, object, action_name, request, create=True): """ Get a unique counter for the given request, with the option to refrain from creating a new one if the intent is just to check existence. """ content_type = ContentType.objects.get_for_model(object) user, ip, user_agent, unique_hash = get_unique(content_type, object.pk, name=action_name, request=request) if create: return self.get_or_create( unique_hash=unique_hash, defaults=dict( content_type=content_type, object_pk=object.pk, name=action_name, ip=ip, user_agent=user_agent, user=user, total=0, ), ) else: try: return (self.get(unique_hash=unique_hash), False) except ActionCounterUnique.DoesNotExist: return (None, False)
def test_bug694544(self): """Bug 694544: unicode character in request details should not break""" try: request = _mock_request(user_agent=u"Some\xef\xbf\xbdbrowser") obj_1 = self.user2 obj_1_ct = ContentType.objects.get_for_model(obj_1) user, ip, user_agent, unique_hash = get_unique(obj_1_ct, obj_1.pk, request=request) except UnicodeDecodeError: ok_(False, "UnicodeDecodeError should not be thrown")
def test_bug694544(self): """Bug 694544: unicode character in request details should not break""" try: request = _mock_request(user_agent=u"Some\xef\xbf\xbdbrowser") obj_1 = self.user2 obj_1_ct = ContentType.objects.get_for_model(obj_1) user, ip, user_agent, unique_hash = get_unique(obj_1_ct, obj_1.pk, request=request) except UnicodeDecodeError: ok_(False, "UnicodeDecodeError should not be thrown")
def test_bad_multiple_counters(self): """ Force multiple counters, possibly result of race condition, ensure graceful handling """ action_name = "likes" obj_1 = self.obj_1 obj_1_ct = ContentType.objects.get_for_model(obj_1) request = self.mk_request() user, ip, user_agent, unique_hash = get_unique(obj_1_ct, obj_1.pk, name=action_name, request=request) # Create an initial counter record directly. u1 = ActionCounterUnique(content_type=obj_1_ct, object_pk=obj_1.pk, name=action_name, total=1, ip=ip, user_agent=user_agent, user=user) u1.save() # Adding a duplicate counter should be prevented at the model level. try: u2 = ActionCounterUnique(content_type=obj_1_ct, object_pk=obj_1.pk, name=action_name, total=1, ip=ip, user_agent=user_agent, user=user) u2.save() ok_(False, "This should have triggered an IntegrityError") except: pass # Try get_unique_for_request, which should turn up the single unique # record created earlier. try: (u, created) = ActionCounterUnique.objects.get_unique_for_request( obj_1, action_name, request) eq_(False, created) except MultipleObjectsReturned: ok_(False, "MultipleObjectsReturned should not be raised")
def test_bad_multiple_flags(self): """ Force multiple flags, possibly result of race condition, ensure graceful handling """ request = _mock_request() obj_1 = self.user2 obj_1_ct = ContentType.objects.get_for_model(obj_1) user, ip, user_agent, unique_hash = get_unique(obj_1_ct, obj_1.pk, request=request) # Create an initial record directly. f1 = ContentFlag(content_type=obj_1_ct, object_pk=obj_1.pk, flag_type="Broken thing", ip=ip, user_agent=user_agent, user=user) f1.save() # Adding a duplicate should be prevented at the model level. try: f2 = ContentFlag(content_type=obj_1_ct, object_pk=obj_1.pk, flag_type="Broken thing", ip=ip, user_agent=user_agent, user=user) f2.save() except IntegrityError: pass # Try flag, which should turn up the single unique record created # earlier. try: flag, created = ContentFlag.objects.flag( request=request, object=obj_1, flag_type='notworking', explanation="It really not go!") ok_(flag is not None) ok_(not created) except MultipleObjectsReturned: ok_(False, "MultipleObjectsReturned should not be raised")
def get_unique_for_request(self, object, action_name, request, create=True): """ Get a unique counter for the given request, with the option to refrain from creating a new one if the intent is just to check existence. """ content_type = ContentType.objects.get_for_model(object) user, ip, user_agent, unique_hash = get_unique(content_type, object.pk, name=action_name, request=request) if create: return self.get_or_create( unique_hash=unique_hash, defaults=dict(content_type=content_type, object_pk=object.pk, name=action_name, ip=ip, user_agent=user_agent, user=user, total=0)) else: try: return (self.get(unique_hash=unique_hash), False) except ActionCounterUnique.DoesNotExist: return (None, False)
def test_bad_multiple_counters(self): """ Force multiple counters, possibly result of race condition, ensure graceful handling """ action_name = "likes" obj_1 = self.obj_1 obj_1_ct = ContentType.objects.get_for_model(obj_1) request = self.mk_request() user, ip, user_agent, unique_hash = get_unique(obj_1_ct, obj_1.pk, name=action_name, request=request) # Create an initial counter record directly. u1 = ActionCounterUnique(content_type=obj_1_ct, object_pk=obj_1.pk, name=action_name, total=1, ip=ip, user_agent=user_agent, user=user) u1.save() # Adding a duplicate counter should be prevented at the model level. try: u2 = ActionCounterUnique(content_type=obj_1_ct, object_pk=obj_1.pk, name=action_name, total=1, ip=ip, user_agent=user_agent, user=user) u2.save() ok_(False, "This should have triggered an IntegrityError") except: pass # Try get_unique_for_request, which should turn up the single unique # record created earlier. try: (u, created) = ActionCounterUnique.objects.get_unique_for_request( obj_1, action_name, request) eq_(False, created) except MultipleObjectsReturned: ok_(False, "MultipleObjectsReturned should not be raised")
def test_bad_multiple_flags(self): """ Force multiple flags, possibly result of race condition, ensure graceful handling """ request = _mock_request() obj_1 = self.user2 obj_1_ct = ContentType.objects.get_for_model(obj_1) user, ip, user_agent, unique_hash = get_unique(obj_1_ct, obj_1.pk, request=request) # Create an initial record directly. f1 = ContentFlag(content_type=obj_1_ct, object_pk=obj_1.pk, flag_type="Broken thing", ip=ip, user_agent=user_agent, user=user) f1.save() # Adding a duplicate should be prevented at the model level. try: f2 = ContentFlag(content_type=obj_1_ct, object_pk=obj_1.pk, flag_type="Broken thing", ip=ip, user_agent=user_agent, user=user) f2.save() except IntegrityError: pass # Try flag, which should turn up the single unique record created # earlier. try: flag, created = ContentFlag.objects.flag( request=request, object=obj_1, flag_type='notworking', explanation="It really not go!") ok_(flag is not None) ok_(not created) except MultipleObjectsReturned: ok_(False, "MultipleObjectsReturned should not be raised")