Merge pull request #475 from taigaio/Refactoring-likes-votes-watchers-and-favourites-names

Refactoring likes, votes, watchers and favourites names
remotes/origin/logger
David Barragán Merino 2015-10-02 14:49:51 +02:00
commit 65bdad4e39
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.choices import NotifyLevel
from taiga.projects.notifications.utils import (
attach_project_watchers_attrs_to_queryset,
attach_project_is_watched_to_queryset,
attach_project_total_watchers_attrs_to_queryset,
attach_project_is_watcher_to_queryset,
attach_notify_level_to_project_queryset)
from taiga.projects.mixins.ordering import BulkUpdateOrderMixin
@ -69,9 +69,9 @@ class ProjectViewSet(LikedResourceMixin, HistoryResourceMixin, ModelCrudViewSet)
def get_queryset(self):
qs = super().get_queryset()
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():
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)
return qs

View File

@ -76,7 +76,7 @@ class IssueViewSet(OCCResourceMixin, VotedResourceMixin, HistoryResourceMixin, W
"owner",
"assigned_to",
"subject",
"votes_count")
"total_voters")
def get_serializer_class(self, *args, **kwargs):
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.notifications.validators import WatchersValidator
from taiga.projects.serializers import BasicIssueStatusSerializer
from taiga.projects.notifications.mixins import WatchedResourceModelSerializer
from taiga.projects.votes.mixins.serializers import VotedResourceSerializerMixin
from taiga.projects.notifications.mixins import EditableWatchedResourceModelSerializer
from taiga.projects.votes.mixins.serializers import VoteResourceSerializerMixin
from taiga.users.serializers import UserBasicInfoSerializer
from . import models
class IssueSerializer(WatchersValidator, VotedResourceSerializerMixin, WatchedResourceModelSerializer, serializers.ModelSerializer):
class IssueSerializer(WatchersValidator, VoteResourceSerializerMixin, EditableWatchedResourceModelSerializer, serializers.ModelSerializer):
tags = TagsField(required=False)
external_reference = PgArrayField(required=False)
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.fields import WatchersField
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 . import models
from . serializers import WatcherSerializer
@ -50,8 +53,9 @@ class WatchedResourceMixin:
def attach_watchers_attrs_to_queryset(self, queryset):
qs = attach_watchers_to_queryset(queryset)
qs = attach_total_watchers_to_queryset(queryset)
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
@ -178,12 +182,20 @@ class WatchedModelMixin(object):
class WatchedResourceModelSerializer(serializers.ModelSerializer):
is_watched = serializers.SerializerMethodField("get_is_watched")
watchers = WatchersField(required=False)
is_watcher = serializers.SerializerMethodField("get_is_watcher")
total_watchers = serializers.SerializerMethodField("get_total_watchers")
def get_is_watched(self, obj):
# The "is_watched" attribute is attached in the get_queryset of the viewset.
return getattr(obj, "is_watched", False) or False
def get_is_watcher(self, obj):
# The "is_watcher" attribute is attached in the get_queryset of the viewset.
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):
#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)
def save(self, **kwargs):
obj = super(WatchedResourceModelSerializer, self).save(**kwargs)
obj = super(EditableWatchedResourceModelSerializer, self).save(**kwargs)
self.fields["watchers"] = WatchersField(required=False)
obj.watchers = [user.id for user in obj.get_watchers()]
return obj

View File

@ -40,8 +40,8 @@ def attach_watchers_to_queryset(queryset, as_field="watchers"):
return qs
def attach_is_watched_to_queryset(queryset, user, as_field="is_watched"):
"""Attach is_watched boolean to each object of the queryset.
def attach_is_watcher_to_queryset(queryset, user, as_field="is_watcher"):
"""Attach is_watcher boolean to each object of the queryset.
:param user: A users.User object model
:param queryset: A Django queryset object.
@ -64,8 +64,28 @@ def attach_is_watched_to_queryset(queryset, user, as_field="is_watched"):
return qs
def attach_project_is_watched_to_queryset(queryset, user, as_field="is_watched"):
"""Attach is_watched boolean to each object of the projects queryset.
def attach_total_watchers_to_queryset(queryset, as_field="total_watchers"):
"""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 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
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.
: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
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
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)
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 TagsColorsField
from taiga.projects.notifications.validators import WatchersValidator
from taiga.users.services import get_photo_or_gravatar_url
from taiga.users.serializers import UserSerializer
from taiga.users.serializers import UserBasicInfoSerializer
@ -40,12 +38,12 @@ from taiga.projects.notifications import models as notify_models
from . import models
from . import services
from .notifications.mixins import WatchedResourceModelSerializer
from .validators import ProjectExistsValidator
from .custom_attributes.serializers import UserStoryCustomAttributeSerializer
from .custom_attributes.serializers import TaskCustomAttributeSerializer
from .custom_attributes.serializers import IssueCustomAttributeSerializer
from .notifications.mixins import WatchedResourceModelSerializer
from .votes.mixins.serializers import LikedResourceSerializerMixin
from .votes.mixins.serializers import FanResourceSerializerMixin
######################################################
## Custom values for selectors
@ -310,7 +308,7 @@ class ProjectMemberSerializer(serializers.ModelSerializer):
## Projects
######################################################
class ProjectSerializer(WatchersValidator, LikedResourceSerializerMixin, WatchedResourceModelSerializer, serializers.ModelSerializer):
class ProjectSerializer(FanResourceSerializerMixin, WatchedResourceModelSerializer, serializers.ModelSerializer):
tags = TagsField(default=[], required=False)
anon_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.notifications.validators import WatchersValidator
from taiga.projects.serializers import BasicTaskStatusSerializerSerializer
from taiga.projects.notifications.mixins import WatchedResourceModelSerializer
from taiga.projects.votes.mixins.serializers import VotedResourceSerializerMixin
from taiga.projects.notifications.mixins import EditableWatchedResourceModelSerializer
from taiga.projects.votes.mixins.serializers import VoteResourceSerializerMixin
from taiga.users.serializers import UserBasicInfoSerializer
from . import models
class TaskSerializer(WatchersValidator, VotedResourceSerializerMixin, WatchedResourceModelSerializer, serializers.ModelSerializer):
class TaskSerializer(WatchersValidator, VoteResourceSerializerMixin, EditableWatchedResourceModelSerializer, serializers.ModelSerializer):
tags = TagsField(required=False, default=[])
external_reference = PgArrayField(required=False)
comment = serializers.SerializerMethodField("get_comment")

View File

@ -70,7 +70,7 @@ class UserStoryViewSet(OCCResourceMixin, VotedResourceMixin, HistoryResourceMixi
order_by_fields = ["backlog_order",
"sprint_order",
"kanban_order",
"votes_count"]
"total_voters"]
# Specific filter used for filtering neighbor user stories
_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.notifications.validators import WatchersValidator
from taiga.projects.serializers import BasicUserStoryStatusSerializer
from taiga.projects.notifications.mixins import WatchedResourceModelSerializer
from taiga.projects.votes.mixins.serializers import VotedResourceSerializerMixin
from taiga.projects.notifications.mixins import EditableWatchedResourceModelSerializer
from taiga.projects.votes.mixins.serializers import VoteResourceSerializerMixin
from taiga.users.serializers import UserBasicInfoSerializer
@ -45,7 +45,7 @@ class RolePointsField(serializers.WritableField):
return json.loads(obj)
class UserStorySerializer(WatchersValidator, VotedResourceSerializerMixin, WatchedResourceModelSerializer, serializers.ModelSerializer):
class UserStorySerializer(WatchersValidator, VoteResourceSerializerMixin, EditableWatchedResourceModelSerializer, serializers.ModelSerializer):
tags = TagsField(default=[], required=False)
external_reference = PgArrayField(required=False)
points = RolePointsField(source="role_points", required=False)

View File

@ -17,21 +17,27 @@
from taiga.base.api import serializers
class BaseVotedResourceSerializer(serializers.ModelSerializer):
def get_votes_counter(self, obj):
# The "votes_count" attribute is attached in the get_queryset of the viewset.
return getattr(obj, "votes_count", 0) or 0
class FanResourceSerializerMixin(serializers.ModelSerializer):
is_fan = serializers.SerializerMethodField("get_is_fan")
total_fans = serializers.SerializerMethodField("get_total_fans")
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.
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):
likes = serializers.SerializerMethodField("get_votes_counter")
is_liked = serializers.SerializerMethodField("get_is_voted")
class VoteResourceSerializerMixin(serializers.ModelSerializer):
is_voter = serializers.SerializerMethodField("get_is_voter")
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):
votes = serializers.SerializerMethodField("get_votes_counter")
is_voted = serializers.SerializerMethodField("get_is_voted")
def get_total_voters(self, obj):
# The "total_likes" attribute is attached in the get_queryset of the viewset.
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 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:
@ -33,10 +33,10 @@ class BaseVotedResource:
# return self.attach_votes_attrs_to_queryset(qs)
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():
qs = attach_is_vote_to_queryset(self.request.user, qs)
qs = attach_is_voter_to_queryset(self.request.user, 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)
with atomic():
vote, created = Vote.objects.get_or_create(content_type=obj_type, object_id=obj.id, user=user)
if not created:
return

View File

@ -18,7 +18,7 @@
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.
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
type = apps.get_model("contenttypes", "ContentType").objects.get_for_model(model)
sql = """SELECT coalesce(SUM(votes_count), 0) FROM (
SELECT coalesce(votes_votes.count, 0) votes_count
sql = """SELECT coalesce(SUM(total_voters), 0) FROM (
SELECT coalesce(votes_votes.count, 0) total_voters
FROM votes_votes
WHERE votes_votes.content_type_id = {type_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
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.
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)
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"])
def favourites(self, request, *args, **kwargs):
def watched(self, request, *args, **kwargs):
for_user = get_object_or_404(models.User, **kwargs)
from_user = request.user
self.check_permissions(request, 'favourites', for_user)
self.check_permissions(request, 'watched', for_user)
filters = {
"type": request.GET.get("type", None),
"action": request.GET.get("action", 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)
elements = page.object_list if page is not None else self.object_list
extra_args = {
"many": True,
"user_votes": services.get_voted_content_for_user(request.user),
"user_watching": services.get_watched_content_for_user(request.user),
}
if page is not None:
serializer = serializers.FavouriteSerializer(page.object_list, **extra_args)
else:
serializer = serializers.FavouriteSerializer(self.object_list, **extra_args)
response_data = [self._serialize_liked_content(elem, **extra_args).data for elem in elements]
return response.Ok(response_data)
@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"])
def password_recovery(self, request, pk=None):

View File

@ -46,7 +46,8 @@ class UserPermission(TaigaResourcePermission):
remove_avatar_perms = IsAuthenticated()
change_email_perms = AllowAny()
contacts_perms = AllowAny()
favourites_perms = AllowAny()
liked_perms = AllowAny()
watched_perms = AllowAny()
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()
action = serializers.CharField()
id = serializers.IntegerField()
ref = serializers.IntegerField()
slug = serializers.CharField()
@ -175,11 +174,8 @@ class FavouriteSerializer(serializers.Serializer):
created_date = serializers.DateTimeField()
is_private = serializers.SerializerMethodField("get_is_private")
is_voted = serializers.SerializerMethodField("get_is_voted")
is_watched = serializers.SerializerMethodField("get_is_watched")
is_watcher = serializers.SerializerMethodField("get_is_watcher")
total_watchers = serializers.IntegerField()
total_votes = serializers.IntegerField()
project = serializers.SerializerMethodField("get_project")
project_name = serializers.SerializerMethodField("get_project_name")
@ -196,7 +192,7 @@ class FavouriteSerializer(serializers.Serializer):
self.user_watching = kwargs.pop("user_watching", {})
# Instantiate the superclass normally
super(FavouriteSerializer, self).__init__(*args, **kwargs)
super(LikeSerializer, self).__init__(*args, **kwargs)
def _none_if_project(self, obj, property):
type = obj.get("type", "")
@ -230,10 +226,7 @@ class FavouriteSerializer(serializers.Serializer):
def get_project_is_private(self, obj):
return self._none_if_project(obj, "project_is_private")
def get_is_voted(self, obj):
return obj["id"] in self.user_votes.get(obj["type"], [])
def get_is_watched(self, obj):
def get_is_watcher(self, obj):
return obj["id"] in self.user_watching.get(obj["type"], [])
def get_photo(self, obj):
@ -248,3 +241,19 @@ class FavouriteSerializer(serializers.Serializer):
def get_tags_color(self, obj):
tags = obj.get("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
def _build_favourites_sql_for_projects(for_user):
def _build_watched_sql_for_projects(for_user):
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,
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
FROM notifications_notifypolicy
INNER JOIN projects_project
@ -207,11 +207,20 @@ def _build_favourites_sql_for_projects(for_user):
LEFT JOIN votes_votes
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}
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,
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
FROM votes_vote
INNER JOIN projects_project
@ -233,65 +242,43 @@ def _build_favourites_sql_for_projects(for_user):
return sql
def _build_favourites_sql_for_type(for_user, type, table_name, ref_column="ref",
def _build_sql_for_type(for_user, type, table_name, action_table, ref_column="ref",
project_column="project_id", assigned_to_column="assigned_to_id",
slug_column="slug", subject_column="subject"):
sql = """
SELECT {table_name}.id AS id, {ref_column} AS ref, '{type}' AS type, 'watch' AS action,
tags, notifications_watched.object_id AS object_id, {table_name}.{project_column} AS project,
SELECT {table_name}.id AS id, {ref_column} AS ref, '{type}' AS type,
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,
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
FROM notifications_watched
FROM {action_table}
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}
ON ({table_name}.id = notifications_watched.object_id)
ON ({table_name}.id = {action_table}.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 notifications_watched.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}
WHERE {action_table}.user_id = {for_user_id}
"""
sql = sql.format(for_user_id=for_user.id, type=type, table_name=table_name,
ref_column = ref_column, project_column=project_column,
assigned_to_column=assigned_to_column, slug_column=slug_column,
subject_column=subject_column)
action_table=action_table, ref_column = ref_column,
project_column=project_column, assigned_to_column=assigned_to_column,
slug_column=slug_column, subject_column=subject_column)
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 = ""
and_needed = False
if type:
filters_sql += " AND type = '{type}' ".format(type=type)
if action:
filters_sql += " AND action = '{action}' ".format(action=action)
if q:
filters_sql += """ AND (
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,
from_user_id=from_user_id,
filters_sql=filters_sql,
userstories_sql=_build_favourites_sql_for_type(for_user, "userstory", "userstories_userstory", slug_column="null"),
tasks_sql=_build_favourites_sql_for_type(for_user, "task", "tasks_task", slug_column="null"),
issues_sql=_build_favourites_sql_for_type(for_user, "issue", "issues_issue", slug_column="null"),
projects_sql=_build_favourites_sql_for_projects(for_user))
userstories_sql=_build_sql_for_type(for_user, "userstory", "userstories_userstory", action_table, slug_column="null"),
tasks_sql=_build_sql_for_type(for_user, "task", "tasks_task", action_table, slug_column="null"),
issues_sql=_build_sql_for_type(for_user, "issue", "issues_issue", action_table, slug_column="null"),
projects_sql=project_sql_builder(for_user))
cursor = connection.cursor()
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))
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.wiki import models as wiki_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
@ -104,7 +104,7 @@ class PointSerializer(serializers.Serializer):
return obj.value
class UserStorySerializer(CustomAttributesValuesWebhookSerializerMixin, WatchedResourceModelSerializer,
class UserStorySerializer(CustomAttributesValuesWebhookSerializerMixin, EditableWatchedResourceModelSerializer,
serializers.ModelSerializer):
tags = TagsField(default=[], required=False)
external_reference = PgArrayField(required=False)
@ -121,7 +121,7 @@ class UserStorySerializer(CustomAttributesValuesWebhookSerializerMixin, WatchedR
return project.userstorycustomattributes.all()
class TaskSerializer(CustomAttributesValuesWebhookSerializerMixin, WatchedResourceModelSerializer,
class TaskSerializer(CustomAttributesValuesWebhookSerializerMixin, EditableWatchedResourceModelSerializer,
serializers.ModelSerializer):
tags = TagsField(default=[], required=False)
owner = UserSerializer()
@ -135,7 +135,7 @@ class TaskSerializer(CustomAttributesValuesWebhookSerializerMixin, WatchedResour
return project.taskcustomattributes.all()
class IssueSerializer(CustomAttributesValuesWebhookSerializerMixin, WatchedResourceModelSerializer,
class IssueSerializer(CustomAttributesValuesWebhookSerializerMixin, EditableWatchedResourceModelSerializer,
serializers.ModelSerializer):
tags = TagsField(default=[], required=False)
owner = UserSerializer()

View File

@ -289,8 +289,20 @@ def test_user_action_change_email(client, data):
assert results == [204, 204, 204]
def test_user_list_votes(client, data):
url = reverse('users-favourites', kwargs={"pk": data.registered_user.pk})
def test_user_list_watched(client, data):
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 = [
None,
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.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.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
@ -348,7 +348,7 @@ def test_mail_permissions(client):
assert "email" in response.data
def test_get_favourites_list():
def test_get_watched_list():
fav_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"])
membership = f.MembershipFactory(project=project, role=role, user=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)
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)
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)
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)
task = f.TaskFactory(project=project, subject="Testing task")
task.add_watcher(fav_user)
content_type = ContentType.objects.get_for_model(task)
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)
issue = f.IssueFactory(project=project, subject="Testing issue")
issue.add_watcher(fav_user)
content_type = ContentType.objects.get_for_model(issue)
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)
assert len(get_favourites_list(fav_user, viewer_user)) == 8
assert len(get_favourites_list(fav_user, viewer_user, type="project")) == 2
assert len(get_favourites_list(fav_user, viewer_user, type="userstory")) == 2
assert len(get_favourites_list(fav_user, viewer_user, type="task")) == 2
assert len(get_favourites_list(fav_user, viewer_user, type="issue")) == 2
assert len(get_favourites_list(fav_user, viewer_user, type="unknown")) == 0
assert len(get_voted_list(fav_user, viewer_user)) == 4
assert len(get_voted_list(fav_user, viewer_user, type="project")) == 1
assert len(get_voted_list(fav_user, viewer_user, type="userstory")) == 1
assert len(get_voted_list(fav_user, viewer_user, type="task")) == 1
assert len(get_voted_list(fav_user, viewer_user, type="issue")) == 1
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_favourites_list(fav_user, viewer_user, action="vote")) == 4
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
assert len(get_voted_list(fav_user, viewer_user, q="issue")) == 1
assert len(get_voted_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()
viewer_user = f.UserFactory()
watcher_user = f.UserFactory()
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)
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)
raw_project_vote_info = get_favourites_list(fav_user, viewer_user)[0]
project_vote_info = FavouriteSerializer(raw_project_vote_info).data
raw_project_vote_info = get_voted_list(fav_user, viewer_user)[0]
project_vote_info = FanSerializer(raw_project_vote_info).data
assert project_vote_info["type"] == "project"
assert project_vote_info["action"] == "vote"
assert project_vote_info["id"] == project.id
assert project_vote_info["ref"] == None
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 project_vote_info["is_private"] == project.is_private
assert project_vote_info["is_voted"] == False
assert project_vote_info["is_watched"] == False
assert project_vote_info["total_watchers"] == 1
assert project_vote_info["total_votes"] == 1
import pprint
pprint.pprint(project_vote_info)
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_name"] == 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
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()
viewer_user = f.UserFactory()
watcher_user = f.UserFactory()
assigned_to_user = f.UserFactory()
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"],
assigned_to=assigned_to_user)
instance.add_watcher(watcher_user)
content_type = ContentType.objects.get_for_model(instance)
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)
raw_instance_vote_info = get_favourites_list(fav_user, viewer_user, type=object_type)[0]
instance_vote_info = FavouriteSerializer(raw_instance_vote_info).data
raw_instance_vote_info = get_voted_list(fav_user, viewer_user, type=object_type)[0]
instance_vote_info = VotedSerializer(raw_instance_vote_info).data
assert instance_vote_info["type"] == object_type
assert instance_vote_info["action"] == "vote"
assert instance_vote_info["id"] == instance.id
assert instance_vote_info["ref"] == instance.ref
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 instance_vote_info["is_private"] == None
assert instance_vote_info["is_voted"] == False
assert instance_vote_info["is_watched"] == False
assert instance_vote_info["total_watchers"] == 1
assert instance_vote_info["total_votes"] == 3
assert instance_vote_info["is_voter"] == False
assert instance_vote_info["is_watcher"] == False
assert instance_vote_info["total_watchers"] == 0
assert instance_vote_info["total_voters"] == 3
assert instance_vote_info["project"] == instance.project.id
assert instance_vote_info["project_name"] == instance.project.name
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"] != ""
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()
viewer_unpriviliged_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
# 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
# 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
# be accesible by any user too
project.anon_permissions = ["view_project", "view_us", "view_tasks", "view_issues"]
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)
assert response.status_code == 200
assert response.data['votes'] == 5
assert response.data['total_voters'] == 5
def test_get_issue_is_voted(client):
@ -101,21 +101,21 @@ def test_get_issue_is_voted(client):
response = client.get(url_detail)
assert response.status_code == 200
assert response.data['votes'] == 0
assert response.data['is_voted'] == False
assert response.data['total_voters'] == 0
assert response.data['is_voter'] == False
response = client.post(url_upvote)
assert response.status_code == 200
response = client.get(url_detail)
assert response.status_code == 200
assert response.data['votes'] == 1
assert response.data['is_voted'] == True
assert response.data['total_voters'] == 1
assert response.data['is_voter'] == True
response = client.post(url_downvote)
assert response.status_code == 200
response = client.get(url_detail)
assert response.status_code == 200
assert response.data['votes'] == 0
assert response.data['is_voted'] == False
assert response.data['total_voters'] == 0
assert response.data['is_voter'] == False

View File

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

View File

@ -86,7 +86,7 @@ def test_get_user_story_votes(client):
response = client.get(url)
assert response.status_code == 200
assert response.data['votes'] == 5
assert response.data['total_voters'] == 5
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)
assert response.status_code == 200
assert response.data['votes'] == 0
assert response.data['is_voted'] == False
assert response.data['total_voters'] == 0
assert response.data['is_voter'] == False
response = client.post(url_upvote)
assert response.status_code == 200
response = client.get(url_detail)
assert response.status_code == 200
assert response.data['votes'] == 1
assert response.data['is_voted'] == True
assert response.data['total_voters'] == 1
assert response.data['is_voter'] == True
response = client.post(url_downvote)
assert response.status_code == 200
response = client.get(url_detail)
assert response.status_code == 200
assert response.data['votes'] == 0
assert response.data['is_voted'] == False
assert response.data['total_voters'] == 0
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.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()
issue = f.IssueFactory(owner=user)
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)
assert response.status_code == 200
assert response.data['watchers'] == []
assert response.data['is_watched'] == False
assert response.data['is_watcher'] == False
response = client.post(url_watch)
assert response.status_code == 200
@ -112,7 +113,7 @@ def test_get_issue_is_watched(client):
response = client.get(url_detail)
assert response.status_code == 200
assert response.data['watchers'] == [user.id]
assert response.data['is_watched'] == True
assert response.data['is_watcher'] == True
response = client.post(url_unwatch)
assert response.status_code == 200
@ -120,4 +121,4 @@ def test_get_issue_is_watched(client):
response = client.get(url_detail)
assert response.status_code == 200
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)
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()
milestone = f.MilestoneFactory(owner=user)
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)
assert response.status_code == 200
assert response.data['watchers'] == []
assert response.data['is_watched'] == False
assert response.data['total_watchers'] == 0
assert response.data['is_watcher'] == False
response = client.post(url_watch)
assert response.status_code == 200
response = client.get(url_detail)
assert response.status_code == 200
assert response.data['watchers'] == [user.id]
assert response.data['is_watched'] == True
assert response.data['total_watchers'] == 1
assert response.data['is_watcher'] == True
response = client.post(url_unwatch)
assert response.status_code == 200
response = client.get(url_detail)
assert response.status_code == 200
assert response.data['watchers'] == []
assert response.data['is_watched'] == False
assert response.data['total_watchers'] == 0
assert response.data['is_watcher'] == False

View File

@ -121,10 +121,10 @@ def test_get_project_watchers(client):
response = client.get(url)
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()
project = f.ProjectFactory.create(is_private=False,
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)
assert response.status_code == 200
assert response.data['watchers'] == []
assert response.data['is_watched'] == False
assert response.data['total_watchers'] == 0
assert response.data['is_watcher'] == False
response = client.post(url_watch)
assert response.status_code == 200
response = client.get(url_detail)
assert response.status_code == 200
assert response.data['watchers'] == [user.id]
assert response.data['is_watched'] == True
assert response.data['total_watchers'] == 1
assert response.data['is_watcher'] == True
response = client.post(url_unwatch)
assert response.status_code == 200
response = client.get(url_detail)
assert response.status_code == 200
assert response.data['watchers'] == []
assert response.data['is_watched'] == False
assert response.data['total_watchers'] == 0
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.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()
task = f.TaskFactory(owner=user)
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)
assert response.status_code == 200
assert response.data['watchers'] == []
assert response.data['is_watched'] == False
assert response.data['is_watcher'] == False
response = client.post(url_watch)
assert response.status_code == 200
@ -112,7 +113,7 @@ def test_get_task_is_watched(client):
response = client.get(url_detail)
assert response.status_code == 200
assert response.data['watchers'] == [user.id]
assert response.data['is_watched'] == True
assert response.data['is_watcher'] == True
response = client.post(url_unwatch)
assert response.status_code == 200
@ -120,4 +121,4 @@ def test_get_task_is_watched(client):
response = client.get(url_detail)
assert response.status_code == 200
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.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_story = f.UserStoryFactory(owner=user)
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)
assert response.status_code == 200
assert response.data['watchers'] == []
assert response.data['is_watched'] == False
assert response.data['is_watcher'] == False
response = client.post(url_watch)
assert response.status_code == 200
@ -112,7 +113,7 @@ def test_get_user_story_is_watched(client):
response = client.get(url_detail)
assert response.status_code == 200
assert response.data['watchers'] == [user.id]
assert response.data['is_watched'] == True
assert response.data['is_watcher'] == True
response = client.post(url_unwatch)
assert response.status_code == 200
@ -120,4 +121,4 @@ def test_get_user_story_is_watched(client):
response = client.get(url_detail)
assert response.status_code == 200
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)
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()
wikipage = f.WikiPageFactory(owner=user)
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)
assert response.status_code == 200
assert response.data['watchers'] == []
assert response.data['is_watched'] == False
assert response.data['total_watchers'] == 0
assert response.data['is_watcher'] == False
response = client.post(url_watch)
assert response.status_code == 200
response = client.get(url_detail)
assert response.status_code == 200
assert response.data['watchers'] == [user.id]
assert response.data['is_watched'] == True
assert response.data['total_watchers'] == 1
assert response.data['is_watcher'] == True
response = client.post(url_unwatch)
assert response.status_code == 200
response = client.get(url_detail)
assert response.status_code == 200
assert response.data['watchers'] == []
assert response.data['is_watched'] == False
assert response.data['total_watchers'] == 0
assert response.data['is_watcher'] == False