User favourites API
parent
bccdc2fae1
commit
3492b46cc9
|
@ -114,6 +114,33 @@ class UsersViewSet(ModelCrudViewSet):
|
|||
self.check_permissions(request, "stats", user)
|
||||
return response.Ok(services.get_stats_for_user(user, request.user))
|
||||
|
||||
@detail_route(methods=["GET"])
|
||||
def favourites(self, request, *args, **kwargs):
|
||||
for_user = get_object_or_404(models.User, **kwargs)
|
||||
from_user = request.user
|
||||
self.check_permissions(request, 'favourites', 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)
|
||||
page = self.paginate_queryset(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)
|
||||
|
||||
return response.Ok(serializer.data)
|
||||
|
||||
@list_route(methods=["POST"])
|
||||
def password_recovery(self, request, pk=None):
|
||||
username_or_email = request.DATA.get('username', None)
|
||||
|
|
|
@ -47,6 +47,7 @@ class UserPermission(TaigaResourcePermission):
|
|||
starred_perms = AllowAny()
|
||||
change_email_perms = AllowAny()
|
||||
contacts_perms = AllowAny()
|
||||
favourites_perms = AllowAny()
|
||||
|
||||
|
||||
class RolesPermission(TaigaResourcePermission):
|
||||
|
|
|
@ -19,11 +19,14 @@ from django.core.exceptions import ValidationError
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from taiga.base.api import serializers
|
||||
from taiga.base.fields import PgArrayField
|
||||
from taiga.base.fields import PgArrayField, TagsField
|
||||
|
||||
from taiga.projects.models import Project
|
||||
from .models import User, Role
|
||||
from .services import get_photo_or_gravatar_url, get_big_photo_or_gravatar_url
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
import re
|
||||
|
||||
|
||||
|
@ -149,3 +152,55 @@ class ProjectRoleSerializer(serializers.ModelSerializer):
|
|||
model = Role
|
||||
fields = ('id', 'name', 'slug', 'order', 'computable')
|
||||
i18n_fields = ("name",)
|
||||
|
||||
|
||||
######################################################
|
||||
## Favourite
|
||||
######################################################
|
||||
|
||||
|
||||
class FavouriteSerializer(serializers.Serializer):
|
||||
type = serializers.CharField()
|
||||
action = serializers.CharField()
|
||||
id = serializers.IntegerField()
|
||||
ref = serializers.IntegerField()
|
||||
slug = serializers.CharField()
|
||||
subject = serializers.CharField()
|
||||
tags = TagsField(default=[])
|
||||
project = serializers.IntegerField()
|
||||
assigned_to = serializers.IntegerField()
|
||||
total_watchers = serializers.IntegerField()
|
||||
|
||||
is_voted = serializers.SerializerMethodField("get_is_voted")
|
||||
is_watched = serializers.SerializerMethodField("get_is_watched")
|
||||
|
||||
created_date = serializers.DateTimeField()
|
||||
|
||||
project_name = serializers.CharField()
|
||||
project_slug = serializers.CharField()
|
||||
project_is_private = serializers.CharField()
|
||||
|
||||
assigned_to_username = serializers.CharField()
|
||||
assigned_to_full_name = serializers.CharField()
|
||||
assigned_to_photo = serializers.SerializerMethodField("get_photo")
|
||||
|
||||
total_votes = serializers.IntegerField()
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
# Don't pass the extra ids args up to the superclass
|
||||
self.user_votes = kwargs.pop("user_votes", {})
|
||||
self.user_watching = kwargs.pop("user_watching", {})
|
||||
|
||||
# Instantiate the superclass normally
|
||||
super(FavouriteSerializer, self).__init__(*args, **kwargs)
|
||||
|
||||
def get_is_voted(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"], [])
|
||||
|
||||
def get_photo(self, obj):
|
||||
UserData = namedtuple("UserData", ["photo", "email"])
|
||||
user_data = UserData(photo=obj["assigned_to_photo"], email=obj.get("assigned_to_email") or "")
|
||||
return get_photo_or_gravatar_url(user_data)
|
||||
|
|
|
@ -20,6 +20,7 @@ This model contains a domain logic for users application.
|
|||
|
||||
from django.apps import apps
|
||||
from django.db.models import Q
|
||||
from django.db import connection
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
|
@ -142,3 +143,173 @@ def get_stats_for_user(from_user, by_user):
|
|||
'total_num_closed_userstories': total_num_closed_userstories,
|
||||
}
|
||||
return project_stats
|
||||
|
||||
|
||||
def get_voted_content_for_user(user):
|
||||
"""Returns a dict where:
|
||||
- The key is the content_type model
|
||||
- The values are list of id's of the different objects voted by the user
|
||||
"""
|
||||
if user.is_anonymous():
|
||||
return {}
|
||||
|
||||
user_votes = {}
|
||||
for (ct_model, object_id) in user.votes.values_list("content_type__model", "object_id"):
|
||||
list = user_votes.get(ct_model, [])
|
||||
list.append(object_id)
|
||||
user_votes[ct_model] = list
|
||||
|
||||
return user_votes
|
||||
|
||||
|
||||
def get_watched_content_for_user(user):
|
||||
"""Returns a dict where:
|
||||
- The key is the content_type model
|
||||
- The values are list of id's of the different objects watched by the user
|
||||
"""
|
||||
if user.is_anonymous():
|
||||
return {}
|
||||
|
||||
user_watches = {}
|
||||
for (ct_model, object_id) in user.watched.values_list("content_type__model", "object_id"):
|
||||
list = user_watches.get(ct_model, [])
|
||||
list.append(object_id)
|
||||
user_watches[ct_model] = list
|
||||
|
||||
return user_watches
|
||||
|
||||
|
||||
def _build_favourites_sql_for_type(for_user, type, table_name, 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,
|
||||
{slug_column} AS slug, {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
|
||||
FROM notifications_watched
|
||||
INNER JOIN django_content_type
|
||||
ON (notifications_watched.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)
|
||||
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, {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
|
||||
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)
|
||||
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,
|
||||
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):
|
||||
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(coalesce(subject, '')) @@ plainto_tsquery('{q}') ".format(q=q)
|
||||
|
||||
sql = """
|
||||
-- BEGIN Basic info: we need to mix info from different tables and denormalize it
|
||||
SELECT entities.*,
|
||||
projects_project.name as project_name, projects_project.slug as project_slug, projects_project.is_private as project_is_private,
|
||||
users_user.username assigned_to_username, users_user.full_name assigned_to_full_name, users_user.photo assigned_to_photo, users_user.email assigned_to_email
|
||||
FROM (
|
||||
{userstories_sql}
|
||||
UNION
|
||||
{tasks_sql}
|
||||
UNION
|
||||
{issues_sql}
|
||||
UNION
|
||||
{projects_sql}
|
||||
) as entities
|
||||
-- END Basic info
|
||||
|
||||
-- BEGIN Project info
|
||||
LEFT JOIN projects_project
|
||||
ON (entities.project = projects_project.id)
|
||||
-- END Project info
|
||||
|
||||
-- BEGIN Assigned to user info
|
||||
LEFT JOIN users_user
|
||||
ON (assigned_to = users_user.id)
|
||||
-- END Assigned to user info
|
||||
|
||||
-- BEGIN Permissions checking
|
||||
LEFT JOIN projects_membership
|
||||
-- Here we check the memberbships from the user requesting the info
|
||||
ON (projects_membership.user_id = {from_user_id} AND projects_membership.project_id = entities.project)
|
||||
|
||||
LEFT JOIN users_role
|
||||
ON (entities.project = users_role.project_id AND users_role.id = projects_membership.role_id)
|
||||
|
||||
WHERE
|
||||
-- public project
|
||||
(
|
||||
projects_project.is_private = false
|
||||
OR(
|
||||
-- private project where the view_ permission is included in the user role for that project or in the anon permissions
|
||||
projects_project.is_private = true
|
||||
AND(
|
||||
(entities.type = 'issue' AND 'view_issues' = ANY (array_cat(users_role.permissions, projects_project.anon_permissions)))
|
||||
OR (entities.type = 'task' AND 'view_tasks' = ANY (array_cat(users_role.permissions, projects_project.anon_permissions)))
|
||||
OR (entities.type = 'userstory' AND 'view_us' = ANY (array_cat(users_role.permissions, projects_project.anon_permissions)))
|
||||
OR (entities.type = 'project' AND 'view_project' = ANY (array_cat(users_role.permissions, projects_project.anon_permissions)))
|
||||
)
|
||||
))
|
||||
-- END Permissions checking
|
||||
{filters_sql}
|
||||
|
||||
ORDER BY entities.created_date;
|
||||
"""
|
||||
|
||||
from_user_id = -1
|
||||
if not from_user.is_anonymous():
|
||||
from_user_id = from_user.id
|
||||
|
||||
sql = sql.format(
|
||||
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_type(for_user, "project", "projects_project",
|
||||
ref_column="null",
|
||||
project_column="id",
|
||||
assigned_to_column="null",
|
||||
subject_column="projects_project.name")
|
||||
)
|
||||
|
||||
cursor = connection.cursor()
|
||||
cursor.execute(sql)
|
||||
|
||||
desc = cursor.description
|
||||
return [
|
||||
dict(zip([col[0] for col in desc], row))
|
||||
for row in cursor.fetchall()
|
||||
]
|
||||
|
|
|
@ -287,3 +287,15 @@ def test_user_action_change_email(client, data):
|
|||
after_each_request()
|
||||
results = helper_test_http_method(client, 'post', url, patch_data, users, after_each_request=after_each_request)
|
||||
assert results == [204, 204, 204]
|
||||
|
||||
|
||||
def test_user_list_votes(client, data):
|
||||
url = reverse('users-favourites', 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]
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import pytest
|
||||
from tempfile import NamedTemporaryFile
|
||||
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
from .. import factories as f
|
||||
|
@ -9,6 +10,7 @@ from taiga.base.utils import json
|
|||
from taiga.users import models
|
||||
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
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
@ -249,3 +251,166 @@ def test_list_contacts_public_projects(client):
|
|||
response_content = response.data
|
||||
assert len(response_content) == 1
|
||||
assert response_content[0]["id"] == user_2.id
|
||||
|
||||
|
||||
def test_get_favourites_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)
|
||||
project.add_watcher(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_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
|
||||
|
||||
|
||||
def test_get_favourites_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")
|
||||
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)
|
||||
|
||||
project_vote_info = get_favourites_list(fav_user, viewer_user)[0]
|
||||
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
|
||||
assert project_vote_info["subject"] == project.name
|
||||
assert project_vote_info["tags"] == project.tags
|
||||
assert project_vote_info["project"] == project.id
|
||||
assert project_vote_info["assigned_to"] == None
|
||||
assert project_vote_info["total_watchers"] == 1
|
||||
assert project_vote_info["created_date"] == vote.created_date
|
||||
assert project_vote_info["project_name"] == project.name
|
||||
assert project_vote_info["project_slug"] == project.slug
|
||||
assert project_vote_info["project_is_private"] == project.is_private
|
||||
assert project_vote_info["assigned_to_username"] == None
|
||||
assert project_vote_info["assigned_to_full_name"] == None
|
||||
assert project_vote_info["assigned_to_photo"] == None
|
||||
assert project_vote_info["assigned_to_email"] == None
|
||||
assert project_vote_info["total_votes"] == 1
|
||||
|
||||
|
||||
def test_get_favourites_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")
|
||||
|
||||
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(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)
|
||||
|
||||
instance_vote_info = get_favourites_list(fav_user, viewer_user, type=object_type)[0]
|
||||
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
|
||||
assert instance_vote_info["subject"] == instance.subject
|
||||
assert instance_vote_info["tags"] == instance.tags
|
||||
assert instance_vote_info["project"] == instance.project.id
|
||||
assert instance_vote_info["assigned_to"] == assigned_to_user.id
|
||||
assert instance_vote_info["total_watchers"] == 1
|
||||
assert instance_vote_info["created_date"] == vote.created_date
|
||||
assert instance_vote_info["project_name"] == instance.project.name
|
||||
assert instance_vote_info["project_slug"] == instance.project.slug
|
||||
assert instance_vote_info["project_is_private"] == instance.project.is_private
|
||||
assert instance_vote_info["assigned_to_username"] == assigned_to_user.username
|
||||
assert instance_vote_info["assigned_to_full_name"] == assigned_to_user.full_name
|
||||
assert instance_vote_info["assigned_to_photo"] == ''
|
||||
assert instance_vote_info["assigned_to_email"] == assigned_to_user.email
|
||||
assert instance_vote_info["total_votes"] == 3
|
||||
|
||||
|
||||
def test_get_favourites_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")
|
||||
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)
|
||||
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")
|
||||
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")
|
||||
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")
|
||||
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)
|
||||
|
||||
#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
|
||||
|
||||
#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
|
||||
|
||||
#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
|
||||
|
|
Loading…
Reference in New Issue