зеркало из https://github.com/mozilla/kitsune.git
[584937] Flags are not deleted for deleted objects.
Also: * cleans up a TODO for edit question in the flagged_question.html template. * checks if content_object is set before attempting to show it. Downside is that we won't find integrity errors if they occur otherwise, but those shouldn't occur in the first place.
This commit is contained in:
Родитель
ed55bcb294
Коммит
fe5acbcd0a
|
@ -11,7 +11,7 @@
|
|||
<h3>{{ _('Take Action:') }}</h3>
|
||||
<div class="actions">
|
||||
<a href="{{ object.content_object.get_absolute_url() }}">View</a>
|
||||
<a href="# {# TODO: depends on Erik's patch that adds edit question #}">Edit</a>
|
||||
<a href="{{ url('questions.edit_question', object.content_object.id) }}">Edit</a>
|
||||
{% if user.has_perm('questions.delete_question') %}
|
||||
<a class="delete" href="{{ url('questions.delete', object.content_object.id) }}">{{ _('Delete') }}</a>
|
||||
{% endif %}
|
||||
|
|
|
@ -9,25 +9,29 @@
|
|||
{% for object in objects %}
|
||||
{% if loop.first %}<ul>{% endif %}
|
||||
<li class="{{ object.content_type }}">
|
||||
<hgroup>
|
||||
<h2>{{ _('Flagged {t} (Reason: {r})')|f(t=object.content_type, r=object.get_reason_display()) }}</h2>
|
||||
{% if object.notes %}
|
||||
<h3 class="notes">{{ _('Other reason:') }} {{ object.notes }}</h3>
|
||||
{% endif %}
|
||||
</hgroup>
|
||||
<div class="wrap">
|
||||
{% include 'flagit/includes/flagged_%s.html' % object.content_type %}
|
||||
<h3>{{ _('Update Status:') }}</h3>
|
||||
<form class="update" action="{{ url('flagit.update', object.id) }}" method="post">
|
||||
{{ csrf() }}
|
||||
<select name="status">
|
||||
<option value="">{{ _('Please select...') }}</option>
|
||||
<option value="1">{{ _('The flag is valid and I fixed the issue.') }}</option>
|
||||
<option value="2">{{ _('The flag is invalid.') }}</option>
|
||||
</select>
|
||||
<input type="submit" class="btn g-btn" value="Update" />
|
||||
</form>
|
||||
</div>
|
||||
{% if object.content_object %}
|
||||
<hgroup>
|
||||
<h2>{{ _('Flagged {t} (Reason: {r})')|f(t=object.content_type, r=object.get_reason_display()) }}</h2>
|
||||
{% if object.notes %}
|
||||
<h3 class="notes">{{ _('Other reason:') }} {{ object.notes }}</h3>
|
||||
{% endif %}
|
||||
</hgroup>
|
||||
<div class="wrap">
|
||||
{% include 'flagit/includes/flagged_%s.html' % object.content_type %}
|
||||
<h3>{{ _('Update Status:') }}</h3>
|
||||
<form class="update" action="{{ url('flagit.update', object.id) }}" method="post">
|
||||
{{ csrf() }}
|
||||
<select name="status">
|
||||
<option value="">{{ _('Please select...') }}</option>
|
||||
<option value="1">{{ _('The flag is valid and I fixed the issue.') }}</option>
|
||||
<option value="2">{{ _('The flag is invalid.') }}</option>
|
||||
</select>
|
||||
<input type="submit" class="btn g-btn" value="Update" />
|
||||
</form>
|
||||
</div>
|
||||
{% else %}
|
||||
{{ _('Oops! {t} {id} no longer exists.')|f(t=object.content_type, id=object.object_id) }}
|
||||
{% endif %}
|
||||
</li>
|
||||
{% if loop.last %}</ul>{% endif %}
|
||||
{% else %}
|
||||
|
|
|
@ -11,6 +11,7 @@ from django.contrib.contenttypes import generic
|
|||
import product_details
|
||||
from taggit.models import Tag
|
||||
|
||||
from flagit.models import FlaggedObject
|
||||
from notifications import create_watch
|
||||
from notifications.tasks import delete_watches
|
||||
from sumo.models import ModelBase, TaggableMixin
|
||||
|
@ -54,6 +55,7 @@ class Question(ModelBase, TaggableMixin):
|
|||
confirmation_id = models.CharField(max_length=40, db_index=True)
|
||||
|
||||
images = generic.GenericRelation(ImageAttachment)
|
||||
flags = generic.GenericRelation(FlaggedObject)
|
||||
|
||||
class Meta:
|
||||
ordering = ['-updated']
|
||||
|
@ -252,6 +254,7 @@ class Answer(ModelBase):
|
|||
upvotes = models.IntegerField(default=0, db_index=True)
|
||||
|
||||
images = generic.GenericRelation(ImageAttachment)
|
||||
flags = generic.GenericRelation(FlaggedObject)
|
||||
|
||||
class Meta:
|
||||
ordering = ['created']
|
||||
|
|
|
@ -6,6 +6,7 @@ from notifications import check_watch
|
|||
import sumo.models
|
||||
from taggit.models import Tag
|
||||
|
||||
from flagit.models import FlaggedObject
|
||||
from questions.models import (Question, QuestionMetaData, Answer,
|
||||
_tenths_version)
|
||||
from questions.tags import add_existing_tag
|
||||
|
@ -37,6 +38,39 @@ class TestAnswer(TestCaseBase):
|
|||
|
||||
question.delete()
|
||||
|
||||
def test_delete_question_removes_flag(self):
|
||||
"""Deleting a question also removes the flags on that question."""
|
||||
question = Question(title='Test Question',
|
||||
content='Lorem Ipsum Dolor',
|
||||
creator_id=118533)
|
||||
question.save()
|
||||
FlaggedObject.objects.create(
|
||||
status=0, content_object=question,
|
||||
reason='language', creator_id=118533)
|
||||
eq_(1, FlaggedObject.objects.count())
|
||||
|
||||
question.delete()
|
||||
eq_(0, FlaggedObject.objects.count())
|
||||
|
||||
def test_delete_answer_removes_flag(self):
|
||||
"""Deleting an answer also removes the flags on that answer."""
|
||||
question = Question(title='Test Question',
|
||||
content='Lorem Ipsum Dolor',
|
||||
creator_id=118533)
|
||||
question.save()
|
||||
|
||||
answer = Answer(question=question, creator_id=47963,
|
||||
content="Test Answer")
|
||||
answer.save()
|
||||
|
||||
FlaggedObject.objects.create(
|
||||
status=0, content_object=answer,
|
||||
reason='language', creator_id=118533)
|
||||
eq_(1, FlaggedObject.objects.count())
|
||||
|
||||
answer.delete()
|
||||
eq_(0, FlaggedObject.objects.count())
|
||||
|
||||
def test_delete_last_answer_of_question(self):
|
||||
"""Deleting the last_answer of a Question should update the question.
|
||||
"""
|
||||
|
@ -91,6 +125,7 @@ class TestAnswer(TestCaseBase):
|
|||
|
||||
eq_(answer.creator_num_answers, 1)
|
||||
|
||||
|
||||
class TestQuestionMetadata(TestCaseBase):
|
||||
"""Tests handling question metadata"""
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
-- Delete orphaned flags on questions
|
||||
DELETE FROM
|
||||
flagit_flaggedobject
|
||||
WHERE
|
||||
object_id NOT IN
|
||||
(
|
||||
SELECT
|
||||
q.id
|
||||
FROM
|
||||
questions_question q
|
||||
)
|
||||
AND content_type_id =
|
||||
(
|
||||
SELECT
|
||||
id
|
||||
FROM
|
||||
django_content_type
|
||||
WHERE
|
||||
name = 'question'
|
||||
AND app_label = 'questions'
|
||||
);
|
||||
|
||||
|
||||
-- Delete orphaned flags on answers
|
||||
DELETE FROM
|
||||
flagit_flaggedobject
|
||||
WHERE
|
||||
object_id NOT IN
|
||||
(
|
||||
SELECT
|
||||
a.id
|
||||
FROM
|
||||
questions_answer a
|
||||
)
|
||||
AND content_type_id =
|
||||
(
|
||||
SELECT
|
||||
id
|
||||
FROM
|
||||
django_content_type
|
||||
WHERE
|
||||
name = 'answer'
|
||||
AND app_label = 'questions'
|
||||
);
|
Загрузка…
Ссылка в новой задаче