Skip to content
Snippets Groups Projects
Commit efb7d92b authored by jan.bednarik's avatar jan.bednarik
Browse files

Exclude superseded reports from results and agregates

parent 4c34d202
No related branches found
No related tags found
No related merge requests found
......@@ -36,9 +36,7 @@ class SearchReportsConnection(relay.Connection):
def _get_authors_cache(ids):
authors = User.objects.filter(id__in=ids).annotate(
total_reports=Count("report", filter=Q(report__is_draft=False))
)
authors = User.objects.with_total_reports().filter(id__in=ids)
return {a.id: types.Author.from_db(a) for a in authors}
......
......@@ -154,9 +154,7 @@ class Author(graphene.ObjectType):
@classmethod
def get_node(cls, info, id):
try:
author = models.User.objects.annotate(
total_reports=Count("report", filter=Q(report__is_draft=False))
).get(id=id, is_author=True)
author = models.User.objects.with_total_reports().get(id=id, is_author=True)
return cls.from_db(author)
except models.User.DoesNotExist:
return None
......@@ -176,7 +174,9 @@ class Author(graphene.ObjectType):
return ReportConnection(page_info=page_info, edges=edges, total_count=total)
def resolve_total_reports(self, info, **kwargs):
return models.Report.objects.filter(author_id=self.id, is_draft=False).count()
return models.Report.objects.filter(
author_id=self.id, is_draft=False, superseded_by=None
).count()
class LoginShortcut(graphene.ObjectType):
......
......@@ -19,7 +19,7 @@ class ReportDoc(DocType):
other_participants = fields.TextField(analyzer=settings.ES_TEXT_ANALYZER)
# there is no support for JSONField now, so we serialize it to keyword
extra_serialized = fields.KeywordField()
superseded_by = fields.IntegerField()
superseded_by_id = fields.IntegerField()
def prepare_extra_serialized(self, instance):
return json.dumps(instance.extra)
......
......@@ -10,6 +10,14 @@ from django.utils import timezone
class CustomUserManager(UserManager):
def with_total_reports(self):
return self.get_queryset().annotate(
total_reports=Count(
"report",
filter=Q(report__is_draft=False) & Q(report__superseded_by=None),
)
)
def sorted(self, **kwargs):
# inline import intentionally
from openlobby.core.api.schema import (
......@@ -17,9 +25,7 @@ class CustomUserManager(UserManager):
AUTHOR_SORT_TOTAL_REPORTS_ID,
)
qs = self.get_queryset().annotate(
total_reports=Count("report", filter=Q(report__is_draft=False))
)
qs = self.with_total_reports()
sort_field = kwargs.get("sort", AUTHOR_SORT_LAST_NAME_ID)
if sort_field == AUTHOR_SORT_LAST_NAME_ID:
......
......@@ -19,6 +19,7 @@ def query_reports(query, paginator, *, highlight=False):
]
s = ReportDoc.search()
s = s.exclude("term", is_draft=True)
s = s.exclude("exists", field="superseded_by_id")
if query != "":
s = s.query("multi_match", query=query, fields=fields)
if highlight:
......@@ -31,6 +32,7 @@ def query_reports(query, paginator, *, highlight=False):
def reports_by_author(author_id, paginator):
s = ReportDoc.search()
s = s.exclude("term", is_draft=True)
s = s.exclude("exists", field="superseded_by_id")
s = s.filter("term", author_id=author_id)
s = s.sort("-date")
s = s[paginator.slice_from : paginator.slice_to]
......
......@@ -14,16 +14,16 @@ authors = [
},
{
"id": 2,
"username": "sponge",
"first_name": "Spongebob",
"last_name": "Squarepants",
"username": "shaun",
"first_name": "Shaun",
"last_name": "Sheep",
"is_author": True,
},
{
"id": 3,
"username": "shaun",
"first_name": "Shaun",
"last_name": "Sheep",
"username": "sponge",
"first_name": "Spongebob",
"last_name": "Squarepants",
"is_author": True,
},
]
......@@ -92,6 +92,47 @@ reports = [
"other_participants": "",
"is_draft": True,
},
{
"id": 6,
"superseded_by_id": 2,
"date": arrow.get(2018, 1, 3).datetime,
"published": arrow.get(2018, 1, 4).datetime,
"edited": arrow.get(2018, 2, 1).datetime,
"title": "The Two Towers",
"body": "Another long story in progress.",
"received_benefit": "Mithrill Jacket",
"provided_benefit": "The Ring",
"our_participants": "Frodo, Gimli, Legolas",
"other_participants": "Saruman, Sauron",
"extra": {"rings": 2},
},
{
"id": 7,
"superseded_by_id": 2,
"date": arrow.get(2018, 1, 3).datetime,
"published": arrow.get(2018, 1, 4).datetime,
"edited": arrow.get(2018, 2, 5).datetime,
"title": "The Towels",
"body": "What am I doing?",
"received_benefit": "Jacket",
"provided_benefit": "The Ringo",
"our_participants": "Ringo Starr",
"other_participants": "",
"extra": {"rings": 1},
},
{
"id": 8,
"superseded_by_id": 1,
"date": arrow.get(2018, 1, 1).datetime,
"published": arrow.get(2018, 1, 2).datetime,
"edited": arrow.get(2018, 1, 3).datetime,
"title": "The Fellowship of the Ringing Bell",
"body": "The bell is ringing!",
"received_benefit": "bell",
"provided_benefit": "noise",
"our_participants": "",
"other_participants": "",
},
]
......@@ -104,6 +145,9 @@ def prepare_reports():
Report.objects.create(author=author1, **reports[2])
Report.objects.create(author=author1, **reports[3])
Report.objects.create(author=author3, **reports[4])
Report.objects.create(author=author2, **reports[5])
Report.objects.create(author=author2, **reports[6])
Report.objects.create(author=author1, **reports[7])
def prepare_author():
......
......@@ -17,9 +17,9 @@ snapshots["test_all 1"] = {
"extra": None,
"firstName": "Shaun",
"hasCollidingName": False,
"id": "QXV0aG9yOjM=",
"id": "QXV0aG9yOjI=",
"lastName": "Sheep",
"totalReports": 0,
"totalReports": 1,
},
},
{
......@@ -28,9 +28,9 @@ snapshots["test_all 1"] = {
"extra": None,
"firstName": "Spongebob",
"hasCollidingName": False,
"id": "QXV0aG9yOjI=",
"id": "QXV0aG9yOjM=",
"lastName": "Squarepants",
"totalReports": 1,
"totalReports": 0,
},
},
{
......@@ -66,9 +66,9 @@ snapshots["test_first 1"] = {
"extra": None,
"firstName": "Shaun",
"hasCollidingName": False,
"id": "QXV0aG9yOjM=",
"id": "QXV0aG9yOjI=",
"lastName": "Sheep",
"totalReports": 0,
"totalReports": 1,
},
},
{
......@@ -77,9 +77,9 @@ snapshots["test_first 1"] = {
"extra": None,
"firstName": "Spongebob",
"hasCollidingName": False,
"id": "QXV0aG9yOjI=",
"id": "QXV0aG9yOjM=",
"lastName": "Squarepants",
"totalReports": 1,
"totalReports": 0,
},
},
],
......@@ -104,9 +104,9 @@ snapshots["test_first_after 1"] = {
"extra": None,
"firstName": "Spongebob",
"hasCollidingName": False,
"id": "QXV0aG9yOjI=",
"id": "QXV0aG9yOjM=",
"lastName": "Squarepants",
"totalReports": 1,
"totalReports": 0,
},
}
],
......@@ -142,9 +142,9 @@ snapshots["test_last_before 1"] = {
"extra": None,
"firstName": "Spongebob",
"hasCollidingName": False,
"id": "QXV0aG9yOjI=",
"id": "QXV0aG9yOjM=",
"lastName": "Squarepants",
"totalReports": 1,
"totalReports": 0,
},
}
],
......@@ -168,19 +168,8 @@ snapshots["test_with_reports 1"] = {
"extra": None,
"firstName": "Shaun",
"hasCollidingName": False,
"id": "QXV0aG9yOjM=",
"lastName": "Sheep",
"reports": {"edges": [], "totalCount": 0},
"totalReports": 0,
}
},
{
"node": {
"extra": None,
"firstName": "Spongebob",
"hasCollidingName": False,
"id": "QXV0aG9yOjI=",
"lastName": "Squarepants",
"lastName": "Sheep",
"reports": {
"edges": [
{
......@@ -206,6 +195,17 @@ snapshots["test_with_reports 1"] = {
"totalReports": 1,
}
},
{
"node": {
"extra": None,
"firstName": "Spongebob",
"hasCollidingName": False,
"id": "QXV0aG9yOjM=",
"lastName": "Squarepants",
"reports": {"edges": [], "totalCount": 0},
"totalReports": 0,
}
},
{
"node": {
"extra": '{"movies": 1}',
......@@ -270,9 +270,9 @@ snapshots["test_sort_by_last_name 1"] = {
"extra": None,
"firstName": "Shaun",
"hasCollidingName": False,
"id": "QXV0aG9yOjM=",
"id": "QXV0aG9yOjI=",
"lastName": "Sheep",
"totalReports": 0,
"totalReports": 1,
},
},
{
......@@ -281,9 +281,9 @@ snapshots["test_sort_by_last_name 1"] = {
"extra": None,
"firstName": "Spongebob",
"hasCollidingName": False,
"id": "QXV0aG9yOjI=",
"id": "QXV0aG9yOjM=",
"lastName": "Squarepants",
"totalReports": 1,
"totalReports": 0,
},
},
{
......@@ -330,9 +330,9 @@ snapshots["test_sort_by_last_name_reversed 1"] = {
"extra": None,
"firstName": "Spongebob",
"hasCollidingName": False,
"id": "QXV0aG9yOjI=",
"id": "QXV0aG9yOjM=",
"lastName": "Squarepants",
"totalReports": 1,
"totalReports": 0,
},
},
{
......@@ -341,9 +341,9 @@ snapshots["test_sort_by_last_name_reversed 1"] = {
"extra": None,
"firstName": "Shaun",
"hasCollidingName": False,
"id": "QXV0aG9yOjM=",
"id": "QXV0aG9yOjI=",
"lastName": "Sheep",
"totalReports": 0,
"totalReports": 1,
},
},
],
......@@ -377,10 +377,10 @@ snapshots["test_sort_by_total_reports 1"] = {
"cursor": "Mg==",
"node": {
"extra": None,
"firstName": "Spongebob",
"firstName": "Shaun",
"hasCollidingName": False,
"id": "QXV0aG9yOjI=",
"lastName": "Squarepants",
"lastName": "Sheep",
"totalReports": 1,
},
},
......@@ -388,10 +388,10 @@ snapshots["test_sort_by_total_reports 1"] = {
"cursor": "Mw==",
"node": {
"extra": None,
"firstName": "Shaun",
"firstName": "Spongebob",
"hasCollidingName": False,
"id": "QXV0aG9yOjM=",
"lastName": "Sheep",
"lastName": "Squarepants",
"totalReports": 0,
},
},
......@@ -415,10 +415,10 @@ snapshots["test_sort_by_total_reports_reversed 1"] = {
"cursor": "MQ==",
"node": {
"extra": None,
"firstName": "Shaun",
"firstName": "Spongebob",
"hasCollidingName": False,
"id": "QXV0aG9yOjM=",
"lastName": "Sheep",
"lastName": "Squarepants",
"totalReports": 0,
},
},
......@@ -426,10 +426,10 @@ snapshots["test_sort_by_total_reports_reversed 1"] = {
"cursor": "Mg==",
"node": {
"extra": None,
"firstName": "Spongebob",
"firstName": "Shaun",
"hasCollidingName": False,
"id": "QXV0aG9yOjI=",
"lastName": "Squarepants",
"lastName": "Sheep",
"totalReports": 1,
},
},
......@@ -477,9 +477,9 @@ snapshots["test_sort_by_default_reversed 1"] = {
"extra": None,
"firstName": "Spongebob",
"hasCollidingName": False,
"id": "QXV0aG9yOjI=",
"id": "QXV0aG9yOjM=",
"lastName": "Squarepants",
"totalReports": 1,
"totalReports": 0,
},
},
{
......@@ -488,9 +488,9 @@ snapshots["test_sort_by_default_reversed 1"] = {
"extra": None,
"firstName": "Shaun",
"hasCollidingName": False,
"id": "QXV0aG9yOjM=",
"id": "QXV0aG9yOjI=",
"lastName": "Sheep",
"totalReports": 0,
"totalReports": 1,
},
},
],
......
......@@ -41,10 +41,10 @@ snapshots["test_all 1"] = {
"node": {
"author": {
"extra": None,
"firstName": "Spongebob",
"firstName": "Shaun",
"hasCollidingName": False,
"id": "QXV0aG9yOjI=",
"lastName": "Squarepants",
"lastName": "Sheep",
"totalReports": 1,
},
"body": "Another long story.",
......@@ -107,10 +107,10 @@ snapshots["test_query 1"] = {
"node": {
"author": {
"extra": None,
"firstName": "Spongebob",
"firstName": "Shaun",
"hasCollidingName": False,
"id": "QXV0aG9yOjI=",
"lastName": "Squarepants",
"lastName": "Sheep",
"totalReports": 1,
},
"body": "Another long story.",
......
......@@ -10,6 +10,8 @@ from openlobby.core.api.schema import (
from openlobby.core.documents import ReportDoc
from openlobby.core.models import Report, User, OpenIdClient, LoginAttempt
from .dummy import prepare_reports
pytestmark = [pytest.mark.django_db, pytest.mark.usefixtures("django_es")]
......@@ -34,6 +36,7 @@ def test_report__is_saved_in_elasticsearch():
date = arrow.get(2018, 1, 1).datetime
published = arrow.get(2018, 1, 2).datetime
edited = arrow.get(2018, 1, 3).datetime
replacement = Report.objects.create(id=4, author=author, date=date, body="IDDQD")
Report.objects.create(
id=3,
author=author,
......@@ -48,12 +51,14 @@ def test_report__is_saved_in_elasticsearch():
other_participants="them",
extra={"a": 3},
is_draft=False,
superseded_by=replacement,
)
docs = list(ReportDoc.search())
assert len(docs) == 1
doc = docs[0]
assert len(docs) == 2
doc = docs[1]
assert doc.meta.id == "3"
assert doc.author_id == 6
assert doc.superseded_by_id == 4
assert doc.date == date
assert doc.published == published
assert doc.edited == edited
......@@ -141,74 +146,39 @@ def test_user__name_collision_excludes_self_on_update():
assert User.objects.get(username="a").has_colliding_name is False
def test_user__sorted_default():
User.objects.create(
username="a", is_author=False, first_name="Ryan", last_name="AGosling"
)
User.objects.create(
username="b", is_author=True, first_name="Ryan", last_name="BGosling"
)
User.objects.create(
username="c", is_author=False, first_name="Ryan", last_name="CGosling"
)
assert User.objects.sorted()[0].username == "a"
def test_user__sorted_default_reversed():
User.objects.create(
username="a", is_author=False, first_name="Ryan", last_name="AGosling"
)
User.objects.create(
username="b", is_author=True, first_name="Ryan", last_name="BGosling"
)
User.objects.create(
username="c", is_author=False, first_name="Ryan", last_name="CGosling"
)
assert User.objects.sorted(reversed=True)[0].username == "c"
def test_user__sorted_last_name():
User.objects.create(
username="a", is_author=False, first_name="Ryan", last_name="AGosling"
)
User.objects.create(
username="b", is_author=True, first_name="Ryan", last_name="BGosling"
)
User.objects.create(
username="c", is_author=False, first_name="Ryan", last_name="CGosling"
)
assert User.objects.sorted(sort=AUTHOR_SORT_LAST_NAME_ID)[0].username == "a"
assert (
User.objects.sorted(sort=AUTHOR_SORT_LAST_NAME_ID, reversed=False)[0].username
== "a"
)
assert (
User.objects.sorted(sort=AUTHOR_SORT_LAST_NAME_ID, reversed=True)[0].username
== "c"
)
def test_user__sorted_total_reports():
author = User.objects.create(
username="a", is_author=True, first_name="Ryan", last_name="AGosling"
)
User.objects.create(
username="b", is_author=True, first_name="Ryan", last_name="BGosling"
)
date = arrow.get(2018, 1, 1).datetime
Report.objects.create(
id=7, author=author, date=date, published=date, body="Lorem ipsum."
)
assert User.objects.sorted(sort=AUTHOR_SORT_TOTAL_REPORTS_ID)[0].username == "a"
assert (
User.objects.sorted(sort=AUTHOR_SORT_TOTAL_REPORTS_ID, reversed=False)[
0
].username
== "a"
)
assert (
User.objects.sorted(sort=AUTHOR_SORT_TOTAL_REPORTS_ID, reversed=True)[
0
].username
== "b"
)
@pytest.mark.parametrize(
"params, expected",
[
({}, ["Sheep", "Squarepants", "Wolfe"]),
({"reversed": False}, ["Sheep", "Squarepants", "Wolfe"]),
({"reversed": True}, ["Wolfe", "Squarepants", "Sheep"]),
({"sort": AUTHOR_SORT_LAST_NAME_ID}, ["Sheep", "Squarepants", "Wolfe"]),
(
{"sort": AUTHOR_SORT_LAST_NAME_ID, "reversed": False},
["Sheep", "Squarepants", "Wolfe"],
),
(
{"sort": AUTHOR_SORT_LAST_NAME_ID, "reversed": True},
["Wolfe", "Squarepants", "Sheep"],
),
({"sort": AUTHOR_SORT_TOTAL_REPORTS_ID}, ["Wolfe", "Sheep", "Squarepants"]),
(
{"sort": AUTHOR_SORT_TOTAL_REPORTS_ID, "reversed": False},
["Wolfe", "Sheep", "Squarepants"],
),
(
{"sort": AUTHOR_SORT_TOTAL_REPORTS_ID, "reversed": True},
["Squarepants", "Sheep", "Wolfe"],
),
],
)
def test_user__sorted(params, expected):
prepare_reports()
last_names = User.objects.sorted(**params).values_list("last_name", flat=True)
assert list(last_names) == expected
def test_user__with_total_reports():
prepare_reports()
users = User.objects.with_total_reports().values_list("last_name", "total_reports")
assert set(users) == {("Wolfe", 2), ("Sheep", 1), ("Squarepants", 0)}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment