Refactoring likes, votes, watchers and favourites names

remotes/origin/logger
Alejandro Alonso 2015-09-30 15:06:15 +02:00 committed by David Barragán Merino
parent 37c9a2fe6e
commit da8024141b
31 changed files with 459 additions and 350 deletions

View File

@ -34,8 +34,8 @@ from taiga.projects.history.mixins import HistoryResourceMixin
from taiga.projects.notifications.mixins import WatchedResourceMixin, WatchersViewSetMixin from taiga.projects.notifications.mixins import WatchedResourceMixin, WatchersViewSetMixin
from taiga.projects.notifications.choices import NotifyLevel from taiga.projects.notifications.choices import NotifyLevel
from taiga.projects.notifications.utils import ( from taiga.projects.notifications.utils import (
attach_project_watchers_attrs_to_queryset, attach_project_total_watchers_attrs_to_queryset,
attach_project_is_watched_to_queryset, attach_project_is_watcher_to_queryset,
attach_notify_level_to_project_queryset) attach_notify_level_to_project_queryset)
from taiga.projects.mixins.ordering import BulkUpdateOrderMixin from taiga.projects.mixins.ordering import BulkUpdateOrderMixin
@ -69,9 +69,9 @@ class ProjectViewSet(LikedResourceMixin, HistoryResourceMixin, ModelCrudViewSet)
def get_queryset(self): def get_queryset(self):
qs = super().get_queryset() qs = super().get_queryset()
qs = self.attach_votes_attrs_to_queryset(qs) qs = self.attach_votes_attrs_to_queryset(qs)
qs = attach_project_watchers_attrs_to_queryset(qs) qs = attach_project_total_watchers_attrs_to_queryset(qs)
if self.request.user.is_authenticated(): if self.request.user.is_authenticated():
qs = attach_project_is_watched_to_queryset(qs, self.request.user) qs = attach_project_is_watcher_to_queryset(qs, self.request.user)
qs = attach_notify_level_to_project_queryset(qs, self.request.user) qs = attach_notify_level_to_project_queryset(qs, self.request.user)
return qs return qs

View File

@ -76,7 +76,7 @@ class IssueViewSet(OCCResourceMixin, VotedResourceMixin, HistoryResourceMixin, W
"owner", "owner",
"assigned_to", "assigned_to",
"subject", "subject",
"votes_count") "total_voters")
def get_serializer_class(self, *args, **kwargs): def get_serializer_class(self, *args, **kwargs):
if self.action in ["retrieve", "by_ref"]: if self.action in ["retrieve", "by_ref"]:

View File

@ -23,15 +23,15 @@ from taiga.mdrender.service import render as mdrender
from taiga.projects.validators import ProjectExistsValidator from taiga.projects.validators import ProjectExistsValidator
from taiga.projects.notifications.validators import WatchersValidator from taiga.projects.notifications.validators import WatchersValidator
from taiga.projects.serializers import BasicIssueStatusSerializer from taiga.projects.serializers import BasicIssueStatusSerializer
from taiga.projects.notifications.mixins import WatchedResourceModelSerializer from taiga.projects.notifications.mixins import EditableWatchedResourceModelSerializer
from taiga.projects.votes.mixins.serializers import VotedResourceSerializerMixin from taiga.projects.votes.mixins.serializers import VoteResourceSerializerMixin
from taiga.users.serializers import UserBasicInfoSerializer from taiga.users.serializers import UserBasicInfoSerializer
from . import models from . import models
class IssueSerializer(WatchersValidator, VotedResourceSerializerMixin, WatchedResourceModelSerializer, serializers.ModelSerializer): class IssueSerializer(WatchersValidator, VoteResourceSerializerMixin, EditableWatchedResourceModelSerializer, serializers.ModelSerializer):
tags = TagsField(required=False) tags = TagsField(required=False)
external_reference = PgArrayField(required=False) external_reference = PgArrayField(required=False)
is_closed = serializers.Field(source="is_closed") is_closed = serializers.Field(source="is_closed")

View File

@ -29,7 +29,10 @@ from taiga.base.api import serializers
from taiga.base.api.utils import get_object_or_404 from taiga.base.api.utils import get_object_or_404
from taiga.base.fields import WatchersField from taiga.base.fields import WatchersField
from taiga.projects.notifications import services from taiga.projects.notifications import services
from taiga.projects.notifications.utils import attach_watchers_to_queryset, attach_is_watched_to_queryset from taiga.projects.notifications.utils import (attach_watchers_to_queryset,
attach_is_watcher_to_queryset,
attach_total_watchers_to_queryset)
from taiga.users.models import User from taiga.users.models import User
from . import models from . import models
from . serializers import WatcherSerializer from . serializers import WatcherSerializer
@ -50,8 +53,9 @@ class WatchedResourceMixin:
def attach_watchers_attrs_to_queryset(self, queryset): def attach_watchers_attrs_to_queryset(self, queryset):
qs = attach_watchers_to_queryset(queryset) qs = attach_watchers_to_queryset(queryset)
qs = attach_total_watchers_to_queryset(queryset)
if self.request.user.is_authenticated(): if self.request.user.is_authenticated():
qs = attach_is_watched_to_queryset(qs, self.request.user) qs = attach_is_watcher_to_queryset(qs, self.request.user)
return qs return qs
@ -178,12 +182,20 @@ class WatchedModelMixin(object):
class WatchedResourceModelSerializer(serializers.ModelSerializer): class WatchedResourceModelSerializer(serializers.ModelSerializer):
is_watched = serializers.SerializerMethodField("get_is_watched") is_watcher = serializers.SerializerMethodField("get_is_watcher")
watchers = WatchersField(required=False) total_watchers = serializers.SerializerMethodField("get_total_watchers")
def get_is_watched(self, obj): def get_is_watcher(self, obj):
# The "is_watched" attribute is attached in the get_queryset of the viewset. # The "is_watcher" attribute is attached in the get_queryset of the viewset.
return getattr(obj, "is_watched", False) or False return getattr(obj, "is_watcher", False) or False
def get_total_watchers(self, obj):
# The "total_watchers" attribute is attached in the get_queryset of the viewset.
return getattr(obj, "total_watchers", 0) or 0
class EditableWatchedResourceModelSerializer(WatchedResourceModelSerializer):
watchers = WatchersField(required=False)
def restore_object(self, attrs, instance=None): def restore_object(self, attrs, instance=None):
#watchers is not a field from the model but can be attached in the get_queryset of the viewset. #watchers is not a field from the model but can be attached in the get_queryset of the viewset.
@ -223,7 +235,7 @@ class WatchedResourceModelSerializer(serializers.ModelSerializer):
return super(WatchedResourceModelSerializer, self).to_native(obj) return super(WatchedResourceModelSerializer, self).to_native(obj)
def save(self, **kwargs): def save(self, **kwargs):
obj = super(WatchedResourceModelSerializer, self).save(**kwargs) obj = super(EditableWatchedResourceModelSerializer, self).save(**kwargs)
self.fields["watchers"] = WatchersField(required=False) self.fields["watchers"] = WatchersField(required=False)
obj.watchers = [user.id for user in obj.get_watchers()] obj.watchers = [user.id for user in obj.get_watchers()]
return obj return obj

View File

@ -40,8 +40,8 @@ def attach_watchers_to_queryset(queryset, as_field="watchers"):
return qs return qs
def attach_is_watched_to_queryset(queryset, user, as_field="is_watched"): def attach_is_watcher_to_queryset(queryset, user, as_field="is_watcher"):
"""Attach is_watched boolean to each object of the queryset. """Attach is_watcher boolean to each object of the queryset.
:param user: A users.User object model :param user: A users.User object model
:param queryset: A Django queryset object. :param queryset: A Django queryset object.
@ -64,8 +64,28 @@ def attach_is_watched_to_queryset(queryset, user, as_field="is_watched"):
return qs return qs
def attach_project_is_watched_to_queryset(queryset, user, as_field="is_watched"): def attach_total_watchers_to_queryset(queryset, as_field="total_watchers"):
"""Attach is_watched boolean to each object of the projects queryset. """Attach total_watchers boolean to each object of the queryset.
:param user: A users.User object model
:param queryset: A Django queryset object.
:param as_field: Attach the boolean as an attribute with this name.
:return: Queryset object with the additional `as_field` field.
"""
model = queryset.model
type = apps.get_model("contenttypes", "ContentType").objects.get_for_model(model)
sql = ("""SELECT count(*)
FROM notifications_watched
WHERE notifications_watched.content_type_id = {type_id}
AND notifications_watched.object_id = {tbl}.id""")
sql = sql.format(type_id=type.id, tbl=model._meta.db_table)
qs = queryset.extra(select={as_field: sql})
return qs
def attach_project_is_watcher_to_queryset(queryset, user, as_field="is_watcher"):
"""Attach is_watcher boolean to each object of the projects queryset.
:param user: A users.User object model :param user: A users.User object model
:param queryset: A Django projects queryset object. :param queryset: A Django projects queryset object.
@ -89,7 +109,7 @@ def attach_project_is_watched_to_queryset(queryset, user, as_field="is_watched")
return qs return qs
def attach_project_watchers_attrs_to_queryset(queryset, as_field="watchers"): def attach_project_total_watchers_attrs_to_queryset(queryset, as_field="total_watchers"):
"""Attach watching user ids to each project of the queryset. """Attach watching user ids to each project of the queryset.
:param queryset: A Django projects queryset object. :param queryset: A Django projects queryset object.
@ -100,10 +120,10 @@ def attach_project_watchers_attrs_to_queryset(queryset, as_field="watchers"):
model = queryset.model model = queryset.model
type = apps.get_model("contenttypes", "ContentType").objects.get_for_model(model) type = apps.get_model("contenttypes", "ContentType").objects.get_for_model(model)
sql = ("""SELECT array(SELECT user_id sql = ("""SELECT count(user_id)
FROM notifications_notifypolicy FROM notifications_notifypolicy
WHERE notifications_notifypolicy.project_id = {tbl}.id WHERE notifications_notifypolicy.project_id = {tbl}.id
AND notifications_notifypolicy.notify_level != {ignore_notify_level})""") AND notifications_notifypolicy.notify_level != {ignore_notify_level}""")
sql = sql.format(tbl=model._meta.db_table, ignore_notify_level=NotifyLevel.ignore) sql = sql.format(tbl=model._meta.db_table, ignore_notify_level=NotifyLevel.ignore)
qs = queryset.extra(select={as_field: sql}) qs = queryset.extra(select={as_field: sql})

View File

@ -25,8 +25,6 @@ from taiga.base.fields import PgArrayField
from taiga.base.fields import TagsField from taiga.base.fields import TagsField
from taiga.base.fields import TagsColorsField from taiga.base.fields import TagsColorsField
from taiga.projects.notifications.validators import WatchersValidator
from taiga.users.services import get_photo_or_gravatar_url from taiga.users.services import get_photo_or_gravatar_url
from taiga.users.serializers import UserSerializer from taiga.users.serializers import UserSerializer
from taiga.users.serializers import UserBasicInfoSerializer from taiga.users.serializers import UserBasicInfoSerializer
@ -40,12 +38,12 @@ from taiga.projects.notifications import models as notify_models
from . import models from . import models
from . import services from . import services
from .notifications.mixins import WatchedResourceModelSerializer
from .validators import ProjectExistsValidator from .validators import ProjectExistsValidator
from .custom_attributes.serializers import UserStoryCustomAttributeSerializer from .custom_attributes.serializers import UserStoryCustomAttributeSerializer
from .custom_attributes.serializers import TaskCustomAttributeSerializer from .custom_attributes.serializers import TaskCustomAttributeSerializer
from .custom_attributes.serializers import IssueCustomAttributeSerializer from .custom_attributes.serializers import IssueCustomAttributeSerializer
from .notifications.mixins import WatchedResourceModelSerializer from .votes.mixins.serializers import FanResourceSerializerMixin
from .votes.mixins.serializers import LikedResourceSerializerMixin
###################################################### ######################################################
## Custom values for selectors ## Custom values for selectors
@ -310,7 +308,7 @@ class ProjectMemberSerializer(serializers.ModelSerializer):
## Projects ## Projects
###################################################### ######################################################
class ProjectSerializer(WatchersValidator, LikedResourceSerializerMixin, WatchedResourceModelSerializer, serializers.ModelSerializer): class ProjectSerializer(FanResourceSerializerMixin, WatchedResourceModelSerializer, serializers.ModelSerializer):
tags = TagsField(default=[], required=False) tags = TagsField(default=[], required=False)
anon_permissions = PgArrayField(required=False) anon_permissions = PgArrayField(required=False)
public_permissions = PgArrayField(required=False) public_permissions = PgArrayField(required=False)

View File

@ -27,15 +27,15 @@ from taiga.projects.milestones.validators import SprintExistsValidator
from taiga.projects.tasks.validators import TaskExistsValidator from taiga.projects.tasks.validators import TaskExistsValidator
from taiga.projects.notifications.validators import WatchersValidator from taiga.projects.notifications.validators import WatchersValidator
from taiga.projects.serializers import BasicTaskStatusSerializerSerializer from taiga.projects.serializers import BasicTaskStatusSerializerSerializer
from taiga.projects.notifications.mixins import WatchedResourceModelSerializer from taiga.projects.notifications.mixins import EditableWatchedResourceModelSerializer
from taiga.projects.votes.mixins.serializers import VotedResourceSerializerMixin from taiga.projects.votes.mixins.serializers import VoteResourceSerializerMixin
from taiga.users.serializers import UserBasicInfoSerializer from taiga.users.serializers import UserBasicInfoSerializer
from . import models from . import models
class TaskSerializer(WatchersValidator, VotedResourceSerializerMixin, WatchedResourceModelSerializer, serializers.ModelSerializer): class TaskSerializer(WatchersValidator, VoteResourceSerializerMixin, EditableWatchedResourceModelSerializer, serializers.ModelSerializer):
tags = TagsField(required=False, default=[]) tags = TagsField(required=False, default=[])
external_reference = PgArrayField(required=False) external_reference = PgArrayField(required=False)
comment = serializers.SerializerMethodField("get_comment") comment = serializers.SerializerMethodField("get_comment")

View File

@ -70,7 +70,7 @@ class UserStoryViewSet(OCCResourceMixin, VotedResourceMixin, HistoryResourceMixi
order_by_fields = ["backlog_order", order_by_fields = ["backlog_order",
"sprint_order", "sprint_order",
"kanban_order", "kanban_order",
"votes_count"] "total_voters"]
# Specific filter used for filtering neighbor user stories # Specific filter used for filtering neighbor user stories
_neighbor_tags_filter = filters.TagsFilter('neighbor_tags') _neighbor_tags_filter = filters.TagsFilter('neighbor_tags')

View File

@ -27,8 +27,8 @@ from taiga.projects.validators import UserStoryStatusExistsValidator
from taiga.projects.userstories.validators import UserStoryExistsValidator from taiga.projects.userstories.validators import UserStoryExistsValidator
from taiga.projects.notifications.validators import WatchersValidator from taiga.projects.notifications.validators import WatchersValidator
from taiga.projects.serializers import BasicUserStoryStatusSerializer from taiga.projects.serializers import BasicUserStoryStatusSerializer
from taiga.projects.notifications.mixins import WatchedResourceModelSerializer from taiga.projects.notifications.mixins import EditableWatchedResourceModelSerializer
from taiga.projects.votes.mixins.serializers import VotedResourceSerializerMixin from taiga.projects.votes.mixins.serializers import VoteResourceSerializerMixin
from taiga.users.serializers import UserBasicInfoSerializer from taiga.users.serializers import UserBasicInfoSerializer
@ -45,7 +45,7 @@ class RolePointsField(serializers.WritableField):
return json.loads(obj) return json.loads(obj)
class UserStorySerializer(WatchersValidator, VotedResourceSerializerMixin, WatchedResourceModelSerializer, serializers.ModelSerializer): class UserStorySerializer(WatchersValidator, VoteResourceSerializerMixin, EditableWatchedResourceModelSerializer, serializers.ModelSerializer):
tags = TagsField(default=[], required=False) tags = TagsField(default=[], required=False)
external_reference = PgArrayField(required=False) external_reference = PgArrayField(required=False)
points = RolePointsField(source="role_points", required=False) points = RolePointsField(source="role_points", required=False)

View File

@ -17,21 +17,27 @@
from taiga.base.api import serializers from taiga.base.api import serializers
class BaseVotedResourceSerializer(serializers.ModelSerializer): class FanResourceSerializerMixin(serializers.ModelSerializer):
def get_votes_counter(self, obj): is_fan = serializers.SerializerMethodField("get_is_fan")
# The "votes_count" attribute is attached in the get_queryset of the viewset. total_fans = serializers.SerializerMethodField("get_total_fans")
return getattr(obj, "votes_count", 0) or 0
def get_is_voted(self, obj): def get_is_fan(self, obj):
# The "is_voted" attribute is attached in the get_queryset of the viewset. # The "is_voted" attribute is attached in the get_queryset of the viewset.
return getattr(obj, "is_voted", False) or False return getattr(obj, "is_voter", False) or False
def get_total_fans(self, obj):
# The "total_likes" attribute is attached in the get_queryset of the viewset.
return getattr(obj, "total_voters", 0) or 0
class LikedResourceSerializerMixin(BaseVotedResourceSerializer): class VoteResourceSerializerMixin(serializers.ModelSerializer):
likes = serializers.SerializerMethodField("get_votes_counter") is_voter = serializers.SerializerMethodField("get_is_voter")
is_liked = serializers.SerializerMethodField("get_is_voted") total_voters = serializers.SerializerMethodField("get_total_voters")
def get_is_voter(self, obj):
# The "is_voted" attribute is attached in the get_queryset of the viewset.
return getattr(obj, "is_voter", False) or False
class VotedResourceSerializerMixin(BaseVotedResourceSerializer): def get_total_voters(self, obj):
votes = serializers.SerializerMethodField("get_votes_counter") # The "total_likes" attribute is attached in the get_queryset of the viewset.
is_voted = serializers.SerializerMethodField("get_is_voted") return getattr(obj, "total_voters", 0) or 0

View File

@ -23,7 +23,7 @@ from taiga.base.decorators import detail_route
from taiga.projects.votes import serializers from taiga.projects.votes import serializers
from taiga.projects.votes import services from taiga.projects.votes import services
from taiga.projects.votes.utils import attach_votes_count_to_queryset, attach_is_vote_to_queryset from taiga.projects.votes.utils import attach_total_voters_to_queryset, attach_is_voter_to_queryset
class BaseVotedResource: class BaseVotedResource:
@ -33,10 +33,10 @@ class BaseVotedResource:
# return self.attach_votes_attrs_to_queryset(qs) # return self.attach_votes_attrs_to_queryset(qs)
def attach_votes_attrs_to_queryset(self, queryset): def attach_votes_attrs_to_queryset(self, queryset):
qs = attach_votes_count_to_queryset(queryset) qs = attach_total_voters_to_queryset(queryset)
if self.request.user.is_authenticated(): if self.request.user.is_authenticated():
qs = attach_is_vote_to_queryset(self.request.user, qs) qs = attach_is_voter_to_queryset(self.request.user, qs)
return qs return qs

View File

@ -35,7 +35,6 @@ def add_vote(obj, user):
obj_type = apps.get_model("contenttypes", "ContentType").objects.get_for_model(obj) obj_type = apps.get_model("contenttypes", "ContentType").objects.get_for_model(obj)
with atomic(): with atomic():
vote, created = Vote.objects.get_or_create(content_type=obj_type, object_id=obj.id, user=user) vote, created = Vote.objects.get_or_create(content_type=obj_type, object_id=obj.id, user=user)
if not created: if not created:
return return

View File

@ -18,7 +18,7 @@
from django.apps import apps from django.apps import apps
def attach_votes_count_to_queryset(queryset, as_field="votes_count"): def attach_total_voters_to_queryset(queryset, as_field="total_voters"):
"""Attach votes count to each object of the queryset. """Attach votes count to each object of the queryset.
Because of laziness of vote objects creation, this makes much simpler and more efficient to Because of laziness of vote objects creation, this makes much simpler and more efficient to
@ -34,8 +34,8 @@ def attach_votes_count_to_queryset(queryset, as_field="votes_count"):
""" """
model = queryset.model model = queryset.model
type = apps.get_model("contenttypes", "ContentType").objects.get_for_model(model) type = apps.get_model("contenttypes", "ContentType").objects.get_for_model(model)
sql = """SELECT coalesce(SUM(votes_count), 0) FROM ( sql = """SELECT coalesce(SUM(total_voters), 0) FROM (
SELECT coalesce(votes_votes.count, 0) votes_count SELECT coalesce(votes_votes.count, 0) total_voters
FROM votes_votes FROM votes_votes
WHERE votes_votes.content_type_id = {type_id} WHERE votes_votes.content_type_id = {type_id}
AND votes_votes.object_id = {tbl}.id AND votes_votes.object_id = {tbl}.id
@ -46,7 +46,7 @@ def attach_votes_count_to_queryset(queryset, as_field="votes_count"):
return qs return qs
def attach_is_vote_to_queryset(user, queryset, as_field="is_voted"): def attach_is_voter_to_queryset(user, queryset, as_field="is_voter"):
"""Attach is_vote boolean to each object of the queryset. """Attach is_vote boolean to each object of the queryset.
Because of laziness of vote objects creation, this makes much simpler and more efficient to Because of laziness of vote objects creation, this makes much simpler and more efficient to

View File

@ -113,32 +113,62 @@ class UsersViewSet(ModelCrudViewSet):
self.check_permissions(request, "stats", user) self.check_permissions(request, "stats", user)
return response.Ok(services.get_stats_for_user(user, request.user)) return response.Ok(services.get_stats_for_user(user, request.user))
def _serialize_liked_content(self, elem, **kwargs):
if elem.get("type") == "project":
serializer = serializers.FanSerializer
else:
serializer = serializers.VotedSerializer
return serializer(elem, **kwargs)
@detail_route(methods=["GET"]) @detail_route(methods=["GET"])
def favourites(self, request, *args, **kwargs): def watched(self, request, *args, **kwargs):
for_user = get_object_or_404(models.User, **kwargs) for_user = get_object_or_404(models.User, **kwargs)
from_user = request.user from_user = request.user
self.check_permissions(request, 'favourites', for_user) self.check_permissions(request, 'watched', for_user)
filters = { filters = {
"type": request.GET.get("type", None), "type": request.GET.get("type", None),
"action": request.GET.get("action", None),
"q": request.GET.get("q", None), "q": request.GET.get("q", None),
} }
self.object_list = services.get_favourites_list(for_user, from_user, **filters) self.object_list = services.get_watched_list(for_user, from_user, **filters)
page = self.paginate_queryset(self.object_list) page = self.paginate_queryset(self.object_list)
elements = page.object_list if page is not None else self.object_list
extra_args = { extra_args = {
"many": True,
"user_votes": services.get_voted_content_for_user(request.user), "user_votes": services.get_voted_content_for_user(request.user),
"user_watching": services.get_watched_content_for_user(request.user), "user_watching": services.get_watched_content_for_user(request.user),
} }
if page is not None: response_data = [self._serialize_liked_content(elem, **extra_args).data for elem in elements]
serializer = serializers.FavouriteSerializer(page.object_list, **extra_args) return response.Ok(response_data)
else:
serializer = serializers.FavouriteSerializer(self.object_list, **extra_args)
@detail_route(methods=["GET"])
def liked(self, request, *args, **kwargs):
for_user = get_object_or_404(models.User, **kwargs)
from_user = request.user
self.check_permissions(request, 'liked', for_user)
filters = {
"type": request.GET.get("type", None),
"q": request.GET.get("q", None),
}
self.object_list = services.get_voted_list(for_user, from_user, **filters)
page = self.paginate_queryset(self.object_list)
elements = page.object_list if page is not None else self.object_list
extra_args = {
"user_votes": services.get_voted_content_for_user(request.user),
"user_watching": services.get_watched_content_for_user(request.user),
}
response_data = [self._serialize_liked_content(elem, **extra_args).data for elem in elements]
return response.Ok(response_data)
return response.Ok(serializer.data)
@list_route(methods=["POST"]) @list_route(methods=["POST"])
def password_recovery(self, request, pk=None): def password_recovery(self, request, pk=None):

View File

@ -46,7 +46,8 @@ class UserPermission(TaigaResourcePermission):
remove_avatar_perms = IsAuthenticated() remove_avatar_perms = IsAuthenticated()
change_email_perms = AllowAny() change_email_perms = AllowAny()
contacts_perms = AllowAny() contacts_perms = AllowAny()
favourites_perms = AllowAny() liked_perms = AllowAny()
watched_perms = AllowAny()
class RolesPermission(TaigaResourcePermission): class RolesPermission(TaigaResourcePermission):

View File

@ -155,13 +155,12 @@ class ProjectRoleSerializer(serializers.ModelSerializer):
###################################################### ######################################################
## Favourite ## Like
###################################################### ######################################################
class FavouriteSerializer(serializers.Serializer): class LikeSerializer(serializers.Serializer):
type = serializers.CharField() type = serializers.CharField()
action = serializers.CharField()
id = serializers.IntegerField() id = serializers.IntegerField()
ref = serializers.IntegerField() ref = serializers.IntegerField()
slug = serializers.CharField() slug = serializers.CharField()
@ -175,11 +174,8 @@ class FavouriteSerializer(serializers.Serializer):
created_date = serializers.DateTimeField() created_date = serializers.DateTimeField()
is_private = serializers.SerializerMethodField("get_is_private") is_private = serializers.SerializerMethodField("get_is_private")
is_voted = serializers.SerializerMethodField("get_is_voted") is_watcher = serializers.SerializerMethodField("get_is_watcher")
is_watched = serializers.SerializerMethodField("get_is_watched")
total_watchers = serializers.IntegerField() total_watchers = serializers.IntegerField()
total_votes = serializers.IntegerField()
project = serializers.SerializerMethodField("get_project") project = serializers.SerializerMethodField("get_project")
project_name = serializers.SerializerMethodField("get_project_name") project_name = serializers.SerializerMethodField("get_project_name")
@ -196,7 +192,7 @@ class FavouriteSerializer(serializers.Serializer):
self.user_watching = kwargs.pop("user_watching", {}) self.user_watching = kwargs.pop("user_watching", {})
# Instantiate the superclass normally # Instantiate the superclass normally
super(FavouriteSerializer, self).__init__(*args, **kwargs) super(LikeSerializer, self).__init__(*args, **kwargs)
def _none_if_project(self, obj, property): def _none_if_project(self, obj, property):
type = obj.get("type", "") type = obj.get("type", "")
@ -230,10 +226,7 @@ class FavouriteSerializer(serializers.Serializer):
def get_project_is_private(self, obj): def get_project_is_private(self, obj):
return self._none_if_project(obj, "project_is_private") return self._none_if_project(obj, "project_is_private")
def get_is_voted(self, obj): def get_is_watcher(self, obj):
return obj["id"] in self.user_votes.get(obj["type"], [])
def get_is_watched(self, obj):
return obj["id"] in self.user_watching.get(obj["type"], []) return obj["id"] in self.user_watching.get(obj["type"], [])
def get_photo(self, obj): def get_photo(self, obj):
@ -248,3 +241,19 @@ class FavouriteSerializer(serializers.Serializer):
def get_tags_color(self, obj): def get_tags_color(self, obj):
tags = obj.get("tags", []) tags = obj.get("tags", [])
return [{"name": tc[0], "color": tc[1]} for tc in obj.get("tags_colors", []) if tc[0] in tags] return [{"name": tc[0], "color": tc[1]} for tc in obj.get("tags_colors", []) if tc[0] in tags]
class FanSerializer(LikeSerializer):
is_fan = serializers.SerializerMethodField("get_is_fan")
total_fans = serializers.IntegerField(source="total_voters")
def get_is_fan(self, obj):
return obj["id"] in self.user_votes.get(obj["type"], [])
class VotedSerializer(LikeSerializer):
is_voter = serializers.SerializerMethodField("get_is_voter")
total_voters = serializers.IntegerField()
def get_is_voter(self, obj):
return obj["id"] in self.user_votes.get(obj["type"], [])

View File

@ -188,12 +188,12 @@ def get_watched_content_for_user(user):
return user_watches return user_watches
def _build_favourites_sql_for_projects(for_user): def _build_watched_sql_for_projects(for_user):
sql = """ sql = """
SELECT projects_project.id AS id, null AS ref, 'project' AS type, 'watch' AS action, SELECT projects_project.id AS id, null AS ref, 'project' AS type,
tags, notifications_notifypolicy.project_id AS object_id, projects_project.id AS project, tags, notifications_notifypolicy.project_id AS object_id, projects_project.id AS project,
slug AS slug, projects_project.name AS name, null AS subject, slug AS slug, projects_project.name AS name, null AS subject,
notifications_notifypolicy.created_at as created_date, coalesce(watchers, 0) as total_watchers, coalesce(votes_votes.count, 0) total_votes, null AS assigned_to, notifications_notifypolicy.created_at as created_date, coalesce(watchers, 0) as total_watchers, coalesce(votes_votes.count, 0) total_voters, null AS assigned_to,
null as status, null as status_color null as status, null as status_color
FROM notifications_notifypolicy FROM notifications_notifypolicy
INNER JOIN projects_project INNER JOIN projects_project
@ -207,11 +207,20 @@ def _build_favourites_sql_for_projects(for_user):
LEFT JOIN votes_votes LEFT JOIN votes_votes
ON (projects_project.id = votes_votes.object_id AND {project_content_type_id} = votes_votes.content_type_id) ON (projects_project.id = votes_votes.object_id AND {project_content_type_id} = votes_votes.content_type_id)
WHERE notifications_notifypolicy.user_id = {for_user_id} WHERE notifications_notifypolicy.user_id = {for_user_id}
UNION """
SELECT projects_project.id AS id, null AS ref, 'project' AS type, 'vote' AS action, sql = sql.format(
for_user_id=for_user.id,
ignore_notify_level=NotifyLevel.ignore,
project_content_type_id=ContentType.objects.get(app_label="projects", model="project").id)
return sql
def _build_voted_sql_for_projects(for_user):
sql = """
SELECT projects_project.id AS id, null AS ref, 'project' AS type,
tags, votes_vote.object_id AS object_id, projects_project.id AS project, tags, votes_vote.object_id AS object_id, projects_project.id AS project,
slug AS slug, projects_project.name AS name, null AS subject, slug AS slug, projects_project.name AS name, null AS subject,
votes_vote.created_date, coalesce(watchers, 0) as total_watchers, coalesce(votes_votes.count, 0) total_votes, null AS assigned_to, votes_vote.created_date, coalesce(watchers, 0) as total_watchers, coalesce(votes_votes.count, 0) total_voters, null AS assigned_to,
null as status, null as status_color null as status, null as status_color
FROM votes_vote FROM votes_vote
INNER JOIN projects_project INNER JOIN projects_project
@ -233,65 +242,43 @@ def _build_favourites_sql_for_projects(for_user):
return sql return sql
def _build_sql_for_type(for_user, type, table_name, action_table, ref_column="ref",
def _build_favourites_sql_for_type(for_user, type, table_name, ref_column="ref",
project_column="project_id", assigned_to_column="assigned_to_id", project_column="project_id", assigned_to_column="assigned_to_id",
slug_column="slug", subject_column="subject"): slug_column="slug", subject_column="subject"):
sql = """ sql = """
SELECT {table_name}.id AS id, {ref_column} AS ref, '{type}' AS type, 'watch' AS action, SELECT {table_name}.id AS id, {ref_column} AS ref, '{type}' AS type,
tags, notifications_watched.object_id AS object_id, {table_name}.{project_column} AS project, tags, {action_table}.object_id AS object_id, {table_name}.{project_column} AS project,
{slug_column} AS slug, null AS name, {subject_column} AS subject, {slug_column} AS slug, null AS name, {subject_column} AS subject,
notifications_watched.created_date, coalesce(watchers, 0) as total_watchers, coalesce(votes_votes.count, 0) total_votes, {assigned_to_column} AS assigned_to, {action_table}.created_date, coalesce(watchers, 0) as total_watchers, coalesce(votes_votes.count, 0) total_voters, {assigned_to_column} AS assigned_to,
projects_{type}status.name as status, projects_{type}status.color as status_color projects_{type}status.name as status, projects_{type}status.color as status_color
FROM notifications_watched FROM {action_table}
INNER JOIN django_content_type INNER JOIN django_content_type
ON (notifications_watched.content_type_id = django_content_type.id AND django_content_type.model = '{type}') ON ({action_table}.content_type_id = django_content_type.id AND django_content_type.model = '{type}')
INNER JOIN {table_name} INNER JOIN {table_name}
ON ({table_name}.id = notifications_watched.object_id) ON ({table_name}.id = {action_table}.object_id)
INNER JOIN projects_{type}status INNER JOIN projects_{type}status
ON (projects_{type}status.id = {table_name}.status_id) ON (projects_{type}status.id = {table_name}.status_id)
LEFT JOIN (SELECT object_id, content_type_id, count(*) watchers FROM notifications_watched GROUP BY object_id, content_type_id) type_watchers LEFT JOIN (SELECT object_id, content_type_id, count(*) watchers FROM notifications_watched GROUP BY object_id, content_type_id) type_watchers
ON {table_name}.id = type_watchers.object_id AND django_content_type.id = type_watchers.content_type_id ON {table_name}.id = type_watchers.object_id AND django_content_type.id = type_watchers.content_type_id
LEFT JOIN votes_votes LEFT JOIN votes_votes
ON ({table_name}.id = votes_votes.object_id AND django_content_type.id = votes_votes.content_type_id) ON ({table_name}.id = votes_votes.object_id AND django_content_type.id = votes_votes.content_type_id)
WHERE notifications_watched.user_id = {for_user_id} WHERE {action_table}.user_id = {for_user_id}
UNION
SELECT {table_name}.id AS id, {ref_column} AS ref, '{type}' AS type, 'vote' AS action,
tags, votes_vote.object_id AS object_id, {table_name}.{project_column} AS project,
{slug_column} AS slug, null AS name, {subject_column} AS subject,
votes_vote.created_date, coalesce(watchers, 0) as total_watchers, votes_votes.count total_votes, {assigned_to_column} AS assigned_to,
projects_{type}status.name as status, projects_{type}status.color as status_color
FROM votes_vote
INNER JOIN django_content_type
ON (votes_vote.content_type_id = django_content_type.id AND django_content_type.model = '{type}')
INNER JOIN {table_name}
ON ({table_name}.id = votes_vote.object_id)
INNER JOIN projects_{type}status
ON (projects_{type}status.id = {table_name}.status_id)
LEFT JOIN (SELECT object_id, content_type_id, count(*) watchers FROM notifications_watched GROUP BY object_id, content_type_id) type_watchers
ON {table_name}.id = type_watchers.object_id AND django_content_type.id = type_watchers.content_type_id
LEFT JOIN votes_votes
ON ({table_name}.id = votes_votes.object_id AND django_content_type.id = votes_votes.content_type_id)
WHERE votes_vote.user_id = {for_user_id}
""" """
sql = sql.format(for_user_id=for_user.id, type=type, table_name=table_name, sql = sql.format(for_user_id=for_user.id, type=type, table_name=table_name,
ref_column = ref_column, project_column=project_column, action_table=action_table, ref_column = ref_column,
assigned_to_column=assigned_to_column, slug_column=slug_column, project_column=project_column, assigned_to_column=assigned_to_column,
subject_column=subject_column) slug_column=slug_column, subject_column=subject_column)
return sql return sql
def get_favourites_list(for_user, from_user, type=None, action=None, q=None): def _get_favourites_list(for_user, from_user, action_table, project_sql_builder, type=None, q=None):
filters_sql = "" filters_sql = ""
and_needed = False and_needed = False
if type: if type:
filters_sql += " AND type = '{type}' ".format(type=type) filters_sql += " AND type = '{type}' ".format(type=type)
if action:
filters_sql += " AND action = '{action}' ".format(action=action)
if q: if q:
filters_sql += """ AND ( filters_sql += """ AND (
to_tsvector('english_nostop', coalesce(subject,'') || ' ' ||coalesce(entities.name,'') || ' ' ||coalesce(to_char(ref, '999'),'')) @@ to_tsquery('english_nostop', '{q}') to_tsvector('english_nostop', coalesce(subject,'') || ' ' ||coalesce(entities.name,'') || ' ' ||coalesce(to_char(ref, '999'),'')) @@ to_tsquery('english_nostop', '{q}')
@ -361,10 +348,10 @@ def get_favourites_list(for_user, from_user, type=None, action=None, q=None):
for_user_id=for_user.id, for_user_id=for_user.id,
from_user_id=from_user_id, from_user_id=from_user_id,
filters_sql=filters_sql, filters_sql=filters_sql,
userstories_sql=_build_favourites_sql_for_type(for_user, "userstory", "userstories_userstory", slug_column="null"), userstories_sql=_build_sql_for_type(for_user, "userstory", "userstories_userstory", action_table, slug_column="null"),
tasks_sql=_build_favourites_sql_for_type(for_user, "task", "tasks_task", slug_column="null"), tasks_sql=_build_sql_for_type(for_user, "task", "tasks_task", action_table, slug_column="null"),
issues_sql=_build_favourites_sql_for_type(for_user, "issue", "issues_issue", slug_column="null"), issues_sql=_build_sql_for_type(for_user, "issue", "issues_issue", action_table, slug_column="null"),
projects_sql=_build_favourites_sql_for_projects(for_user)) projects_sql=project_sql_builder(for_user))
cursor = connection.cursor() cursor = connection.cursor()
cursor.execute(sql) cursor.execute(sql)
@ -374,3 +361,11 @@ def get_favourites_list(for_user, from_user, type=None, action=None, q=None):
dict(zip([col[0] for col in desc], row)) dict(zip([col[0] for col in desc], row))
for row in cursor.fetchall() for row in cursor.fetchall()
] ]
def get_watched_list(for_user, from_user, type=None, q=None):
return _get_favourites_list(for_user, from_user, "notifications_watched", _build_watched_sql_for_projects, type=type, q=q)
def get_voted_list(for_user, from_user, type=None, q=None):
return _get_favourites_list(for_user, from_user, "votes_vote", _build_voted_sql_for_projects, type=type, q=q)

View File

@ -25,7 +25,7 @@ from taiga.projects.issues import models as issue_models
from taiga.projects.milestones import models as milestone_models from taiga.projects.milestones import models as milestone_models
from taiga.projects.wiki import models as wiki_models from taiga.projects.wiki import models as wiki_models
from taiga.projects.history import models as history_models from taiga.projects.history import models as history_models
from taiga.projects.notifications.mixins import WatchedResourceModelSerializer from taiga.projects.notifications.mixins import EditableWatchedResourceModelSerializer
from .models import Webhook, WebhookLog from .models import Webhook, WebhookLog
@ -104,7 +104,7 @@ class PointSerializer(serializers.Serializer):
return obj.value return obj.value
class UserStorySerializer(CustomAttributesValuesWebhookSerializerMixin, WatchedResourceModelSerializer, class UserStorySerializer(CustomAttributesValuesWebhookSerializerMixin, EditableWatchedResourceModelSerializer,
serializers.ModelSerializer): serializers.ModelSerializer):
tags = TagsField(default=[], required=False) tags = TagsField(default=[], required=False)
external_reference = PgArrayField(required=False) external_reference = PgArrayField(required=False)
@ -121,7 +121,7 @@ class UserStorySerializer(CustomAttributesValuesWebhookSerializerMixin, WatchedR
return project.userstorycustomattributes.all() return project.userstorycustomattributes.all()
class TaskSerializer(CustomAttributesValuesWebhookSerializerMixin, WatchedResourceModelSerializer, class TaskSerializer(CustomAttributesValuesWebhookSerializerMixin, EditableWatchedResourceModelSerializer,
serializers.ModelSerializer): serializers.ModelSerializer):
tags = TagsField(default=[], required=False) tags = TagsField(default=[], required=False)
owner = UserSerializer() owner = UserSerializer()
@ -135,7 +135,7 @@ class TaskSerializer(CustomAttributesValuesWebhookSerializerMixin, WatchedResour
return project.taskcustomattributes.all() return project.taskcustomattributes.all()
class IssueSerializer(CustomAttributesValuesWebhookSerializerMixin, WatchedResourceModelSerializer, class IssueSerializer(CustomAttributesValuesWebhookSerializerMixin, EditableWatchedResourceModelSerializer,
serializers.ModelSerializer): serializers.ModelSerializer):
tags = TagsField(default=[], required=False) tags = TagsField(default=[], required=False)
owner = UserSerializer() owner = UserSerializer()

View File

@ -289,8 +289,20 @@ def test_user_action_change_email(client, data):
assert results == [204, 204, 204] assert results == [204, 204, 204]
def test_user_list_votes(client, data): def test_user_list_watched(client, data):
url = reverse('users-favourites', kwargs={"pk": data.registered_user.pk}) url = reverse('users-watched', kwargs={"pk": data.registered_user.pk})
users = [
None,
data.registered_user,
data.other_user,
data.superuser,
]
results = helper_test_http_method(client, 'get', url, None, users)
assert results == [200, 200, 200, 200]
def test_user_list_liked(client, data):
url = reverse('users-liked', kwargs={"pk": data.registered_user.pk})
users = [ users = [
None, None,
data.registered_user, data.registered_user,

View File

@ -1,123 +0,0 @@
# Copyright (C) 2015 Andrey Antukh <niwi@niwi.be>
# Copyright (C) 2015 Jesús Espino <jespinog@gmail.com>
# Copyright (C) 2015 David Barragán <bameda@dbarragan.com>
# Copyright (C) 2015 Anler Hernández <hello@anler.me>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import pytest
from django.core.urlresolvers import reverse
from .. import factories as f
pytestmark = pytest.mark.django_db
def test_like_project(client):
user = f.UserFactory.create()
project = f.create_project(owner=user)
f.MembershipFactory.create(project=project, user=user, is_owner=True)
url = reverse("projects-like", args=(project.id,))
client.login(user)
response = client.post(url)
assert response.status_code == 200
def test_unlike_project(client):
user = f.UserFactory.create()
project = f.create_project(owner=user)
f.MembershipFactory.create(project=project, user=user, is_owner=True)
url = reverse("projects-unlike", args=(project.id,))
client.login(user)
response = client.post(url)
assert response.status_code == 200
def test_list_project_fans(client):
user = f.UserFactory.create()
project = f.create_project(owner=user)
f.MembershipFactory.create(project=project, user=user, is_owner=True)
f.VoteFactory.create(content_object=project, user=user)
url = reverse("project-fans-list", args=(project.id,))
client.login(user)
response = client.get(url)
assert response.status_code == 200
assert response.data[0]['id'] == user.id
def test_get_project_fan(client):
user = f.UserFactory.create()
project = f.create_project(owner=user)
f.MembershipFactory.create(project=project, user=user, is_owner=True)
vote = f.VoteFactory.create(content_object=project, user=user)
url = reverse("project-fans-detail", args=(project.id, vote.user.id))
client.login(user)
response = client.get(url)
assert response.status_code == 200
assert response.data['id'] == vote.user.id
def test_get_project_likes(client):
user = f.UserFactory.create()
project = f.create_project(owner=user)
f.MembershipFactory.create(project=project, user=user, is_owner=True)
url = reverse("projects-detail", args=(project.id,))
f.VotesFactory.create(content_object=project, count=5)
client.login(user)
response = client.get(url)
assert response.status_code == 200
assert response.data['likes'] == 5
def test_get_project_is_liked(client):
user = f.UserFactory.create()
project = f.create_project(owner=user)
f.MembershipFactory.create(project=project, user=user, is_owner=True)
f.VotesFactory.create(content_object=project)
url_detail = reverse("projects-detail", args=(project.id,))
url_like = reverse("projects-like", args=(project.id,))
url_unlike = reverse("projects-unlike", args=(project.id,))
client.login(user)
response = client.get(url_detail)
assert response.status_code == 200
assert response.data['likes'] == 0
assert response.data['is_liked'] == False
response = client.post(url_like)
assert response.status_code == 200
response = client.get(url_detail)
assert response.status_code == 200
assert response.data['likes'] == 1
assert response.data['is_liked'] == True
response = client.post(url_unlike)
assert response.status_code == 200
response = client.get(url_detail)
assert response.status_code == 200
assert response.data['likes'] == 0
assert response.data['is_liked'] == False

View File

@ -9,10 +9,10 @@ from .. import factories as f
from taiga.base.utils import json from taiga.base.utils import json
from taiga.users import models from taiga.users import models
from taiga.users.serializers import FavouriteSerializer from taiga.users.serializers import FanSerializer, VotedSerializer
from taiga.auth.tokens import get_token_for_user from taiga.auth.tokens import get_token_for_user
from taiga.permissions.permissions import MEMBERS_PERMISSIONS, ANON_PERMISSIONS, USER_PERMISSIONS from taiga.permissions.permissions import MEMBERS_PERMISSIONS, ANON_PERMISSIONS, USER_PERMISSIONS
from taiga.users.services import get_favourites_list from taiga.users.services import get_watched_list, get_voted_list
from easy_thumbnails.files import generate_all_aliases, get_thumbnailer from easy_thumbnails.files import generate_all_aliases, get_thumbnailer
@ -348,7 +348,7 @@ def test_mail_permissions(client):
assert "email" in response.data assert "email" in response.data
def test_get_favourites_list(): def test_get_watched_list():
fav_user = f.UserFactory() fav_user = f.UserFactory()
viewer_user = f.UserFactory() viewer_user = f.UserFactory()
@ -356,58 +356,117 @@ def test_get_favourites_list():
role = f.RoleFactory(project=project, permissions=["view_project", "view_us", "view_tasks", "view_issues"]) role = f.RoleFactory(project=project, permissions=["view_project", "view_us", "view_tasks", "view_issues"])
membership = f.MembershipFactory(project=project, role=role, user=fav_user) membership = f.MembershipFactory(project=project, role=role, user=fav_user)
project.add_watcher(fav_user) project.add_watcher(fav_user)
user_story = f.UserStoryFactory(project=project, subject="Testing user story")
user_story.add_watcher(fav_user)
task = f.TaskFactory(project=project, subject="Testing task")
task.add_watcher(fav_user)
issue = f.IssueFactory(project=project, subject="Testing issue")
issue.add_watcher(fav_user)
assert len(get_watched_list(fav_user, viewer_user)) == 4
assert len(get_watched_list(fav_user, viewer_user, type="project")) == 1
assert len(get_watched_list(fav_user, viewer_user, type="userstory")) == 1
assert len(get_watched_list(fav_user, viewer_user, type="task")) == 1
assert len(get_watched_list(fav_user, viewer_user, type="issue")) == 1
assert len(get_watched_list(fav_user, viewer_user, type="unknown")) == 0
assert len(get_watched_list(fav_user, viewer_user, q="issue")) == 1
assert len(get_watched_list(fav_user, viewer_user, q="unexisting text")) == 0
def test_get_voted_list():
fav_user = f.UserFactory()
viewer_user = f.UserFactory()
project = f.ProjectFactory(is_private=False, name="Testing project")
role = f.RoleFactory(project=project, permissions=["view_project", "view_us", "view_tasks", "view_issues"])
membership = f.MembershipFactory(project=project, role=role, user=fav_user)
content_type = ContentType.objects.get_for_model(project) content_type = ContentType.objects.get_for_model(project)
f.VoteFactory(content_type=content_type, object_id=project.id, user=fav_user) f.VoteFactory(content_type=content_type, object_id=project.id, user=fav_user)
f.VotesFactory(content_type=content_type, object_id=project.id, count=1) f.VotesFactory(content_type=content_type, object_id=project.id, count=1)
user_story = f.UserStoryFactory(project=project, subject="Testing user story") user_story = f.UserStoryFactory(project=project, subject="Testing user story")
user_story.add_watcher(fav_user)
content_type = ContentType.objects.get_for_model(user_story) content_type = ContentType.objects.get_for_model(user_story)
f.VoteFactory(content_type=content_type, object_id=user_story.id, user=fav_user) f.VoteFactory(content_type=content_type, object_id=user_story.id, user=fav_user)
f.VotesFactory(content_type=content_type, object_id=user_story.id, count=1) f.VotesFactory(content_type=content_type, object_id=user_story.id, count=1)
task = f.TaskFactory(project=project, subject="Testing task") task = f.TaskFactory(project=project, subject="Testing task")
task.add_watcher(fav_user)
content_type = ContentType.objects.get_for_model(task) content_type = ContentType.objects.get_for_model(task)
f.VoteFactory(content_type=content_type, object_id=task.id, user=fav_user) f.VoteFactory(content_type=content_type, object_id=task.id, user=fav_user)
f.VotesFactory(content_type=content_type, object_id=task.id, count=1) f.VotesFactory(content_type=content_type, object_id=task.id, count=1)
issue = f.IssueFactory(project=project, subject="Testing issue") issue = f.IssueFactory(project=project, subject="Testing issue")
issue.add_watcher(fav_user)
content_type = ContentType.objects.get_for_model(issue) content_type = ContentType.objects.get_for_model(issue)
f.VoteFactory(content_type=content_type, object_id=issue.id, user=fav_user) f.VoteFactory(content_type=content_type, object_id=issue.id, user=fav_user)
f.VotesFactory(content_type=content_type, object_id=issue.id, count=1) f.VotesFactory(content_type=content_type, object_id=issue.id, count=1)
assert len(get_favourites_list(fav_user, viewer_user)) == 8 assert len(get_voted_list(fav_user, viewer_user)) == 4
assert len(get_favourites_list(fav_user, viewer_user, type="project")) == 2 assert len(get_voted_list(fav_user, viewer_user, type="project")) == 1
assert len(get_favourites_list(fav_user, viewer_user, type="userstory")) == 2 assert len(get_voted_list(fav_user, viewer_user, type="userstory")) == 1
assert len(get_favourites_list(fav_user, viewer_user, type="task")) == 2 assert len(get_voted_list(fav_user, viewer_user, type="task")) == 1
assert len(get_favourites_list(fav_user, viewer_user, type="issue")) == 2 assert len(get_voted_list(fav_user, viewer_user, type="issue")) == 1
assert len(get_favourites_list(fav_user, viewer_user, type="unknown")) == 0 assert len(get_voted_list(fav_user, viewer_user, type="unknown")) == 0
assert len(get_favourites_list(fav_user, viewer_user, action="watch")) == 4 assert len(get_voted_list(fav_user, viewer_user, q="issue")) == 1
assert len(get_favourites_list(fav_user, viewer_user, action="vote")) == 4 assert len(get_voted_list(fav_user, viewer_user, q="unexisting text")) == 0
assert len(get_favourites_list(fav_user, viewer_user, q="issue")) == 2
assert len(get_favourites_list(fav_user, viewer_user, q="unexisting text")) == 0
def test_get_favourites_list_valid_info_for_project(): def test_get_watched_list_valid_info_for_project():
fav_user = f.UserFactory()
viewer_user = f.UserFactory()
project = f.ProjectFactory(is_private=False, name="Testing project", tags=['test', 'tag'])
role = f.RoleFactory(project=project, permissions=["view_project", "view_us", "view_tasks", "view_issues"])
project.add_watcher(fav_user)
raw_project_watch_info = get_watched_list(fav_user, viewer_user)[0]
project_watch_info = FanSerializer(raw_project_watch_info).data
assert project_watch_info["type"] == "project"
assert project_watch_info["id"] == project.id
assert project_watch_info["ref"] == None
assert project_watch_info["slug"] == project.slug
assert project_watch_info["name"] == project.name
assert project_watch_info["subject"] == None
assert project_watch_info["description"] == project.description
assert project_watch_info["assigned_to"] == None
assert project_watch_info["status"] == None
assert project_watch_info["status_color"] == None
tags_colors = {tc["name"]:tc["color"] for tc in project_watch_info["tags_colors"]}
assert "test" in tags_colors
assert "tag" in tags_colors
assert project_watch_info["is_private"] == project.is_private
assert project_watch_info["is_fan"] == False
assert project_watch_info["is_watcher"] == False
assert project_watch_info["total_watchers"] == 1
assert project_watch_info["total_fans"] == 0
assert project_watch_info["project"] == None
assert project_watch_info["project_name"] == None
assert project_watch_info["project_slug"] == None
assert project_watch_info["project_is_private"] == None
assert project_watch_info["assigned_to_username"] == None
assert project_watch_info["assigned_to_full_name"] == None
assert project_watch_info["assigned_to_photo"] == None
def test_get_voted_list_valid_info_for_project():
fav_user = f.UserFactory() fav_user = f.UserFactory()
viewer_user = f.UserFactory() viewer_user = f.UserFactory()
watcher_user = f.UserFactory()
project = f.ProjectFactory(is_private=False, name="Testing project", tags=['test', 'tag']) project = f.ProjectFactory(is_private=False, name="Testing project", tags=['test', 'tag'])
project.add_watcher(watcher_user)
content_type = ContentType.objects.get_for_model(project) content_type = ContentType.objects.get_for_model(project)
vote = f.VoteFactory(content_type=content_type, object_id=project.id, user=fav_user) vote = f.VoteFactory(content_type=content_type, object_id=project.id, user=fav_user)
f.VotesFactory(content_type=content_type, object_id=project.id, count=1) f.VotesFactory(content_type=content_type, object_id=project.id, count=1)
raw_project_vote_info = get_favourites_list(fav_user, viewer_user)[0] raw_project_vote_info = get_voted_list(fav_user, viewer_user)[0]
project_vote_info = FavouriteSerializer(raw_project_vote_info).data project_vote_info = FanSerializer(raw_project_vote_info).data
assert project_vote_info["type"] == "project" assert project_vote_info["type"] == "project"
assert project_vote_info["action"] == "vote"
assert project_vote_info["id"] == project.id assert project_vote_info["id"] == project.id
assert project_vote_info["ref"] == None assert project_vote_info["ref"] == None
assert project_vote_info["slug"] == project.slug assert project_vote_info["slug"] == project.slug
@ -423,10 +482,14 @@ def test_get_favourites_list_valid_info_for_project():
assert "tag" in tags_colors assert "tag" in tags_colors
assert project_vote_info["is_private"] == project.is_private assert project_vote_info["is_private"] == project.is_private
assert project_vote_info["is_voted"] == False
assert project_vote_info["is_watched"] == False import pprint
assert project_vote_info["total_watchers"] == 1 pprint.pprint(project_vote_info)
assert project_vote_info["total_votes"] == 1
assert project_vote_info["is_fan"] == False
assert project_vote_info["is_watcher"] == False
assert project_vote_info["total_watchers"] == 0
assert project_vote_info["total_fans"] == 1
assert project_vote_info["project"] == None assert project_vote_info["project"] == None
assert project_vote_info["project_name"] == None assert project_vote_info["project_name"] == None
assert project_vote_info["project_slug"] == None assert project_vote_info["project_slug"] == None
@ -436,10 +499,61 @@ def test_get_favourites_list_valid_info_for_project():
assert project_vote_info["assigned_to_photo"] == None assert project_vote_info["assigned_to_photo"] == None
def test_get_favourites_list_valid_info_for_not_project_types(): def test_get_watched_list_valid_info_for_not_project_types():
fav_user = f.UserFactory()
viewer_user = f.UserFactory()
assigned_to_user = f.UserFactory()
project = f.ProjectFactory(is_private=False, name="Testing project")
factories = {
"userstory": f.UserStoryFactory,
"task": f.TaskFactory,
"issue": f.IssueFactory
}
for object_type in factories:
instance = factories[object_type](project=project,
subject="Testing",
tags=["test1", "test2"],
assigned_to=assigned_to_user)
instance.add_watcher(fav_user)
raw_instance_watch_info = get_watched_list(fav_user, viewer_user, type=object_type)[0]
instance_watch_info = VotedSerializer(raw_instance_watch_info).data
assert instance_watch_info["type"] == object_type
assert instance_watch_info["id"] == instance.id
assert instance_watch_info["ref"] == instance.ref
assert instance_watch_info["slug"] == None
assert instance_watch_info["name"] == None
assert instance_watch_info["subject"] == instance.subject
assert instance_watch_info["description"] == None
assert instance_watch_info["assigned_to"] == instance.assigned_to.id
assert instance_watch_info["status"] == instance.status.name
assert instance_watch_info["status_color"] == instance.status.color
tags_colors = {tc["name"]:tc["color"] for tc in instance_watch_info["tags_colors"]}
assert "test1" in tags_colors
assert "test2" in tags_colors
assert instance_watch_info["is_private"] == None
assert instance_watch_info["is_voter"] == False
assert instance_watch_info["is_watcher"] == False
assert instance_watch_info["total_watchers"] == 1
assert instance_watch_info["total_voters"] == 0
assert instance_watch_info["project"] == instance.project.id
assert instance_watch_info["project_name"] == instance.project.name
assert instance_watch_info["project_slug"] == instance.project.slug
assert instance_watch_info["project_is_private"] == instance.project.is_private
assert instance_watch_info["assigned_to_username"] == instance.assigned_to.username
assert instance_watch_info["assigned_to_full_name"] == instance.assigned_to.full_name
assert instance_watch_info["assigned_to_photo"] != ""
def test_get_voted_list_valid_info_for_not_project_types():
fav_user = f.UserFactory() fav_user = f.UserFactory()
viewer_user = f.UserFactory() viewer_user = f.UserFactory()
watcher_user = f.UserFactory()
assigned_to_user = f.UserFactory() assigned_to_user = f.UserFactory()
project = f.ProjectFactory(is_private=False, name="Testing project") project = f.ProjectFactory(is_private=False, name="Testing project")
@ -456,16 +570,14 @@ def test_get_favourites_list_valid_info_for_not_project_types():
tags=["test1", "test2"], tags=["test1", "test2"],
assigned_to=assigned_to_user) assigned_to=assigned_to_user)
instance.add_watcher(watcher_user)
content_type = ContentType.objects.get_for_model(instance) content_type = ContentType.objects.get_for_model(instance)
vote = f.VoteFactory(content_type=content_type, object_id=instance.id, user=fav_user) vote = f.VoteFactory(content_type=content_type, object_id=instance.id, user=fav_user)
f.VotesFactory(content_type=content_type, object_id=instance.id, count=3) f.VotesFactory(content_type=content_type, object_id=instance.id, count=3)
raw_instance_vote_info = get_favourites_list(fav_user, viewer_user, type=object_type)[0] raw_instance_vote_info = get_voted_list(fav_user, viewer_user, type=object_type)[0]
instance_vote_info = FavouriteSerializer(raw_instance_vote_info).data instance_vote_info = VotedSerializer(raw_instance_vote_info).data
assert instance_vote_info["type"] == object_type assert instance_vote_info["type"] == object_type
assert instance_vote_info["action"] == "vote"
assert instance_vote_info["id"] == instance.id assert instance_vote_info["id"] == instance.id
assert instance_vote_info["ref"] == instance.ref assert instance_vote_info["ref"] == instance.ref
assert instance_vote_info["slug"] == None assert instance_vote_info["slug"] == None
@ -481,10 +593,10 @@ def test_get_favourites_list_valid_info_for_not_project_types():
assert "test2" in tags_colors assert "test2" in tags_colors
assert instance_vote_info["is_private"] == None assert instance_vote_info["is_private"] == None
assert instance_vote_info["is_voted"] == False assert instance_vote_info["is_voter"] == False
assert instance_vote_info["is_watched"] == False assert instance_vote_info["is_watcher"] == False
assert instance_vote_info["total_watchers"] == 1 assert instance_vote_info["total_watchers"] == 0
assert instance_vote_info["total_votes"] == 3 assert instance_vote_info["total_voters"] == 3
assert instance_vote_info["project"] == instance.project.id assert instance_vote_info["project"] == instance.project.id
assert instance_vote_info["project_name"] == instance.project.name assert instance_vote_info["project_name"] == instance.project.name
assert instance_vote_info["project_slug"] == instance.project.slug assert instance_vote_info["project_slug"] == instance.project.slug
@ -494,7 +606,41 @@ def test_get_favourites_list_valid_info_for_not_project_types():
assert instance_vote_info["assigned_to_photo"] != "" assert instance_vote_info["assigned_to_photo"] != ""
def test_get_favourites_list_permissions(): def test_get_watched_list_permissions():
fav_user = f.UserFactory()
viewer_unpriviliged_user = f.UserFactory()
viewer_priviliged_user = f.UserFactory()
project = f.ProjectFactory(is_private=True, name="Testing project")
project.add_watcher(fav_user)
role = f.RoleFactory(project=project, permissions=["view_project", "view_us", "view_tasks", "view_issues"])
membership = f.MembershipFactory(project=project, role=role, user=viewer_priviliged_user)
user_story = f.UserStoryFactory(project=project, subject="Testing user story")
user_story.add_watcher(fav_user)
task = f.TaskFactory(project=project, subject="Testing task")
task.add_watcher(fav_user)
issue = f.IssueFactory(project=project, subject="Testing issue")
issue.add_watcher(fav_user)
#If the project is private a viewer user without any permission shouldn' see
# any vote
assert len(get_watched_list(fav_user, viewer_unpriviliged_user)) == 0
#If the project is private but the viewer user has permissions the votes should
# be accesible
assert len(get_watched_list(fav_user, viewer_priviliged_user)) == 4
#If the project is private but has the required anon permissions the votes should
# be accesible by any user too
project.anon_permissions = ["view_project", "view_us", "view_tasks", "view_issues"]
project.save()
assert len(get_watched_list(fav_user, viewer_unpriviliged_user)) == 4
def test_get_voted_list_permissions():
fav_user = f.UserFactory() fav_user = f.UserFactory()
viewer_unpriviliged_user = f.UserFactory() viewer_unpriviliged_user = f.UserFactory()
viewer_priviliged_user = f.UserFactory() viewer_priviliged_user = f.UserFactory()
@ -523,14 +669,14 @@ def test_get_favourites_list_permissions():
#If the project is private a viewer user without any permission shouldn' see #If the project is private a viewer user without any permission shouldn' see
# any vote # any vote
assert len(get_favourites_list(fav_user, viewer_unpriviliged_user)) == 0 assert len(get_voted_list(fav_user, viewer_unpriviliged_user)) == 0
#If the project is private but the viewer user has permissions the votes should #If the project is private but the viewer user has permissions the votes should
# be accesible # be accesible
assert len(get_favourites_list(fav_user, viewer_priviliged_user)) == 4 assert len(get_voted_list(fav_user, viewer_priviliged_user)) == 4
#If the project is private but has the required anon permissions the votes should #If the project is private but has the required anon permissions the votes should
# be accesible by any user too # be accesible by any user too
project.anon_permissions = ["view_project", "view_us", "view_tasks", "view_issues"] project.anon_permissions = ["view_project", "view_us", "view_tasks", "view_issues"]
project.save() project.save()
assert len(get_favourites_list(fav_user, viewer_unpriviliged_user)) == 4 assert len(get_voted_list(fav_user, viewer_unpriviliged_user)) == 4

View File

@ -85,7 +85,7 @@ def test_get_issue_votes(client):
response = client.get(url) response = client.get(url)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['votes'] == 5 assert response.data['total_voters'] == 5
def test_get_issue_is_voted(client): def test_get_issue_is_voted(client):
@ -101,21 +101,21 @@ def test_get_issue_is_voted(client):
response = client.get(url_detail) response = client.get(url_detail)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['votes'] == 0 assert response.data['total_voters'] == 0
assert response.data['is_voted'] == False assert response.data['is_voter'] == False
response = client.post(url_upvote) response = client.post(url_upvote)
assert response.status_code == 200 assert response.status_code == 200
response = client.get(url_detail) response = client.get(url_detail)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['votes'] == 1 assert response.data['total_voters'] == 1
assert response.data['is_voted'] == True assert response.data['is_voter'] == True
response = client.post(url_downvote) response = client.post(url_downvote)
assert response.status_code == 200 assert response.status_code == 200
response = client.get(url_detail) response = client.get(url_detail)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['votes'] == 0 assert response.data['total_voters'] == 0
assert response.data['is_voted'] == False assert response.data['is_voter'] == False

View File

@ -87,7 +87,7 @@ def test_get_task_votes(client):
response = client.get(url) response = client.get(url)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['votes'] == 5 assert response.data['total_voters'] == 5
def test_get_task_is_voted(client): def test_get_task_is_voted(client):
@ -103,21 +103,21 @@ def test_get_task_is_voted(client):
response = client.get(url_detail) response = client.get(url_detail)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['votes'] == 0 assert response.data['total_voters'] == 0
assert response.data['is_voted'] == False assert response.data['is_voter'] == False
response = client.post(url_upvote) response = client.post(url_upvote)
assert response.status_code == 200 assert response.status_code == 200
response = client.get(url_detail) response = client.get(url_detail)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['votes'] == 1 assert response.data['total_voters'] == 1
assert response.data['is_voted'] == True assert response.data['is_voter'] == True
response = client.post(url_downvote) response = client.post(url_downvote)
assert response.status_code == 200 assert response.status_code == 200
response = client.get(url_detail) response = client.get(url_detail)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['votes'] == 0 assert response.data['total_voters'] == 0
assert response.data['is_voted'] == False assert response.data['is_voter'] == False

View File

@ -86,7 +86,7 @@ def test_get_user_story_votes(client):
response = client.get(url) response = client.get(url)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['votes'] == 5 assert response.data['total_voters'] == 5
def test_get_user_story_is_voted(client): def test_get_user_story_is_voted(client):
@ -102,21 +102,21 @@ def test_get_user_story_is_voted(client):
response = client.get(url_detail) response = client.get(url_detail)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['votes'] == 0 assert response.data['total_voters'] == 0
assert response.data['is_voted'] == False assert response.data['is_voter'] == False
response = client.post(url_upvote) response = client.post(url_upvote)
assert response.status_code == 200 assert response.status_code == 200
response = client.get(url_detail) response = client.get(url_detail)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['votes'] == 1 assert response.data['total_voters'] == 1
assert response.data['is_voted'] == True assert response.data['is_voter'] == True
response = client.post(url_downvote) response = client.post(url_downvote)
assert response.status_code == 200 assert response.status_code == 200
response = client.get(url_detail) response = client.get(url_detail)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['votes'] == 0 assert response.data['total_voters'] == 0
assert response.data['is_voted'] == False assert response.data['is_voter'] == False

View File

@ -89,9 +89,10 @@ def test_get_issue_watchers(client):
assert response.status_code == 200 assert response.status_code == 200
assert response.data['watchers'] == [user.id] assert response.data['watchers'] == [user.id]
assert response.data['total_watchers'] == 1
def test_get_issue_is_watched(client): def test_get_issue_is_watcher(client):
user = f.UserFactory.create() user = f.UserFactory.create()
issue = f.IssueFactory(owner=user) issue = f.IssueFactory(owner=user)
f.MembershipFactory.create(project=issue.project, user=user, is_owner=True) f.MembershipFactory.create(project=issue.project, user=user, is_owner=True)
@ -104,7 +105,7 @@ def test_get_issue_is_watched(client):
response = client.get(url_detail) response = client.get(url_detail)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['watchers'] == [] assert response.data['watchers'] == []
assert response.data['is_watched'] == False assert response.data['is_watcher'] == False
response = client.post(url_watch) response = client.post(url_watch)
assert response.status_code == 200 assert response.status_code == 200
@ -112,7 +113,7 @@ def test_get_issue_is_watched(client):
response = client.get(url_detail) response = client.get(url_detail)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['watchers'] == [user.id] assert response.data['watchers'] == [user.id]
assert response.data['is_watched'] == True assert response.data['is_watcher'] == True
response = client.post(url_unwatch) response = client.post(url_unwatch)
assert response.status_code == 200 assert response.status_code == 200
@ -120,4 +121,4 @@ def test_get_issue_is_watched(client):
response = client.get(url_detail) response = client.get(url_detail)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['watchers'] == [] assert response.data['watchers'] == []
assert response.data['is_watched'] == False assert response.data['is_watcher'] == False

View File

@ -88,10 +88,10 @@ def test_get_milestone_watchers(client):
response = client.get(url) response = client.get(url)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['watchers'] == [user.id] assert response.data['total_watchers'] == 1
def test_get_milestone_is_watched(client): def test_get_milestone_is_watcher(client):
user = f.UserFactory.create() user = f.UserFactory.create()
milestone = f.MilestoneFactory(owner=user) milestone = f.MilestoneFactory(owner=user)
f.MembershipFactory.create(project=milestone.project, user=user, is_owner=True) f.MembershipFactory.create(project=milestone.project, user=user, is_owner=True)
@ -103,21 +103,21 @@ def test_get_milestone_is_watched(client):
response = client.get(url_detail) response = client.get(url_detail)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['watchers'] == [] assert response.data['total_watchers'] == 0
assert response.data['is_watched'] == False assert response.data['is_watcher'] == False
response = client.post(url_watch) response = client.post(url_watch)
assert response.status_code == 200 assert response.status_code == 200
response = client.get(url_detail) response = client.get(url_detail)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['watchers'] == [user.id] assert response.data['total_watchers'] == 1
assert response.data['is_watched'] == True assert response.data['is_watcher'] == True
response = client.post(url_unwatch) response = client.post(url_unwatch)
assert response.status_code == 200 assert response.status_code == 200
response = client.get(url_detail) response = client.get(url_detail)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['watchers'] == [] assert response.data['total_watchers'] == 0
assert response.data['is_watched'] == False assert response.data['is_watcher'] == False

View File

@ -121,10 +121,10 @@ def test_get_project_watchers(client):
response = client.get(url) response = client.get(url)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['watchers'] == [user.id] assert response.data['total_watchers'] == 1
def test_get_project_is_watched(client): def test_get_project_is_watcher(client):
user = f.UserFactory.create() user = f.UserFactory.create()
project = f.ProjectFactory.create(is_private=False, project = f.ProjectFactory.create(is_private=False,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)), anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
@ -139,21 +139,22 @@ def test_get_project_is_watched(client):
response = client.get(url_detail) response = client.get(url_detail)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['watchers'] == [] assert response.data['total_watchers'] == 0
assert response.data['is_watched'] == False
assert response.data['is_watcher'] == False
response = client.post(url_watch) response = client.post(url_watch)
assert response.status_code == 200 assert response.status_code == 200
response = client.get(url_detail) response = client.get(url_detail)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['watchers'] == [user.id] assert response.data['total_watchers'] == 1
assert response.data['is_watched'] == True assert response.data['is_watcher'] == True
response = client.post(url_unwatch) response = client.post(url_unwatch)
assert response.status_code == 200 assert response.status_code == 200
response = client.get(url_detail) response = client.get(url_detail)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['watchers'] == [] assert response.data['total_watchers'] == 0
assert response.data['is_watched'] == False assert response.data['is_watcher'] == False

View File

@ -89,9 +89,10 @@ def test_get_task_watchers(client):
assert response.status_code == 200 assert response.status_code == 200
assert response.data['watchers'] == [user.id] assert response.data['watchers'] == [user.id]
assert response.data['total_watchers'] == 1
def test_get_task_is_watched(client): def test_get_task_is_watcher(client):
user = f.UserFactory.create() user = f.UserFactory.create()
task = f.TaskFactory(owner=user) task = f.TaskFactory(owner=user)
f.MembershipFactory.create(project=task.project, user=user, is_owner=True) f.MembershipFactory.create(project=task.project, user=user, is_owner=True)
@ -104,7 +105,7 @@ def test_get_task_is_watched(client):
response = client.get(url_detail) response = client.get(url_detail)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['watchers'] == [] assert response.data['watchers'] == []
assert response.data['is_watched'] == False assert response.data['is_watcher'] == False
response = client.post(url_watch) response = client.post(url_watch)
assert response.status_code == 200 assert response.status_code == 200
@ -112,7 +113,7 @@ def test_get_task_is_watched(client):
response = client.get(url_detail) response = client.get(url_detail)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['watchers'] == [user.id] assert response.data['watchers'] == [user.id]
assert response.data['is_watched'] == True assert response.data['is_watcher'] == True
response = client.post(url_unwatch) response = client.post(url_unwatch)
assert response.status_code == 200 assert response.status_code == 200
@ -120,4 +121,4 @@ def test_get_task_is_watched(client):
response = client.get(url_detail) response = client.get(url_detail)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['watchers'] == [] assert response.data['watchers'] == []
assert response.data['is_watched'] == False assert response.data['is_watcher'] == False

View File

@ -89,9 +89,10 @@ def test_get_user_story_watchers(client):
assert response.status_code == 200 assert response.status_code == 200
assert response.data['watchers'] == [user.id] assert response.data['watchers'] == [user.id]
assert response.data['total_watchers'] == 1
def test_get_user_story_is_watched(client): def test_get_user_story_is_watcher(client):
user = f.UserFactory.create() user = f.UserFactory.create()
user_story = f.UserStoryFactory(owner=user) user_story = f.UserStoryFactory(owner=user)
f.MembershipFactory.create(project=user_story.project, user=user, is_owner=True) f.MembershipFactory.create(project=user_story.project, user=user, is_owner=True)
@ -104,7 +105,7 @@ def test_get_user_story_is_watched(client):
response = client.get(url_detail) response = client.get(url_detail)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['watchers'] == [] assert response.data['watchers'] == []
assert response.data['is_watched'] == False assert response.data['is_watcher'] == False
response = client.post(url_watch) response = client.post(url_watch)
assert response.status_code == 200 assert response.status_code == 200
@ -112,7 +113,7 @@ def test_get_user_story_is_watched(client):
response = client.get(url_detail) response = client.get(url_detail)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['watchers'] == [user.id] assert response.data['watchers'] == [user.id]
assert response.data['is_watched'] == True assert response.data['is_watcher'] == True
response = client.post(url_unwatch) response = client.post(url_unwatch)
assert response.status_code == 200 assert response.status_code == 200
@ -120,4 +121,4 @@ def test_get_user_story_is_watched(client):
response = client.get(url_detail) response = client.get(url_detail)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['watchers'] == [] assert response.data['watchers'] == []
assert response.data['is_watched'] == False assert response.data['is_watcher'] == False

View File

@ -88,10 +88,10 @@ def test_get_wikipage_watchers(client):
response = client.get(url) response = client.get(url)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['watchers'] == [user.id] assert response.data['total_watchers'] == 1
def test_get_wikipage_is_watched(client): def test_get_wikipage_is_watcher(client):
user = f.UserFactory.create() user = f.UserFactory.create()
wikipage = f.WikiPageFactory(owner=user) wikipage = f.WikiPageFactory(owner=user)
f.MembershipFactory.create(project=wikipage.project, user=user, is_owner=True) f.MembershipFactory.create(project=wikipage.project, user=user, is_owner=True)
@ -103,21 +103,21 @@ def test_get_wikipage_is_watched(client):
response = client.get(url_detail) response = client.get(url_detail)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['watchers'] == [] assert response.data['total_watchers'] == 0
assert response.data['is_watched'] == False assert response.data['is_watcher'] == False
response = client.post(url_watch) response = client.post(url_watch)
assert response.status_code == 200 assert response.status_code == 200
response = client.get(url_detail) response = client.get(url_detail)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['watchers'] == [user.id] assert response.data['total_watchers'] == 1
assert response.data['is_watched'] == True assert response.data['is_watcher'] == True
response = client.post(url_unwatch) response = client.post(url_unwatch)
assert response.status_code == 200 assert response.status_code == 200
response = client.get(url_detail) response = client.get(url_detail)
assert response.status_code == 200 assert response.status_code == 200
assert response.data['watchers'] == [] assert response.data['total_watchers'] == 0
assert response.data['is_watched'] == False assert response.data['is_watcher'] == False