Merge remote-tracking branch 'upstream/master'
commit
77591b8ad6
|
@ -17,7 +17,6 @@ notifications:
|
|||
email:
|
||||
recipients:
|
||||
- jespinog@gmail.com
|
||||
- andrei.antoukh@gmail.com
|
||||
- bameda@dbarragan.com
|
||||
on_success: change
|
||||
on_failure: change
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
## 1.8.0 ??? (unreleased)
|
||||
|
||||
### Features
|
||||
- Improve timeline resource.
|
||||
- Add sitemap of taiga-front (the web client).
|
||||
- Search by reference (thanks to [@artlepool](https://github.com/artlepool))
|
||||
- Add call 'by_username' to the API resource User
|
||||
|
||||
|
|
|
@ -257,6 +257,7 @@ INSTALLED_APPS = [
|
|||
"django.contrib.messages",
|
||||
"django.contrib.admin",
|
||||
"django.contrib.staticfiles",
|
||||
"django.contrib.sitemaps",
|
||||
|
||||
"taiga.base",
|
||||
"taiga.base.api",
|
||||
|
@ -449,9 +450,16 @@ BITBUCKET_VALID_ORIGIN_IPS = ["131.103.20.165", "131.103.20.166"]
|
|||
GITLAB_VALID_ORIGIN_IPS = []
|
||||
|
||||
EXPORTS_TTL = 60 * 60 * 24 # 24 hours
|
||||
|
||||
CELERY_ENABLED = False
|
||||
WEBHOOKS_ENABLED = False
|
||||
|
||||
|
||||
# If is True /front/sitemap.xml show a valid sitemap of taiga-front client
|
||||
FRONT_SITEMAP_ENABLED = False
|
||||
FRONT_SITEMAP_CACHE_TIMEOUT = 24*60*60 # In second
|
||||
|
||||
|
||||
from .sr import *
|
||||
|
||||
|
||||
|
|
|
@ -62,3 +62,8 @@ DATABASES = {
|
|||
#GITHUB_API_URL = "https://api.github.com/"
|
||||
#GITHUB_API_CLIENT_ID = "yourgithubclientid"
|
||||
#GITHUB_API_CLIENT_SECRET = "yourgithubclientsecret"
|
||||
|
||||
# SITEMAP
|
||||
# If is True /front/sitemap.xml show a valid sitemap of taiga-front client
|
||||
#FRONT_SITEMAP_ENABLED = False
|
||||
#FRONT_SITEMAP_CACHE_TIMEOUT = 24*60*60 # In second
|
||||
|
|
|
@ -49,6 +49,9 @@ class I18NJsonField(JsonField):
|
|||
|
||||
def translate_values(self, d):
|
||||
i18n_d = {}
|
||||
if d is None:
|
||||
return d
|
||||
|
||||
for key, value in d.items():
|
||||
if isinstance(value, dict):
|
||||
i18n_d[key] = self.translate_values(value)
|
||||
|
|
|
@ -364,6 +364,26 @@ class TagsFilter(FilterBackend):
|
|||
return super().filter_queryset(request, queryset, view)
|
||||
|
||||
|
||||
class StatusFilter(FilterBackend):
|
||||
def __init__(self, filter_name='status'):
|
||||
self.filter_name = filter_name
|
||||
|
||||
def _get_status_queryparams(self, params):
|
||||
status = params.get(self.filter_name, None)
|
||||
if status is not None:
|
||||
status = set([x.strip() for x in status.split(",")])
|
||||
return list(status)
|
||||
|
||||
return None
|
||||
|
||||
def filter_queryset(self, request, queryset, view):
|
||||
query_status = self._get_status_queryparams(request.QUERY_PARAMS)
|
||||
if query_status:
|
||||
queryset = queryset.filter(status__in=query_status)
|
||||
|
||||
return super().filter_queryset(request, queryset, view)
|
||||
|
||||
|
||||
class QFilter(FilterBackend):
|
||||
def filter_queryset(self, request, queryset, view):
|
||||
q = request.QUERY_PARAMS.get('q', None)
|
||||
|
|
|
@ -121,7 +121,7 @@
|
|||
|
||||
.headerContent {
|
||||
text-align: center;
|
||||
color:#b8b8b8 !important;
|
||||
color:#8D8D8D !important;
|
||||
font-family: 'Open Sans', Arial, Helvetica;
|
||||
font-size:14px;
|
||||
margin-bottom:16px;
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
* @style heading 2
|
||||
*/
|
||||
h2{
|
||||
color: #b8b8b8 !important;
|
||||
color: #8D8D8D !important;
|
||||
display:block;
|
||||
font-family: 'Open Sans', Arial;
|
||||
font-size:20px;
|
||||
|
|
|
@ -121,7 +121,7 @@
|
|||
|
||||
.headerContent {
|
||||
text-align: center;
|
||||
color:#b8b8b8 !important;
|
||||
color:#8D8D8D !important;
|
||||
font-family: 'Open Sans', Arial, Helvetica;
|
||||
font-size:14px;
|
||||
margin-bottom:16px;
|
||||
|
@ -418,14 +418,14 @@
|
|||
</tr>
|
||||
{% for entry in history_entries%}
|
||||
{% if entry.comment %}
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
{% trans comment=mdrender(project, entry.comment) %}
|
||||
<h3>comment:</h3>
|
||||
<p>{{ comment }}</p>
|
||||
{% endtrans %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
{% trans comment=mdrender(project, entry.comment) %}
|
||||
<h3>comment:</h3>
|
||||
<p>{{ comment }}</p>
|
||||
{% endtrans %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% set changed_fields = entry.values_diff %}
|
||||
{% if changed_fields %}
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
# Copyright (C) 2014 Andrey Antukh <niwi@niwi.be>
|
||||
# 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/>.
|
||||
|
||||
from django_jinja import library
|
||||
from django_sites import get_by_id as get_site_by_id
|
||||
|
||||
|
||||
urls = {
|
||||
"home": "/",
|
||||
|
||||
"login": "/login",
|
||||
"change-password": "/change-password/{0}",
|
||||
"change-email": "/change-email/{0}",
|
||||
"cancel-account": "/cancel-account/{0}",
|
||||
"invitation": "/invitation/{0}",
|
||||
|
||||
"project": "/project/{0}",
|
||||
|
||||
"backlog": "/project/{0}/backlog/",
|
||||
"taskboard": "/project/{0}/taskboard/{1}",
|
||||
"kanban": "/project/{0}/kanban/",
|
||||
"userstory": "/project/{0}/us/{1}",
|
||||
"task": "/project/{0}/task/{1}",
|
||||
|
||||
"issues": "/project/{0}/issues",
|
||||
"issue": "/project/{0}/issue/{1}",
|
||||
|
||||
"wiki": "/project/{0}/wiki/{1}",
|
||||
|
||||
"project-admin": "/project/{0}/admin/project-profile/details",
|
||||
}
|
||||
|
||||
|
||||
@library.global_function(name="resolve_front_url")
|
||||
def resolve(type, *args):
|
||||
site = get_site_by_id("front")
|
||||
url_tmpl = "{scheme}//{domain}{url}"
|
||||
|
||||
scheme = site.scheme and "{0}:".format(site.scheme) or ""
|
||||
url = urls[type].format(*args)
|
||||
return url_tmpl.format(scheme=scheme, domain=site.domain, url=url)
|
|
@ -0,0 +1,60 @@
|
|||
# Copyright (C) 2015 David Barragán <bameda@dbarragan.com>
|
||||
# Copyright (C) 2015 Taiga Agile LLC <support@taiga.io>
|
||||
#
|
||||
# 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/>.
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from .generics import GenericSitemap
|
||||
|
||||
from .projects import ProjectsSitemap
|
||||
from .projects import ProjectBacklogsSitemap
|
||||
from .projects import ProjectKanbansSitemap
|
||||
from .projects import ProjectIssuesSitemap
|
||||
from .projects import ProjectTeamsSitemap
|
||||
|
||||
from .milestones import MilestonesSitemap
|
||||
|
||||
from .userstories import UserStoriesSitemap
|
||||
|
||||
from .tasks import TasksSitemap
|
||||
|
||||
from .issues import IssuesSitemap
|
||||
|
||||
from .wiki import WikiPagesSitemap
|
||||
|
||||
from .users import UsersSitemap
|
||||
|
||||
|
||||
sitemaps = OrderedDict([
|
||||
("generics", GenericSitemap),
|
||||
|
||||
("projects", ProjectsSitemap),
|
||||
("project-backlogs", ProjectBacklogsSitemap),
|
||||
("project-kanbans", ProjectKanbansSitemap),
|
||||
("project-issues-list", ProjectIssuesSitemap),
|
||||
("project-teams", ProjectTeamsSitemap),
|
||||
|
||||
("milestones", MilestonesSitemap),
|
||||
|
||||
("userstories", UserStoriesSitemap),
|
||||
|
||||
("tasks", TasksSitemap),
|
||||
|
||||
("issues", IssuesSitemap),
|
||||
|
||||
("wikipages", WikiPagesSitemap),
|
||||
|
||||
("users", UsersSitemap)
|
||||
])
|
|
@ -0,0 +1,45 @@
|
|||
# Copyright (C) 2015 David Barragán <bameda@dbarragan.com>
|
||||
# Copyright (C) 2015 Taiga Agile LLC <support@taiga.io>
|
||||
#
|
||||
# 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/>.
|
||||
|
||||
from django.contrib.sitemaps import Sitemap as DjangoSitemap
|
||||
|
||||
|
||||
class Sitemap(DjangoSitemap):
|
||||
def get_urls(self, page=1, site=None, protocol=None):
|
||||
urls = []
|
||||
latest_lastmod = None
|
||||
all_items_lastmod = True # track if all items have a lastmod
|
||||
for item in self.paginator.page(page).object_list:
|
||||
loc = self.__get('location', item)
|
||||
priority = self.__get('priority', item, None)
|
||||
lastmod = self.__get('lastmod', item, None)
|
||||
if all_items_lastmod:
|
||||
all_items_lastmod = lastmod is not None
|
||||
if (all_items_lastmod and
|
||||
(latest_lastmod is None or lastmod > latest_lastmod)):
|
||||
latest_lastmod = lastmod
|
||||
url_info = {
|
||||
'item': item,
|
||||
'location': loc,
|
||||
'lastmod': lastmod,
|
||||
'changefreq': self.__get('changefreq', item, None),
|
||||
'priority': str(priority if priority is not None else ''),
|
||||
}
|
||||
urls.append(url_info)
|
||||
if all_items_lastmod and latest_lastmod:
|
||||
self.latest_lastmod = latest_lastmod
|
||||
|
||||
return urls
|
|
@ -0,0 +1,42 @@
|
|||
# Copyright (C) 2015 David Barragán <bameda@dbarragan.com>
|
||||
# Copyright (C) 2015 Taiga Agile LLC <support@taiga.io>
|
||||
#
|
||||
# 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/>.
|
||||
|
||||
from django.db.models import Q
|
||||
from django.apps import apps
|
||||
|
||||
from taiga.front.templatetags.functions import resolve
|
||||
|
||||
from .base import Sitemap
|
||||
|
||||
|
||||
class GenericSitemap(Sitemap):
|
||||
def items(self):
|
||||
return [
|
||||
{"url_key": "home", "changefreq": "monthly", "priority": 0.6},
|
||||
{"url_key": "login", "changefreq": "monthly", "priority": 0.6},
|
||||
{"url_key": "register", "changefreq": "monthly", "priority": 0.6},
|
||||
{"url_key": "forgot-password", "changefreq": "monthly", "priority": 0.6}
|
||||
]
|
||||
|
||||
def location(self, obj):
|
||||
return resolve(obj["url_key"])
|
||||
|
||||
def changefreq(self, obj):
|
||||
return obj.get("changefreq", None)
|
||||
|
||||
def priority(self, obj):
|
||||
return obj.get("priority", None)
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
# Copyright (C) 2015 David Barragán <bameda@dbarragan.com>
|
||||
# Copyright (C) 2015 Taiga Agile LLC <support@taiga.io>
|
||||
#
|
||||
# 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/>.
|
||||
|
||||
from django.db.models import Q
|
||||
from django.apps import apps
|
||||
|
||||
from taiga.front.templatetags.functions import resolve
|
||||
|
||||
from .base import Sitemap
|
||||
|
||||
|
||||
class IssuesSitemap(Sitemap):
|
||||
def items(self):
|
||||
issue_model = apps.get_model("issues", "Issue")
|
||||
|
||||
# Get issues of public projects OR private projects if anon user can view them
|
||||
queryset = issue_model.objects.filter(Q(project__is_private=False) |
|
||||
Q(project__is_private=True,
|
||||
project__anon_permissions__contains=["view_issues"]))
|
||||
|
||||
# Project data is needed
|
||||
queryset = queryset.select_related("project")
|
||||
|
||||
return queryset
|
||||
|
||||
def location(self, obj):
|
||||
return resolve("issue", obj.project.slug, obj.ref)
|
||||
|
||||
def lastmod(self, obj):
|
||||
return obj.modified_date
|
||||
|
||||
def changefreq(self, obj):
|
||||
return "daily"
|
||||
|
||||
def priority(self, obj):
|
||||
return 0.6
|
|
@ -0,0 +1,51 @@
|
|||
# Copyright (C) 2015 David Barragán <bameda@dbarragan.com>
|
||||
# Copyright (C) 2015 Taiga Agile LLC <support@taiga.io>
|
||||
#
|
||||
# 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/>.
|
||||
|
||||
from django.db.models import Q
|
||||
from django.apps import apps
|
||||
|
||||
from taiga.front.templatetags.functions import resolve
|
||||
|
||||
from .base import Sitemap
|
||||
|
||||
|
||||
class MilestonesSitemap(Sitemap):
|
||||
def items(self):
|
||||
milestone_model = apps.get_model("milestones", "Milestone")
|
||||
|
||||
# Get US of public projects OR private projects if anon user can view them and us and tasks
|
||||
queryset = milestone_model.objects.filter(Q(project__is_private=False) |
|
||||
Q(project__is_private=True,
|
||||
project__anon_permissions__contains=["view_milestones",
|
||||
"view_us",
|
||||
"view_tasks"]))
|
||||
|
||||
# Project data is needed
|
||||
queryset = queryset.select_related("project")
|
||||
|
||||
return queryset
|
||||
|
||||
def location(self, obj):
|
||||
return resolve("taskboard", obj.project.slug, obj.slug)
|
||||
|
||||
def lastmod(self, obj):
|
||||
return obj.modified_date
|
||||
|
||||
def changefreq(self, obj):
|
||||
return "daily"
|
||||
|
||||
def priority(self, obj):
|
||||
return 0.6
|
|
@ -0,0 +1,154 @@
|
|||
# Copyright (C) 2015 David Barragán <bameda@dbarragan.com>
|
||||
# Copyright (C) 2015 Taiga Agile LLC <support@taiga.io>
|
||||
#
|
||||
# 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/>.
|
||||
|
||||
from django.db.models import Q
|
||||
from django.apps import apps
|
||||
|
||||
from taiga.front.templatetags.functions import resolve
|
||||
|
||||
from .base import Sitemap
|
||||
|
||||
|
||||
class ProjectsSitemap(Sitemap):
|
||||
def items(self):
|
||||
project_model = apps.get_model("projects", "Project")
|
||||
|
||||
# Get public projects OR private projects if anon user can view them
|
||||
queryset = project_model.objects.filter(Q(is_private=False) |
|
||||
Q(is_private=True,
|
||||
anon_permissions__contains=["view_project"]))
|
||||
|
||||
return queryset
|
||||
|
||||
def location(self, obj):
|
||||
return resolve("project", obj.slug)
|
||||
|
||||
def lastmod(self, obj):
|
||||
return obj.modified_date
|
||||
|
||||
def changefreq(self, obj):
|
||||
return "daily"
|
||||
|
||||
def priority(self, obj):
|
||||
return 0.6
|
||||
|
||||
|
||||
class ProjectBacklogsSitemap(Sitemap):
|
||||
def items(self):
|
||||
project_model = apps.get_model("projects", "Project")
|
||||
|
||||
# Get public projects OR private projects if anon user can view them and user stories
|
||||
queryset = project_model.objects.filter(Q(is_private=False) |
|
||||
Q(is_private=True,
|
||||
anon_permissions__contains=["view_project",
|
||||
"view_us"]))
|
||||
|
||||
# Exclude projects without backlog enabled
|
||||
queryset = queryset.exclude(is_backlog_activated=False)
|
||||
|
||||
return queryset
|
||||
|
||||
def location(self, obj):
|
||||
return resolve("backlog", obj.slug)
|
||||
|
||||
def lastmod(self, obj):
|
||||
return obj.modified_date
|
||||
|
||||
def changefreq(self, obj):
|
||||
return "daily"
|
||||
|
||||
def priority(self, obj):
|
||||
return 0.6
|
||||
|
||||
|
||||
class ProjectKanbansSitemap(Sitemap):
|
||||
def items(self):
|
||||
project_model = apps.get_model("projects", "Project")
|
||||
|
||||
# Get public projects OR private projects if anon user can view them and user stories
|
||||
queryset = project_model.objects.filter(Q(is_private=False) |
|
||||
Q(is_private=True,
|
||||
anon_permissions__contains=["view_project",
|
||||
"view_us"]))
|
||||
|
||||
# Exclude projects without kanban enabled
|
||||
queryset = queryset.exclude(is_kanban_activated=False)
|
||||
|
||||
return queryset
|
||||
|
||||
def location(self, obj):
|
||||
return resolve("kanban", obj.slug)
|
||||
|
||||
def lastmod(self, obj):
|
||||
return obj.modified_date
|
||||
|
||||
def changefreq(self, obj):
|
||||
return "daily"
|
||||
|
||||
def priority(self, obj):
|
||||
return 0.6
|
||||
|
||||
|
||||
class ProjectIssuesSitemap(Sitemap):
|
||||
def items(self):
|
||||
project_model = apps.get_model("projects", "Project")
|
||||
|
||||
# Get public projects OR private projects if anon user can view them and issues
|
||||
queryset = project_model.objects.filter(Q(is_private=False) |
|
||||
Q(is_private=True,
|
||||
anon_permissions__contains=["view_project",
|
||||
"view_issues"]))
|
||||
|
||||
# Exclude projects without issues enabled
|
||||
queryset = queryset.exclude(is_issues_activated=False)
|
||||
|
||||
return queryset
|
||||
|
||||
def location(self, obj):
|
||||
return resolve("issues", obj.slug)
|
||||
|
||||
def lastmod(self, obj):
|
||||
return obj.modified_date
|
||||
|
||||
def changefreq(self, obj):
|
||||
return "daily"
|
||||
|
||||
def priority(self, obj):
|
||||
return 0.6
|
||||
|
||||
|
||||
class ProjectTeamsSitemap(Sitemap):
|
||||
def items(self):
|
||||
project_model = apps.get_model("projects", "Project")
|
||||
|
||||
# Get public projects OR private projects if anon user can view them
|
||||
queryset = project_model.objects.filter(Q(is_private=False) |
|
||||
Q(is_private=True,
|
||||
anon_permissions__contains=["view_project"]))
|
||||
|
||||
return queryset
|
||||
|
||||
def location(self, obj):
|
||||
return resolve("team", obj.slug)
|
||||
|
||||
def lastmod(self, obj):
|
||||
return obj.modified_date
|
||||
|
||||
def changefreq(self, obj):
|
||||
return "daily"
|
||||
|
||||
def priority(self, obj):
|
||||
return 0.6
|
|
@ -0,0 +1,49 @@
|
|||
# Copyright (C) 2015 David Barragán <bameda@dbarragan.com>
|
||||
# Copyright (C) 2015 Taiga Agile LLC <support@taiga.io>
|
||||
#
|
||||
# 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/>.
|
||||
|
||||
from django.db.models import Q
|
||||
from django.apps import apps
|
||||
|
||||
from taiga.front.templatetags.functions import resolve
|
||||
|
||||
from .base import Sitemap
|
||||
|
||||
|
||||
class TasksSitemap(Sitemap):
|
||||
def items(self):
|
||||
task_model = apps.get_model("tasks", "Task")
|
||||
|
||||
# Get tasks of public projects OR private projects if anon user can view them
|
||||
queryset = task_model.objects.filter(Q(project__is_private=False) |
|
||||
Q(project__is_private=True,
|
||||
project__anon_permissions__contains=["view_tasks"]))
|
||||
|
||||
# Project data is needed
|
||||
queryset = queryset.select_related("project")
|
||||
|
||||
return queryset
|
||||
|
||||
def location(self, obj):
|
||||
return resolve("task", obj.project.slug, obj.ref)
|
||||
|
||||
def lastmod(self, obj):
|
||||
return obj.modified_date
|
||||
|
||||
def changefreq(self, obj):
|
||||
return "daily"
|
||||
|
||||
def priority(self, obj):
|
||||
return 0.4
|
|
@ -0,0 +1,44 @@
|
|||
# Copyright (C) 2015 David Barragán <bameda@dbarragan.com>
|
||||
# Copyright (C) 2015 Taiga Agile LLC <support@taiga.io>
|
||||
#
|
||||
# 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/>.
|
||||
|
||||
from django.apps import apps
|
||||
|
||||
from taiga.front.templatetags.functions import resolve
|
||||
|
||||
from .base import Sitemap
|
||||
|
||||
|
||||
class UsersSitemap(Sitemap):
|
||||
def items(self):
|
||||
user_model = apps.get_model("users", "User")
|
||||
|
||||
# Only active users and not system users
|
||||
queryset = user_model.objects.filter(is_active=True,
|
||||
is_system=False)
|
||||
|
||||
return queryset
|
||||
|
||||
def location(self, obj):
|
||||
return resolve("user", obj.username)
|
||||
|
||||
def lastmod(self, obj):
|
||||
return None
|
||||
|
||||
def changefreq(self, obj):
|
||||
return "daily"
|
||||
|
||||
def priority(self, obj):
|
||||
return 0.6
|
|
@ -0,0 +1,49 @@
|
|||
# Copyright (C) 2015 David Barragán <bameda@dbarragan.com>
|
||||
# Copyright (C) 2015 Taiga Agile LLC <support@taiga.io>
|
||||
#
|
||||
# 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/>.
|
||||
|
||||
from django.db.models import Q
|
||||
from django.apps import apps
|
||||
|
||||
from taiga.front.templatetags.functions import resolve
|
||||
|
||||
from .base import Sitemap
|
||||
|
||||
|
||||
class UserStoriesSitemap(Sitemap):
|
||||
def items(self):
|
||||
us_model = apps.get_model("userstories", "UserStory")
|
||||
|
||||
# Get US of public projects OR private projects if anon user can view them
|
||||
queryset = us_model.objects.filter(Q(project__is_private=False) |
|
||||
Q(project__is_private=True,
|
||||
project__anon_permissions__contains=["view_us"]))
|
||||
|
||||
# Project data is needed
|
||||
queryset = queryset.select_related("project")
|
||||
|
||||
return queryset
|
||||
|
||||
def location(self, obj):
|
||||
return resolve("userstory", obj.project.slug, obj.ref)
|
||||
|
||||
def lastmod(self, obj):
|
||||
return obj.modified_date
|
||||
|
||||
def changefreq(self, obj):
|
||||
return "daily"
|
||||
|
||||
def priority(self, obj):
|
||||
return 0.6
|
|
@ -0,0 +1,52 @@
|
|||
# Copyright (C) 2015 David Barragán <bameda@dbarragan.com>
|
||||
# Copyright (C) 2015 Taiga Agile LLC <support@taiga.io>
|
||||
#
|
||||
# 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/>.
|
||||
|
||||
from django.db.models import Q
|
||||
from django.apps import apps
|
||||
|
||||
from taiga.front.templatetags.functions import resolve
|
||||
|
||||
from .base import Sitemap
|
||||
|
||||
|
||||
class WikiPagesSitemap(Sitemap):
|
||||
def items(self):
|
||||
wiki_page_model = apps.get_model("wiki", "WikiPage")
|
||||
|
||||
# Get wiki pages of public projects OR private projects if anon user can view them
|
||||
queryset = wiki_page_model.objects.filter(Q(project__is_private=False) |
|
||||
Q(project__is_private=True,
|
||||
project__anon_permissions__contains=["view_wiki_pages"]))
|
||||
|
||||
# Exclude wiki pages from projects without wiki section enabled
|
||||
queryset = queryset.exclude(project__is_wiki_activated=False)
|
||||
|
||||
# Project data is needed
|
||||
queryset = queryset.select_related("project")
|
||||
|
||||
return queryset
|
||||
|
||||
def location(self, obj):
|
||||
return resolve("wiki", obj.project.slug, obj.slug)
|
||||
|
||||
def lastmod(self, obj):
|
||||
return obj.modified_date
|
||||
|
||||
def changefreq(self, obj):
|
||||
return "daily"
|
||||
|
||||
def priority(self, obj):
|
||||
return 0.6
|
|
@ -0,0 +1,34 @@
|
|||
# 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>
|
||||
# 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/>.
|
||||
|
||||
|
||||
from django_jinja import library
|
||||
from django_sites import get_by_id as get_site_by_id
|
||||
|
||||
from taiga.front.urls import urls
|
||||
|
||||
|
||||
register = library.Library()
|
||||
|
||||
|
||||
@register.global_function(name="resolve_front_url")
|
||||
def resolve(type, *args):
|
||||
site = get_site_by_id("front")
|
||||
url_tmpl = "{scheme}//{domain}{url}"
|
||||
|
||||
scheme = site.scheme and "{0}:".format(site.scheme) or ""
|
||||
url = urls[type].format(*args)
|
||||
return url_tmpl.format(scheme=scheme, domain=site.domain, url=url)
|
|
@ -0,0 +1,49 @@
|
|||
# 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>
|
||||
# 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/>.
|
||||
|
||||
|
||||
urls = {
|
||||
"home": "/",
|
||||
"login": "/login",
|
||||
"register": "/register",
|
||||
"forgot-password": "/forgot-password",
|
||||
|
||||
"change-password": "/change-password/{0}", # user.token
|
||||
"change-email": "/change-email/{0}", # user.email_token
|
||||
"cancel-account": "/cancel-account/{0}", # auth.token.get_token_for_user(user)
|
||||
"invitation": "/invitation/{0}", # membership.token
|
||||
|
||||
"user": "/profile/{0}", # user.username
|
||||
|
||||
"project": "/project/{0}", # project.slug
|
||||
|
||||
"backlog": "/project/{0}/backlog/", # project.slug
|
||||
"taskboard": "/project/{0}/taskboard/{1}", # project.slug, milestone.slug
|
||||
"kanban": "/project/{0}/kanban/", # project.slug
|
||||
|
||||
"userstory": "/project/{0}/us/{1}", # project.slug, us.ref
|
||||
"task": "/project/{0}/task/{1}", # project.slug, task.ref
|
||||
|
||||
"issues": "/project/{0}/issues", # project.slug
|
||||
"issue": "/project/{0}/issue/{1}", # project.slug, issue.ref
|
||||
|
||||
"wiki": "/project/{0}/wiki/{1}", # project.slug, wikipage.slug
|
||||
|
||||
"team": "/project/{0}/team/", # project.slug
|
||||
|
||||
"project-admin": "/project/{0}/admin/project-profile/details", # project.slug
|
||||
}
|
||||
|
|
@ -9,8 +9,8 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: taiga-back\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-05-25 17:31+0200\n"
|
||||
"PO-Revision-Date: 2015-05-25 13:58+0000\n"
|
||||
"POT-Creation-Date: 2015-06-09 09:47+0200\n"
|
||||
"PO-Revision-Date: 2015-06-09 07:47+0000\n"
|
||||
"Last-Translator: Taiga Dev Team <support@taiga.io>\n"
|
||||
"Language-Team: Catalan (http://www.transifex.com/projects/p/taiga-back/"
|
||||
"language/ca/)\n"
|
||||
|
@ -435,16 +435,12 @@ msgstr "Actualitzacions"
|
|||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" <h3>comment:"
|
||||
" <h3>comment:"
|
||||
"</h3>\n"
|
||||
" <p>"
|
||||
" <p>"
|
||||
"%(comment)s</p>\n"
|
||||
" "
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
"<h3>Comentari:</h3>\n"
|
||||
" <p>%(comment)s</p>\n"
|
||||
" "
|
||||
|
||||
#: taiga/base/templates/emails/updates-body-text.jinja:6
|
||||
#, python-format
|
||||
|
@ -1082,7 +1078,7 @@ msgstr "Amo"
|
|||
#: taiga/projects/models.py:507 taiga/projects/models.py:538
|
||||
#: taiga/projects/notifications/models.py:69 taiga/projects/tasks/models.py:41
|
||||
#: taiga/projects/userstories/models.py:62 taiga/projects/wiki/models.py:28
|
||||
#: taiga/projects/wiki/models.py:66 taiga/users/models.py:193
|
||||
#: taiga/projects/wiki/models.py:66 taiga/users/models.py:196
|
||||
msgid "project"
|
||||
msgstr "Projecte"
|
||||
|
||||
|
@ -1126,7 +1122,7 @@ msgstr "Descripció"
|
|||
#: taiga/projects/models.py:391 taiga/projects/models.py:418
|
||||
#: taiga/projects/models.py:453 taiga/projects/models.py:476
|
||||
#: taiga/projects/models.py:501 taiga/projects/models.py:534
|
||||
#: taiga/projects/wiki/models.py:71 taiga/users/models.py:188
|
||||
#: taiga/projects/wiki/models.py:71 taiga/users/models.py:191
|
||||
msgid "order"
|
||||
msgstr "Ordre"
|
||||
|
||||
|
@ -1148,7 +1144,7 @@ msgstr ""
|
|||
#: taiga/projects/models.py:414 taiga/projects/models.py:451
|
||||
#: taiga/projects/models.py:474 taiga/projects/models.py:497
|
||||
#: taiga/projects/models.py:532 taiga/projects/models.py:555
|
||||
#: taiga/users/models.py:180 taiga/webhooks/models.py:27
|
||||
#: taiga/users/models.py:183 taiga/webhooks/models.py:27
|
||||
msgid "name"
|
||||
msgstr "Nom"
|
||||
|
||||
|
@ -1371,7 +1367,7 @@ msgstr "referència externa"
|
|||
#: taiga/projects/milestones/models.py:37 taiga/projects/models.py:125
|
||||
#: taiga/projects/models.py:352 taiga/projects/models.py:416
|
||||
#: taiga/projects/models.py:499 taiga/projects/models.py:557
|
||||
#: taiga/projects/wiki/models.py:30 taiga/users/models.py:182
|
||||
#: taiga/projects/wiki/models.py:30 taiga/users/models.py:185
|
||||
msgid "slug"
|
||||
msgstr "slug"
|
||||
|
||||
|
@ -1421,7 +1417,7 @@ msgstr "email"
|
|||
msgid "create at"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/projects/models.py:63 taiga/users/models.py:126
|
||||
#: taiga/projects/models.py:63 taiga/users/models.py:128
|
||||
msgid "token"
|
||||
msgstr "token"
|
||||
|
||||
|
@ -2107,15 +2103,15 @@ msgstr ""
|
|||
msgid "The version must be an integer"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/projects/occ/mixins.py:56
|
||||
msgid "The version is not valid"
|
||||
#: taiga/projects/occ/mixins.py:58
|
||||
msgid "The version parameter is not valid"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/projects/occ/mixins.py:72
|
||||
#: taiga/projects/occ/mixins.py:74
|
||||
msgid "The version doesn't match with the current one"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/projects/occ/mixins.py:92
|
||||
#: taiga/projects/occ/mixins.py:93
|
||||
msgid "version"
|
||||
msgstr "Versió"
|
||||
|
||||
|
@ -2131,43 +2127,43 @@ msgstr "Aquest e-mail ja està en ús"
|
|||
msgid "Invalid role for the project"
|
||||
msgstr "Rol invàlid per al projecte"
|
||||
|
||||
#: taiga/projects/serializers.py:343
|
||||
#: taiga/projects/serializers.py:340
|
||||
msgid "Total milestones must be major or equal to zero"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/projects/serializers.py:400
|
||||
#: taiga/projects/serializers.py:402
|
||||
msgid "Default options"
|
||||
msgstr "Opcions per defecte"
|
||||
|
||||
#: taiga/projects/serializers.py:401
|
||||
#: taiga/projects/serializers.py:403
|
||||
msgid "User story's statuses"
|
||||
msgstr "Estatus d'històries d'usuari"
|
||||
|
||||
#: taiga/projects/serializers.py:402
|
||||
#: taiga/projects/serializers.py:404
|
||||
msgid "Points"
|
||||
msgstr "Punts"
|
||||
|
||||
#: taiga/projects/serializers.py:403
|
||||
#: taiga/projects/serializers.py:405
|
||||
msgid "Task's statuses"
|
||||
msgstr "Estatus de tasques"
|
||||
|
||||
#: taiga/projects/serializers.py:404
|
||||
#: taiga/projects/serializers.py:406
|
||||
msgid "Issue's statuses"
|
||||
msgstr "Estatus d'incidéncies"
|
||||
|
||||
#: taiga/projects/serializers.py:405
|
||||
#: taiga/projects/serializers.py:407
|
||||
msgid "Issue's types"
|
||||
msgstr "Tipus d'incidéncies"
|
||||
|
||||
#: taiga/projects/serializers.py:406
|
||||
#: taiga/projects/serializers.py:408
|
||||
msgid "Priorities"
|
||||
msgstr "Prioritats"
|
||||
|
||||
#: taiga/projects/serializers.py:407
|
||||
#: taiga/projects/serializers.py:409
|
||||
msgid "Severities"
|
||||
msgstr "Severitats"
|
||||
|
||||
#: taiga/projects/serializers.py:408
|
||||
#: taiga/projects/serializers.py:410
|
||||
msgid "Roles"
|
||||
msgstr "Rols"
|
||||
|
||||
|
@ -2653,57 +2649,57 @@ msgstr "Permissos"
|
|||
msgid "Important dates"
|
||||
msgstr "Dates importants"
|
||||
|
||||
#: taiga/users/api.py:112 taiga/users/api.py:119
|
||||
#: taiga/users/api.py:124 taiga/users/api.py:131
|
||||
msgid "Invalid username or email"
|
||||
msgstr "Nom d'usuari o email invàlid"
|
||||
|
||||
#: taiga/users/api.py:128
|
||||
#: taiga/users/api.py:140
|
||||
msgid "Mail sended successful!"
|
||||
msgstr "Correu enviat satisfactòriament"
|
||||
|
||||
#: taiga/users/api.py:140 taiga/users/api.py:145
|
||||
#: taiga/users/api.py:152 taiga/users/api.py:157
|
||||
msgid "Token is invalid"
|
||||
msgstr "Token invàlid"
|
||||
|
||||
#: taiga/users/api.py:166
|
||||
#: taiga/users/api.py:178
|
||||
msgid "Current password parameter needed"
|
||||
msgstr "Paràmetre de password actual requerit"
|
||||
|
||||
#: taiga/users/api.py:169
|
||||
#: taiga/users/api.py:181
|
||||
msgid "New password parameter needed"
|
||||
msgstr "Paràmetre de password requerit"
|
||||
|
||||
#: taiga/users/api.py:172
|
||||
#: taiga/users/api.py:184
|
||||
msgid "Invalid password length at least 6 charaters needed"
|
||||
msgstr "Password invàlid, al menys 6 caràcters requerits"
|
||||
|
||||
#: taiga/users/api.py:175
|
||||
#: taiga/users/api.py:187
|
||||
msgid "Invalid current password"
|
||||
msgstr "Password actual invàlid"
|
||||
|
||||
#: taiga/users/api.py:191
|
||||
#: taiga/users/api.py:203
|
||||
msgid "Incomplete arguments"
|
||||
msgstr "Arguments incomplets."
|
||||
|
||||
#: taiga/users/api.py:196
|
||||
#: taiga/users/api.py:208
|
||||
msgid "Invalid image format"
|
||||
msgstr "Format d'image invàlid"
|
||||
|
||||
#: taiga/users/api.py:249
|
||||
#: taiga/users/api.py:261
|
||||
msgid "Duplicated email"
|
||||
msgstr "Email duplicat"
|
||||
|
||||
#: taiga/users/api.py:251
|
||||
#: taiga/users/api.py:263
|
||||
msgid "Not valid email"
|
||||
msgstr "Email no vàlid"
|
||||
|
||||
#: taiga/users/api.py:271 taiga/users/api.py:277
|
||||
#: taiga/users/api.py:283 taiga/users/api.py:289
|
||||
msgid ""
|
||||
"Invalid, are you sure the token is correct and you didn't use it before?"
|
||||
msgstr ""
|
||||
"Invàlid. Estás segur que el token es correcte i que no l'has usat abans?"
|
||||
|
||||
#: taiga/users/api.py:304 taiga/users/api.py:312 taiga/users/api.py:315
|
||||
#: taiga/users/api.py:316 taiga/users/api.py:324 taiga/users/api.py:327
|
||||
msgid "Invalid, are you sure the token is correct?"
|
||||
msgstr "Invàlid. Estás segur que el token es correcte?"
|
||||
|
||||
|
@ -2761,22 +2757,26 @@ msgid "default language"
|
|||
msgstr "llenguatge per defecte"
|
||||
|
||||
#: taiga/users/models.py:122
|
||||
msgid "default theme"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/users/models.py:124
|
||||
msgid "default timezone"
|
||||
msgstr "zona horaria per defecte"
|
||||
|
||||
#: taiga/users/models.py:124
|
||||
#: taiga/users/models.py:126
|
||||
msgid "colorize tags"
|
||||
msgstr "coloritza tags"
|
||||
|
||||
#: taiga/users/models.py:129
|
||||
#: taiga/users/models.py:131
|
||||
msgid "email token"
|
||||
msgstr "token de correu"
|
||||
|
||||
#: taiga/users/models.py:131
|
||||
#: taiga/users/models.py:133
|
||||
msgid "new email address"
|
||||
msgstr "nova adreça de correu"
|
||||
|
||||
#: taiga/users/models.py:185
|
||||
#: taiga/users/models.py:188
|
||||
msgid "permissions"
|
||||
msgstr "permissos"
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: taiga-back\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-05-25 17:31+0200\n"
|
||||
"POT-Creation-Date: 2015-06-09 09:47+0200\n"
|
||||
"PO-Revision-Date: 2015-03-25 20:09+0100\n"
|
||||
"Last-Translator: Taiga Dev Team <support@taiga.io>\n"
|
||||
"Language-Team: Taiga Dev Team <support@taiga.io>\n"
|
||||
|
@ -427,11 +427,11 @@ msgstr ""
|
|||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" <h3>comment:"
|
||||
" <h3>comment:"
|
||||
"</h3>\n"
|
||||
" <p>"
|
||||
" <p>"
|
||||
"%(comment)s</p>\n"
|
||||
" "
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: taiga/base/templates/emails/updates-body-text.jinja:6
|
||||
|
@ -1051,7 +1051,7 @@ msgstr ""
|
|||
#: taiga/projects/models.py:507 taiga/projects/models.py:538
|
||||
#: taiga/projects/notifications/models.py:69 taiga/projects/tasks/models.py:41
|
||||
#: taiga/projects/userstories/models.py:62 taiga/projects/wiki/models.py:28
|
||||
#: taiga/projects/wiki/models.py:66 taiga/users/models.py:193
|
||||
#: taiga/projects/wiki/models.py:66 taiga/users/models.py:196
|
||||
msgid "project"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1095,7 +1095,7 @@ msgstr ""
|
|||
#: taiga/projects/models.py:391 taiga/projects/models.py:418
|
||||
#: taiga/projects/models.py:453 taiga/projects/models.py:476
|
||||
#: taiga/projects/models.py:501 taiga/projects/models.py:534
|
||||
#: taiga/projects/wiki/models.py:71 taiga/users/models.py:188
|
||||
#: taiga/projects/wiki/models.py:71 taiga/users/models.py:191
|
||||
msgid "order"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1117,7 +1117,7 @@ msgstr ""
|
|||
#: taiga/projects/models.py:414 taiga/projects/models.py:451
|
||||
#: taiga/projects/models.py:474 taiga/projects/models.py:497
|
||||
#: taiga/projects/models.py:532 taiga/projects/models.py:555
|
||||
#: taiga/users/models.py:180 taiga/webhooks/models.py:27
|
||||
#: taiga/users/models.py:183 taiga/webhooks/models.py:27
|
||||
msgid "name"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1340,7 +1340,7 @@ msgstr ""
|
|||
#: taiga/projects/milestones/models.py:37 taiga/projects/models.py:125
|
||||
#: taiga/projects/models.py:352 taiga/projects/models.py:416
|
||||
#: taiga/projects/models.py:499 taiga/projects/models.py:557
|
||||
#: taiga/projects/wiki/models.py:30 taiga/users/models.py:182
|
||||
#: taiga/projects/wiki/models.py:30 taiga/users/models.py:185
|
||||
msgid "slug"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1390,7 +1390,7 @@ msgstr ""
|
|||
msgid "create at"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/projects/models.py:63 taiga/users/models.py:126
|
||||
#: taiga/projects/models.py:63 taiga/users/models.py:128
|
||||
msgid "token"
|
||||
msgstr ""
|
||||
|
||||
|
@ -2070,15 +2070,15 @@ msgstr ""
|
|||
msgid "The version must be an integer"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/projects/occ/mixins.py:56
|
||||
msgid "The version is not valid"
|
||||
#: taiga/projects/occ/mixins.py:58
|
||||
msgid "The version parameter is not valid"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/projects/occ/mixins.py:72
|
||||
#: taiga/projects/occ/mixins.py:74
|
||||
msgid "The version doesn't match with the current one"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/projects/occ/mixins.py:92
|
||||
#: taiga/projects/occ/mixins.py:93
|
||||
msgid "version"
|
||||
msgstr ""
|
||||
|
||||
|
@ -2094,43 +2094,43 @@ msgstr ""
|
|||
msgid "Invalid role for the project"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/projects/serializers.py:343
|
||||
#: taiga/projects/serializers.py:340
|
||||
msgid "Total milestones must be major or equal to zero"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/projects/serializers.py:400
|
||||
#: taiga/projects/serializers.py:402
|
||||
msgid "Default options"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/projects/serializers.py:401
|
||||
#: taiga/projects/serializers.py:403
|
||||
msgid "User story's statuses"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/projects/serializers.py:402
|
||||
#: taiga/projects/serializers.py:404
|
||||
msgid "Points"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/projects/serializers.py:403
|
||||
#: taiga/projects/serializers.py:405
|
||||
msgid "Task's statuses"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/projects/serializers.py:404
|
||||
#: taiga/projects/serializers.py:406
|
||||
msgid "Issue's statuses"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/projects/serializers.py:405
|
||||
#: taiga/projects/serializers.py:407
|
||||
msgid "Issue's types"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/projects/serializers.py:406
|
||||
#: taiga/projects/serializers.py:408
|
||||
msgid "Priorities"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/projects/serializers.py:407
|
||||
#: taiga/projects/serializers.py:409
|
||||
msgid "Severities"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/projects/serializers.py:408
|
||||
#: taiga/projects/serializers.py:410
|
||||
msgid "Roles"
|
||||
msgstr ""
|
||||
|
||||
|
@ -2596,56 +2596,56 @@ msgstr ""
|
|||
msgid "Important dates"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/users/api.py:112 taiga/users/api.py:119
|
||||
#: taiga/users/api.py:124 taiga/users/api.py:131
|
||||
msgid "Invalid username or email"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/users/api.py:128
|
||||
#: taiga/users/api.py:140
|
||||
msgid "Mail sended successful!"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/users/api.py:140 taiga/users/api.py:145
|
||||
#: taiga/users/api.py:152 taiga/users/api.py:157
|
||||
msgid "Token is invalid"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/users/api.py:166
|
||||
#: taiga/users/api.py:178
|
||||
msgid "Current password parameter needed"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/users/api.py:169
|
||||
#: taiga/users/api.py:181
|
||||
msgid "New password parameter needed"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/users/api.py:172
|
||||
#: taiga/users/api.py:184
|
||||
msgid "Invalid password length at least 6 charaters needed"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/users/api.py:175
|
||||
#: taiga/users/api.py:187
|
||||
msgid "Invalid current password"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/users/api.py:191
|
||||
#: taiga/users/api.py:203
|
||||
msgid "Incomplete arguments"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/users/api.py:196
|
||||
#: taiga/users/api.py:208
|
||||
msgid "Invalid image format"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/users/api.py:249
|
||||
#: taiga/users/api.py:261
|
||||
msgid "Duplicated email"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/users/api.py:251
|
||||
#: taiga/users/api.py:263
|
||||
msgid "Not valid email"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/users/api.py:271 taiga/users/api.py:277
|
||||
#: taiga/users/api.py:283 taiga/users/api.py:289
|
||||
msgid ""
|
||||
"Invalid, are you sure the token is correct and you didn't use it before?"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/users/api.py:304 taiga/users/api.py:312 taiga/users/api.py:315
|
||||
#: taiga/users/api.py:316 taiga/users/api.py:324 taiga/users/api.py:327
|
||||
msgid "Invalid, are you sure the token is correct?"
|
||||
msgstr ""
|
||||
|
||||
|
@ -2699,22 +2699,26 @@ msgid "default language"
|
|||
msgstr ""
|
||||
|
||||
#: taiga/users/models.py:122
|
||||
msgid "default timezone"
|
||||
msgid "default theme"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/users/models.py:124
|
||||
msgid "default timezone"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/users/models.py:126
|
||||
msgid "colorize tags"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/users/models.py:129
|
||||
#: taiga/users/models.py:131
|
||||
msgid "email token"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/users/models.py:131
|
||||
#: taiga/users/models.py:133
|
||||
msgid "new email address"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/users/models.py:185
|
||||
#: taiga/users/models.py:188
|
||||
msgid "permissions"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -12,9 +12,9 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: taiga-back\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-05-25 17:31+0200\n"
|
||||
"PO-Revision-Date: 2015-05-25 15:50+0000\n"
|
||||
"Last-Translator: David Barragán <bameda@gmail.com>\n"
|
||||
"POT-Creation-Date: 2015-06-09 09:47+0200\n"
|
||||
"PO-Revision-Date: 2015-06-09 07:47+0000\n"
|
||||
"Last-Translator: Taiga Dev Team <support@taiga.io>\n"
|
||||
"Language-Team: Spanish (http://www.transifex.com/projects/p/taiga-back/"
|
||||
"language/es/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
|
@ -471,15 +471,12 @@ msgstr "Actualizaciones"
|
|||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" <h3>comment:"
|
||||
" <h3>comment:"
|
||||
"</h3>\n"
|
||||
" <p>"
|
||||
" <p>"
|
||||
"%(comment)s</p>\n"
|
||||
" "
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
"<h3>comentario:</h3>\n"
|
||||
"<p>%(comment)s</p>"
|
||||
|
||||
#: taiga/base/templates/emails/updates-body-text.jinja:6
|
||||
#, python-format
|
||||
|
@ -1220,7 +1217,7 @@ msgstr "Dueño"
|
|||
#: taiga/projects/models.py:507 taiga/projects/models.py:538
|
||||
#: taiga/projects/notifications/models.py:69 taiga/projects/tasks/models.py:41
|
||||
#: taiga/projects/userstories/models.py:62 taiga/projects/wiki/models.py:28
|
||||
#: taiga/projects/wiki/models.py:66 taiga/users/models.py:193
|
||||
#: taiga/projects/wiki/models.py:66 taiga/users/models.py:196
|
||||
msgid "project"
|
||||
msgstr "Proyecto"
|
||||
|
||||
|
@ -1264,7 +1261,7 @@ msgstr "descripción"
|
|||
#: taiga/projects/models.py:391 taiga/projects/models.py:418
|
||||
#: taiga/projects/models.py:453 taiga/projects/models.py:476
|
||||
#: taiga/projects/models.py:501 taiga/projects/models.py:534
|
||||
#: taiga/projects/wiki/models.py:71 taiga/users/models.py:188
|
||||
#: taiga/projects/wiki/models.py:71 taiga/users/models.py:191
|
||||
msgid "order"
|
||||
msgstr "orden"
|
||||
|
||||
|
@ -1286,7 +1283,7 @@ msgstr "Talky"
|
|||
#: taiga/projects/models.py:414 taiga/projects/models.py:451
|
||||
#: taiga/projects/models.py:474 taiga/projects/models.py:497
|
||||
#: taiga/projects/models.py:532 taiga/projects/models.py:555
|
||||
#: taiga/users/models.py:180 taiga/webhooks/models.py:27
|
||||
#: taiga/users/models.py:183 taiga/webhooks/models.py:27
|
||||
msgid "name"
|
||||
msgstr "nombre"
|
||||
|
||||
|
@ -1509,7 +1506,7 @@ msgstr "referencia externa"
|
|||
#: taiga/projects/milestones/models.py:37 taiga/projects/models.py:125
|
||||
#: taiga/projects/models.py:352 taiga/projects/models.py:416
|
||||
#: taiga/projects/models.py:499 taiga/projects/models.py:557
|
||||
#: taiga/projects/wiki/models.py:30 taiga/users/models.py:182
|
||||
#: taiga/projects/wiki/models.py:30 taiga/users/models.py:185
|
||||
msgid "slug"
|
||||
msgstr "slug"
|
||||
|
||||
|
@ -1561,7 +1558,7 @@ msgstr "email"
|
|||
msgid "create at"
|
||||
msgstr "creado el"
|
||||
|
||||
#: taiga/projects/models.py:63 taiga/users/models.py:126
|
||||
#: taiga/projects/models.py:63 taiga/users/models.py:128
|
||||
msgid "token"
|
||||
msgstr "token"
|
||||
|
||||
|
@ -2478,15 +2475,15 @@ msgstr "Los observadores tienen usuarios invalidos"
|
|||
msgid "The version must be an integer"
|
||||
msgstr "La versión debe ser un número entero"
|
||||
|
||||
#: taiga/projects/occ/mixins.py:56
|
||||
msgid "The version is not valid"
|
||||
msgstr "La versión no es válida"
|
||||
#: taiga/projects/occ/mixins.py:58
|
||||
msgid "The version parameter is not valid"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/projects/occ/mixins.py:72
|
||||
#: taiga/projects/occ/mixins.py:74
|
||||
msgid "The version doesn't match with the current one"
|
||||
msgstr "Las version difiere de la actual"
|
||||
|
||||
#: taiga/projects/occ/mixins.py:92
|
||||
#: taiga/projects/occ/mixins.py:93
|
||||
msgid "version"
|
||||
msgstr "versión"
|
||||
|
||||
|
@ -2503,43 +2500,43 @@ msgstr "La dirección de email ya está en uso."
|
|||
msgid "Invalid role for the project"
|
||||
msgstr "Rol inválido para el proyecto"
|
||||
|
||||
#: taiga/projects/serializers.py:343
|
||||
#: taiga/projects/serializers.py:340
|
||||
msgid "Total milestones must be major or equal to zero"
|
||||
msgstr "El número total de sprints debe ser mayor o igual a cero"
|
||||
|
||||
#: taiga/projects/serializers.py:400
|
||||
#: taiga/projects/serializers.py:402
|
||||
msgid "Default options"
|
||||
msgstr "Opciones por defecto"
|
||||
|
||||
#: taiga/projects/serializers.py:401
|
||||
#: taiga/projects/serializers.py:403
|
||||
msgid "User story's statuses"
|
||||
msgstr "Estados de historia de usuario"
|
||||
|
||||
#: taiga/projects/serializers.py:402
|
||||
#: taiga/projects/serializers.py:404
|
||||
msgid "Points"
|
||||
msgstr "Puntos"
|
||||
|
||||
#: taiga/projects/serializers.py:403
|
||||
#: taiga/projects/serializers.py:405
|
||||
msgid "Task's statuses"
|
||||
msgstr "Estado de tareas"
|
||||
|
||||
#: taiga/projects/serializers.py:404
|
||||
#: taiga/projects/serializers.py:406
|
||||
msgid "Issue's statuses"
|
||||
msgstr "Estados de peticion"
|
||||
|
||||
#: taiga/projects/serializers.py:405
|
||||
#: taiga/projects/serializers.py:407
|
||||
msgid "Issue's types"
|
||||
msgstr "Tipos de petición"
|
||||
|
||||
#: taiga/projects/serializers.py:406
|
||||
#: taiga/projects/serializers.py:408
|
||||
msgid "Priorities"
|
||||
msgstr "Prioridades"
|
||||
|
||||
#: taiga/projects/serializers.py:407
|
||||
#: taiga/projects/serializers.py:409
|
||||
msgid "Severities"
|
||||
msgstr "Gravedades"
|
||||
|
||||
#: taiga/projects/serializers.py:408
|
||||
#: taiga/projects/serializers.py:410
|
||||
msgid "Roles"
|
||||
msgstr "Roles"
|
||||
|
||||
|
@ -3059,57 +3056,57 @@ msgstr "Permisos"
|
|||
msgid "Important dates"
|
||||
msgstr "datos importántes"
|
||||
|
||||
#: taiga/users/api.py:112 taiga/users/api.py:119
|
||||
#: taiga/users/api.py:124 taiga/users/api.py:131
|
||||
msgid "Invalid username or email"
|
||||
msgstr "Nombre de usuario o email no válidos"
|
||||
|
||||
#: taiga/users/api.py:128
|
||||
#: taiga/users/api.py:140
|
||||
msgid "Mail sended successful!"
|
||||
msgstr "¡Correo enviado con éxito!"
|
||||
|
||||
#: taiga/users/api.py:140 taiga/users/api.py:145
|
||||
#: taiga/users/api.py:152 taiga/users/api.py:157
|
||||
msgid "Token is invalid"
|
||||
msgstr "token inválido"
|
||||
|
||||
#: taiga/users/api.py:166
|
||||
#: taiga/users/api.py:178
|
||||
msgid "Current password parameter needed"
|
||||
msgstr "La contraseña actual es obligatoria."
|
||||
|
||||
#: taiga/users/api.py:169
|
||||
#: taiga/users/api.py:181
|
||||
msgid "New password parameter needed"
|
||||
msgstr "La nueva contraseña es obligatoria"
|
||||
|
||||
#: taiga/users/api.py:172
|
||||
#: taiga/users/api.py:184
|
||||
msgid "Invalid password length at least 6 charaters needed"
|
||||
msgstr "La longitud de la contraseña debe de ser de al menos 6 caracteres"
|
||||
|
||||
#: taiga/users/api.py:175
|
||||
#: taiga/users/api.py:187
|
||||
msgid "Invalid current password"
|
||||
msgstr "Contraseña actual inválida"
|
||||
|
||||
#: taiga/users/api.py:191
|
||||
#: taiga/users/api.py:203
|
||||
msgid "Incomplete arguments"
|
||||
msgstr "Argumentos incompletos"
|
||||
|
||||
#: taiga/users/api.py:196
|
||||
#: taiga/users/api.py:208
|
||||
msgid "Invalid image format"
|
||||
msgstr "Formato de imagen no válido"
|
||||
|
||||
#: taiga/users/api.py:249
|
||||
#: taiga/users/api.py:261
|
||||
msgid "Duplicated email"
|
||||
msgstr "Email duplicado"
|
||||
|
||||
#: taiga/users/api.py:251
|
||||
#: taiga/users/api.py:263
|
||||
msgid "Not valid email"
|
||||
msgstr "Email no válido"
|
||||
|
||||
#: taiga/users/api.py:271 taiga/users/api.py:277
|
||||
#: taiga/users/api.py:283 taiga/users/api.py:289
|
||||
msgid ""
|
||||
"Invalid, are you sure the token is correct and you didn't use it before?"
|
||||
msgstr ""
|
||||
"Invalido, ¿estás seguro de que el token es correcto y no se ha usado antes?"
|
||||
|
||||
#: taiga/users/api.py:304 taiga/users/api.py:312 taiga/users/api.py:315
|
||||
#: taiga/users/api.py:316 taiga/users/api.py:324 taiga/users/api.py:327
|
||||
msgid "Invalid, are you sure the token is correct?"
|
||||
msgstr "Inválido, ¿estás seguro de que el token es correcto?"
|
||||
|
||||
|
@ -3167,22 +3164,26 @@ msgid "default language"
|
|||
msgstr "idioma por defecto"
|
||||
|
||||
#: taiga/users/models.py:122
|
||||
msgid "default theme"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/users/models.py:124
|
||||
msgid "default timezone"
|
||||
msgstr "zona horaria por defecto"
|
||||
|
||||
#: taiga/users/models.py:124
|
||||
#: taiga/users/models.py:126
|
||||
msgid "colorize tags"
|
||||
msgstr "añade color a las etiquetas"
|
||||
|
||||
#: taiga/users/models.py:129
|
||||
#: taiga/users/models.py:131
|
||||
msgid "email token"
|
||||
msgstr "token de email"
|
||||
|
||||
#: taiga/users/models.py:131
|
||||
#: taiga/users/models.py:133
|
||||
msgid "new email address"
|
||||
msgstr "nueva dirección de email"
|
||||
|
||||
#: taiga/users/models.py:185
|
||||
#: taiga/users/models.py:188
|
||||
msgid "permissions"
|
||||
msgstr "permisos"
|
||||
|
||||
|
|
|
@ -9,9 +9,9 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: taiga-back\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-05-25 17:31+0200\n"
|
||||
"PO-Revision-Date: 2015-05-25 15:44+0000\n"
|
||||
"Last-Translator: David Barragán <bameda@gmail.com>\n"
|
||||
"POT-Creation-Date: 2015-06-09 09:47+0200\n"
|
||||
"PO-Revision-Date: 2015-06-09 07:47+0000\n"
|
||||
"Last-Translator: Taiga Dev Team <support@taiga.io>\n"
|
||||
"Language-Team: Finnish (http://www.transifex.com/projects/p/taiga-back/"
|
||||
"language/fi/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
|
@ -461,15 +461,12 @@ msgstr "Päivityksiä"
|
|||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" <h3>comment:"
|
||||
" <h3>comment:"
|
||||
"</h3>\n"
|
||||
" <p>"
|
||||
" <p>"
|
||||
"%(comment)s</p>\n"
|
||||
" "
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
"<h3>kommentti:</h3>\n"
|
||||
"<p>%(comment)s</p>"
|
||||
|
||||
#: taiga/base/templates/emails/updates-body-text.jinja:6
|
||||
#, python-format
|
||||
|
@ -1210,7 +1207,7 @@ msgstr "omistaja"
|
|||
#: taiga/projects/models.py:507 taiga/projects/models.py:538
|
||||
#: taiga/projects/notifications/models.py:69 taiga/projects/tasks/models.py:41
|
||||
#: taiga/projects/userstories/models.py:62 taiga/projects/wiki/models.py:28
|
||||
#: taiga/projects/wiki/models.py:66 taiga/users/models.py:193
|
||||
#: taiga/projects/wiki/models.py:66 taiga/users/models.py:196
|
||||
msgid "project"
|
||||
msgstr "projekti"
|
||||
|
||||
|
@ -1254,7 +1251,7 @@ msgstr "kuvaus"
|
|||
#: taiga/projects/models.py:391 taiga/projects/models.py:418
|
||||
#: taiga/projects/models.py:453 taiga/projects/models.py:476
|
||||
#: taiga/projects/models.py:501 taiga/projects/models.py:534
|
||||
#: taiga/projects/wiki/models.py:71 taiga/users/models.py:188
|
||||
#: taiga/projects/wiki/models.py:71 taiga/users/models.py:191
|
||||
msgid "order"
|
||||
msgstr "order"
|
||||
|
||||
|
@ -1276,7 +1273,7 @@ msgstr "Talky"
|
|||
#: taiga/projects/models.py:414 taiga/projects/models.py:451
|
||||
#: taiga/projects/models.py:474 taiga/projects/models.py:497
|
||||
#: taiga/projects/models.py:532 taiga/projects/models.py:555
|
||||
#: taiga/users/models.py:180 taiga/webhooks/models.py:27
|
||||
#: taiga/users/models.py:183 taiga/webhooks/models.py:27
|
||||
msgid "name"
|
||||
msgstr "nimi"
|
||||
|
||||
|
@ -1499,7 +1496,7 @@ msgstr "ulkoinen viittaus"
|
|||
#: taiga/projects/milestones/models.py:37 taiga/projects/models.py:125
|
||||
#: taiga/projects/models.py:352 taiga/projects/models.py:416
|
||||
#: taiga/projects/models.py:499 taiga/projects/models.py:557
|
||||
#: taiga/projects/wiki/models.py:30 taiga/users/models.py:182
|
||||
#: taiga/projects/wiki/models.py:30 taiga/users/models.py:185
|
||||
msgid "slug"
|
||||
msgstr "hukka-aika"
|
||||
|
||||
|
@ -1549,7 +1546,7 @@ msgstr "sähköposti"
|
|||
msgid "create at"
|
||||
msgstr "luo täällä"
|
||||
|
||||
#: taiga/projects/models.py:63 taiga/users/models.py:126
|
||||
#: taiga/projects/models.py:63 taiga/users/models.py:128
|
||||
msgid "token"
|
||||
msgstr "tunniste"
|
||||
|
||||
|
@ -2475,15 +2472,15 @@ msgstr "Vahdit sisältävät virheellisiä käyttäjiä"
|
|||
msgid "The version must be an integer"
|
||||
msgstr "Versio pitää olla kokonaisluku"
|
||||
|
||||
#: taiga/projects/occ/mixins.py:56
|
||||
msgid "The version is not valid"
|
||||
msgstr "Versio on virheellinen"
|
||||
#: taiga/projects/occ/mixins.py:58
|
||||
msgid "The version parameter is not valid"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/projects/occ/mixins.py:72
|
||||
#: taiga/projects/occ/mixins.py:74
|
||||
msgid "The version doesn't match with the current one"
|
||||
msgstr "Versio ei ole sama kuin nykyinen"
|
||||
|
||||
#: taiga/projects/occ/mixins.py:92
|
||||
#: taiga/projects/occ/mixins.py:93
|
||||
msgid "version"
|
||||
msgstr "versio"
|
||||
|
||||
|
@ -2499,43 +2496,43 @@ msgstr "Sähköpostiosoite on jo käytössä"
|
|||
msgid "Invalid role for the project"
|
||||
msgstr "Virheellinen rooli projektille"
|
||||
|
||||
#: taiga/projects/serializers.py:343
|
||||
#: taiga/projects/serializers.py:340
|
||||
msgid "Total milestones must be major or equal to zero"
|
||||
msgstr "Virstapylväitä yhteensä pitää olla vähintään 0."
|
||||
|
||||
#: taiga/projects/serializers.py:400
|
||||
#: taiga/projects/serializers.py:402
|
||||
msgid "Default options"
|
||||
msgstr "Oletusoptiot"
|
||||
|
||||
#: taiga/projects/serializers.py:401
|
||||
#: taiga/projects/serializers.py:403
|
||||
msgid "User story's statuses"
|
||||
msgstr "Käyttäjätarinatilat"
|
||||
|
||||
#: taiga/projects/serializers.py:402
|
||||
#: taiga/projects/serializers.py:404
|
||||
msgid "Points"
|
||||
msgstr "Pisteet"
|
||||
|
||||
#: taiga/projects/serializers.py:403
|
||||
#: taiga/projects/serializers.py:405
|
||||
msgid "Task's statuses"
|
||||
msgstr "Tehtävien tilat"
|
||||
|
||||
#: taiga/projects/serializers.py:404
|
||||
#: taiga/projects/serializers.py:406
|
||||
msgid "Issue's statuses"
|
||||
msgstr "Pyyntöjen tilat"
|
||||
|
||||
#: taiga/projects/serializers.py:405
|
||||
#: taiga/projects/serializers.py:407
|
||||
msgid "Issue's types"
|
||||
msgstr "pyyntötyypit"
|
||||
|
||||
#: taiga/projects/serializers.py:406
|
||||
#: taiga/projects/serializers.py:408
|
||||
msgid "Priorities"
|
||||
msgstr "Kiireellisyydet"
|
||||
|
||||
#: taiga/projects/serializers.py:407
|
||||
#: taiga/projects/serializers.py:409
|
||||
msgid "Severities"
|
||||
msgstr "Vakavuudet"
|
||||
|
||||
#: taiga/projects/serializers.py:408
|
||||
#: taiga/projects/serializers.py:410
|
||||
msgid "Roles"
|
||||
msgstr "Roolit"
|
||||
|
||||
|
@ -3052,58 +3049,58 @@ msgstr "Oikeudet"
|
|||
msgid "Important dates"
|
||||
msgstr "Tärkeät päivämäärät"
|
||||
|
||||
#: taiga/users/api.py:112 taiga/users/api.py:119
|
||||
#: taiga/users/api.py:124 taiga/users/api.py:131
|
||||
msgid "Invalid username or email"
|
||||
msgstr "Tuntematon käyttäjänimi tai sähköposti"
|
||||
|
||||
#: taiga/users/api.py:128
|
||||
#: taiga/users/api.py:140
|
||||
msgid "Mail sended successful!"
|
||||
msgstr "Sähköposti lähetetty."
|
||||
|
||||
#: taiga/users/api.py:140 taiga/users/api.py:145
|
||||
#: taiga/users/api.py:152 taiga/users/api.py:157
|
||||
msgid "Token is invalid"
|
||||
msgstr "Tunniste on virheellinen"
|
||||
|
||||
#: taiga/users/api.py:166
|
||||
#: taiga/users/api.py:178
|
||||
msgid "Current password parameter needed"
|
||||
msgstr "Nykyinen salasanaparametri tarvitaan"
|
||||
|
||||
#: taiga/users/api.py:169
|
||||
#: taiga/users/api.py:181
|
||||
msgid "New password parameter needed"
|
||||
msgstr "Uusi salasanaparametri tarvitaan"
|
||||
|
||||
#: taiga/users/api.py:172
|
||||
#: taiga/users/api.py:184
|
||||
msgid "Invalid password length at least 6 charaters needed"
|
||||
msgstr "Salasanan pitää olla vähintään 6 merkkiä pitkä"
|
||||
|
||||
#: taiga/users/api.py:175
|
||||
#: taiga/users/api.py:187
|
||||
msgid "Invalid current password"
|
||||
msgstr "Virheellinen nykyinen salasana"
|
||||
|
||||
#: taiga/users/api.py:191
|
||||
#: taiga/users/api.py:203
|
||||
msgid "Incomplete arguments"
|
||||
msgstr "Puutteelliset argumentit"
|
||||
|
||||
#: taiga/users/api.py:196
|
||||
#: taiga/users/api.py:208
|
||||
msgid "Invalid image format"
|
||||
msgstr "Väärä kuvaformaatti"
|
||||
|
||||
#: taiga/users/api.py:249
|
||||
#: taiga/users/api.py:261
|
||||
msgid "Duplicated email"
|
||||
msgstr "Sähköposti on jo olemassa"
|
||||
|
||||
#: taiga/users/api.py:251
|
||||
#: taiga/users/api.py:263
|
||||
msgid "Not valid email"
|
||||
msgstr "Virheellinen sähköposti"
|
||||
|
||||
#: taiga/users/api.py:271 taiga/users/api.py:277
|
||||
#: taiga/users/api.py:283 taiga/users/api.py:289
|
||||
msgid ""
|
||||
"Invalid, are you sure the token is correct and you didn't use it before?"
|
||||
msgstr ""
|
||||
"Virheellinen. Oletko varma, että tunniste on oikea ja et ole jo käyttänyt "
|
||||
"sitä?"
|
||||
|
||||
#: taiga/users/api.py:304 taiga/users/api.py:312 taiga/users/api.py:315
|
||||
#: taiga/users/api.py:316 taiga/users/api.py:324 taiga/users/api.py:327
|
||||
msgid "Invalid, are you sure the token is correct?"
|
||||
msgstr "Virheellinen, oletko varma että tunniste on oikea?"
|
||||
|
||||
|
@ -3161,22 +3158,26 @@ msgid "default language"
|
|||
msgstr "oletuskieli"
|
||||
|
||||
#: taiga/users/models.py:122
|
||||
msgid "default theme"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/users/models.py:124
|
||||
msgid "default timezone"
|
||||
msgstr "oletus aikavyöhyke"
|
||||
|
||||
#: taiga/users/models.py:124
|
||||
#: taiga/users/models.py:126
|
||||
msgid "colorize tags"
|
||||
msgstr "väritä avainsanat"
|
||||
|
||||
#: taiga/users/models.py:129
|
||||
#: taiga/users/models.py:131
|
||||
msgid "email token"
|
||||
msgstr "sähköpostitunniste"
|
||||
|
||||
#: taiga/users/models.py:131
|
||||
#: taiga/users/models.py:133
|
||||
msgid "new email address"
|
||||
msgstr "uusi sähköpostiosoite"
|
||||
|
||||
#: taiga/users/models.py:185
|
||||
#: taiga/users/models.py:188
|
||||
msgid "permissions"
|
||||
msgstr "oikeudet"
|
||||
|
||||
|
|
|
@ -5,15 +5,17 @@
|
|||
# Translators:
|
||||
# Alain Poirier <alain.poirier@net-ng.com>, 2015
|
||||
# David Barragán <bameda@gmail.com>, 2015
|
||||
# Florent B. <me@kxrz.me>, 2015
|
||||
# Louis-Michel Couture <louim_1@hotmail.com>, 2015
|
||||
# Matthieu Durocher <matthieu@technocyclope.com>, 2015
|
||||
# Stéphane Mor <stephanemor@gmail.com>, 2015
|
||||
# William Godin <williamgodin@gmail.com>, 2015
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: taiga-back\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-05-25 17:31+0200\n"
|
||||
"PO-Revision-Date: 2015-05-25 13:58+0000\n"
|
||||
"POT-Creation-Date: 2015-06-09 09:47+0200\n"
|
||||
"PO-Revision-Date: 2015-06-09 07:47+0000\n"
|
||||
"Last-Translator: Taiga Dev Team <support@taiga.io>\n"
|
||||
"Language-Team: French (http://www.transifex.com/projects/p/taiga-back/"
|
||||
"language/fr/)\n"
|
||||
|
@ -142,7 +144,7 @@ msgstr ""
|
|||
#: taiga/base/api/fields.py:860
|
||||
#, python-format
|
||||
msgid "\"%s\" value must be a float."
|
||||
msgstr "La valeur de \"%s\" doit être un nombre flottant."
|
||||
msgstr "La valeur de \"%s\" doit être un nombre en virgule flottante."
|
||||
|
||||
#: taiga/base/api/fields.py:881
|
||||
msgid "Enter a number."
|
||||
|
@ -225,7 +227,7 @@ msgstr "Type incorrect. Valeur pk attendue, %s reçu."
|
|||
#: taiga/base/api/relations.py:310
|
||||
#, python-format
|
||||
msgid "Object with %s=%s does not exist."
|
||||
msgstr "L'object pour lequel %s=%s n'existe pas."
|
||||
msgstr "L'objet pour lequel %s=%s n'existe pas."
|
||||
|
||||
#: taiga/base/api/relations.py:346
|
||||
msgid "Invalid hyperlink - No URL match"
|
||||
|
@ -461,15 +463,12 @@ msgstr "Updates"
|
|||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" <h3>comment:"
|
||||
" <h3>comment:"
|
||||
"</h3>\n"
|
||||
" <p>"
|
||||
" <p>"
|
||||
"%(comment)s</p>\n"
|
||||
" "
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
"<h3>commentaire:</h3>\n"
|
||||
"<p>%(comment)s</p>"
|
||||
|
||||
#: taiga/base/templates/emails/updates-body-text.jinja:6
|
||||
#, python-format
|
||||
|
@ -484,7 +483,7 @@ msgstr ""
|
|||
|
||||
#: taiga/export_import/api.py:103
|
||||
msgid "We needed at least one role"
|
||||
msgstr ""
|
||||
msgstr "Veuillez sélectionner au moins un rôle."
|
||||
|
||||
#: taiga/export_import/api.py:197
|
||||
msgid "Needed dump file"
|
||||
|
@ -496,15 +495,16 @@ msgstr "Format de dump invalide"
|
|||
|
||||
#: taiga/export_import/dump_service.py:96
|
||||
msgid "error importing project data"
|
||||
msgstr ""
|
||||
msgstr "Erreur lors de l'importation de données"
|
||||
|
||||
#: taiga/export_import/dump_service.py:109
|
||||
msgid "error importing lists of project attributes"
|
||||
msgstr ""
|
||||
msgstr "erreur lors de l'importation des listes des attributs de projet"
|
||||
|
||||
#: taiga/export_import/dump_service.py:114
|
||||
msgid "error importing default project attributes values"
|
||||
msgstr ""
|
||||
"erreur lors de l'importation des valeurs par défaut des attributs de projet"
|
||||
|
||||
#: taiga/export_import/dump_service.py:124
|
||||
msgid "error importing custom attributes"
|
||||
|
@ -520,7 +520,7 @@ msgstr "Erreur à l'importation des groupes d'utilisateurs"
|
|||
|
||||
#: taiga/export_import/dump_service.py:149
|
||||
msgid "error importing sprints"
|
||||
msgstr ""
|
||||
msgstr "Erreur lors de l'importation des sprints."
|
||||
|
||||
#: taiga/export_import/dump_service.py:154
|
||||
msgid "error importing wiki pages"
|
||||
|
@ -540,11 +540,11 @@ msgstr "erreur à l'importation des histoires utilisateur"
|
|||
|
||||
#: taiga/export_import/dump_service.py:174
|
||||
msgid "error importing tasks"
|
||||
msgstr ""
|
||||
msgstr "Erreur lors de l'importation des tâches."
|
||||
|
||||
#: taiga/export_import/dump_service.py:179
|
||||
msgid "error importing tags"
|
||||
msgstr ""
|
||||
msgstr "erreur lors de l'importation des mots-clés"
|
||||
|
||||
#: taiga/export_import/dump_service.py:183
|
||||
msgid "error importing timelines"
|
||||
|
@ -870,7 +870,7 @@ msgstr ""
|
|||
|
||||
#: taiga/hooks/github/event_hooks.py:169
|
||||
msgid "Issue created from GitHub."
|
||||
msgstr ""
|
||||
msgstr "Suivi de problème créé à partir de GitHub."
|
||||
|
||||
#: taiga/hooks/github/event_hooks.py:178 taiga/hooks/github/event_hooks.py:193
|
||||
msgid "Invalid issue comment information"
|
||||
|
@ -1106,7 +1106,7 @@ msgstr "propriétaire"
|
|||
#: taiga/projects/models.py:507 taiga/projects/models.py:538
|
||||
#: taiga/projects/notifications/models.py:69 taiga/projects/tasks/models.py:41
|
||||
#: taiga/projects/userstories/models.py:62 taiga/projects/wiki/models.py:28
|
||||
#: taiga/projects/wiki/models.py:66 taiga/users/models.py:193
|
||||
#: taiga/projects/wiki/models.py:66 taiga/users/models.py:196
|
||||
msgid "project"
|
||||
msgstr "projet"
|
||||
|
||||
|
@ -1150,7 +1150,7 @@ msgstr "description"
|
|||
#: taiga/projects/models.py:391 taiga/projects/models.py:418
|
||||
#: taiga/projects/models.py:453 taiga/projects/models.py:476
|
||||
#: taiga/projects/models.py:501 taiga/projects/models.py:534
|
||||
#: taiga/projects/wiki/models.py:71 taiga/users/models.py:188
|
||||
#: taiga/projects/wiki/models.py:71 taiga/users/models.py:191
|
||||
msgid "order"
|
||||
msgstr "ordre"
|
||||
|
||||
|
@ -1172,7 +1172,7 @@ msgstr "Talky"
|
|||
#: taiga/projects/models.py:414 taiga/projects/models.py:451
|
||||
#: taiga/projects/models.py:474 taiga/projects/models.py:497
|
||||
#: taiga/projects/models.py:532 taiga/projects/models.py:555
|
||||
#: taiga/users/models.py:180 taiga/webhooks/models.py:27
|
||||
#: taiga/users/models.py:183 taiga/webhooks/models.py:27
|
||||
msgid "name"
|
||||
msgstr "nom"
|
||||
|
||||
|
@ -1395,7 +1395,7 @@ msgstr "référence externe"
|
|||
#: taiga/projects/milestones/models.py:37 taiga/projects/models.py:125
|
||||
#: taiga/projects/models.py:352 taiga/projects/models.py:416
|
||||
#: taiga/projects/models.py:499 taiga/projects/models.py:557
|
||||
#: taiga/projects/wiki/models.py:30 taiga/users/models.py:182
|
||||
#: taiga/projects/wiki/models.py:30 taiga/users/models.py:185
|
||||
msgid "slug"
|
||||
msgstr "slug"
|
||||
|
||||
|
@ -1443,9 +1443,9 @@ msgstr "email"
|
|||
|
||||
#: taiga/projects/models.py:61
|
||||
msgid "create at"
|
||||
msgstr ""
|
||||
msgstr "Créé le"
|
||||
|
||||
#: taiga/projects/models.py:63 taiga/users/models.py:126
|
||||
#: taiga/projects/models.py:63 taiga/users/models.py:128
|
||||
msgid "token"
|
||||
msgstr "jeton"
|
||||
|
||||
|
@ -2131,15 +2131,15 @@ msgstr "La liste des observateurs contient des utilisateurs invalides"
|
|||
msgid "The version must be an integer"
|
||||
msgstr "La version doit être un nombre entier"
|
||||
|
||||
#: taiga/projects/occ/mixins.py:56
|
||||
msgid "The version is not valid"
|
||||
msgstr "La version n'est pas valide"
|
||||
#: taiga/projects/occ/mixins.py:58
|
||||
msgid "The version parameter is not valid"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/projects/occ/mixins.py:72
|
||||
#: taiga/projects/occ/mixins.py:74
|
||||
msgid "The version doesn't match with the current one"
|
||||
msgstr "La version ne correspond pas à la version courante"
|
||||
|
||||
#: taiga/projects/occ/mixins.py:92
|
||||
#: taiga/projects/occ/mixins.py:93
|
||||
msgid "version"
|
||||
msgstr "version"
|
||||
|
||||
|
@ -2156,43 +2156,43 @@ msgstr "Adresse email déjà existante"
|
|||
msgid "Invalid role for the project"
|
||||
msgstr "Rôle non valide pour le projet"
|
||||
|
||||
#: taiga/projects/serializers.py:343
|
||||
#: taiga/projects/serializers.py:340
|
||||
msgid "Total milestones must be major or equal to zero"
|
||||
msgstr "Le nombre de jalons doit être supérieur ou égal à zéro"
|
||||
|
||||
#: taiga/projects/serializers.py:400
|
||||
#: taiga/projects/serializers.py:402
|
||||
msgid "Default options"
|
||||
msgstr "Options par défaut"
|
||||
|
||||
#: taiga/projects/serializers.py:401
|
||||
#: taiga/projects/serializers.py:403
|
||||
msgid "User story's statuses"
|
||||
msgstr "Etats de la User Story"
|
||||
|
||||
#: taiga/projects/serializers.py:402
|
||||
#: taiga/projects/serializers.py:404
|
||||
msgid "Points"
|
||||
msgstr "Points"
|
||||
|
||||
#: taiga/projects/serializers.py:403
|
||||
#: taiga/projects/serializers.py:405
|
||||
msgid "Task's statuses"
|
||||
msgstr "Etats des tâches"
|
||||
|
||||
#: taiga/projects/serializers.py:404
|
||||
#: taiga/projects/serializers.py:406
|
||||
msgid "Issue's statuses"
|
||||
msgstr "Statuts des problèmes"
|
||||
|
||||
#: taiga/projects/serializers.py:405
|
||||
#: taiga/projects/serializers.py:407
|
||||
msgid "Issue's types"
|
||||
msgstr "Types de problèmes"
|
||||
|
||||
#: taiga/projects/serializers.py:406
|
||||
#: taiga/projects/serializers.py:408
|
||||
msgid "Priorities"
|
||||
msgstr "Priorités"
|
||||
|
||||
#: taiga/projects/serializers.py:407
|
||||
#: taiga/projects/serializers.py:409
|
||||
msgid "Severities"
|
||||
msgstr "Sévérités"
|
||||
|
||||
#: taiga/projects/serializers.py:408
|
||||
#: taiga/projects/serializers.py:410
|
||||
msgid "Roles"
|
||||
msgstr "Rôles"
|
||||
|
||||
|
@ -2689,58 +2689,58 @@ msgstr "Permissions"
|
|||
msgid "Important dates"
|
||||
msgstr "Dates importantes"
|
||||
|
||||
#: taiga/users/api.py:112 taiga/users/api.py:119
|
||||
#: taiga/users/api.py:124 taiga/users/api.py:131
|
||||
msgid "Invalid username or email"
|
||||
msgstr "Nom d'utilisateur ou email non valide"
|
||||
|
||||
#: taiga/users/api.py:128
|
||||
#: taiga/users/api.py:140
|
||||
msgid "Mail sended successful!"
|
||||
msgstr "Mail envoyé avec succès!"
|
||||
|
||||
#: taiga/users/api.py:140 taiga/users/api.py:145
|
||||
#: taiga/users/api.py:152 taiga/users/api.py:157
|
||||
msgid "Token is invalid"
|
||||
msgstr "Jeton invalide"
|
||||
|
||||
#: taiga/users/api.py:166
|
||||
#: taiga/users/api.py:178
|
||||
msgid "Current password parameter needed"
|
||||
msgstr "Paramètre 'mot de passe actuel' requis"
|
||||
|
||||
#: taiga/users/api.py:169
|
||||
#: taiga/users/api.py:181
|
||||
msgid "New password parameter needed"
|
||||
msgstr "Paramètre 'nouveau mot de passe' requis"
|
||||
|
||||
#: taiga/users/api.py:172
|
||||
#: taiga/users/api.py:184
|
||||
msgid "Invalid password length at least 6 charaters needed"
|
||||
msgstr "Le mot de passe doit être d'au moins 6 caractères"
|
||||
|
||||
#: taiga/users/api.py:175
|
||||
#: taiga/users/api.py:187
|
||||
msgid "Invalid current password"
|
||||
msgstr "Mot de passe actuel incorrect"
|
||||
|
||||
#: taiga/users/api.py:191
|
||||
#: taiga/users/api.py:203
|
||||
msgid "Incomplete arguments"
|
||||
msgstr "arguments manquants"
|
||||
|
||||
#: taiga/users/api.py:196
|
||||
#: taiga/users/api.py:208
|
||||
msgid "Invalid image format"
|
||||
msgstr "format de l'image non valide"
|
||||
|
||||
#: taiga/users/api.py:249
|
||||
#: taiga/users/api.py:261
|
||||
msgid "Duplicated email"
|
||||
msgstr "Email dupliquée"
|
||||
|
||||
#: taiga/users/api.py:251
|
||||
#: taiga/users/api.py:263
|
||||
msgid "Not valid email"
|
||||
msgstr "Email non valide"
|
||||
|
||||
#: taiga/users/api.py:271 taiga/users/api.py:277
|
||||
#: taiga/users/api.py:283 taiga/users/api.py:289
|
||||
msgid ""
|
||||
"Invalid, are you sure the token is correct and you didn't use it before?"
|
||||
msgstr ""
|
||||
"Invalide, êtes-vous sûre que le jeton est correct et qu'il n'a pas déjà été "
|
||||
"utilisé ?"
|
||||
|
||||
#: taiga/users/api.py:304 taiga/users/api.py:312 taiga/users/api.py:315
|
||||
#: taiga/users/api.py:316 taiga/users/api.py:324 taiga/users/api.py:327
|
||||
msgid "Invalid, are you sure the token is correct?"
|
||||
msgstr "Invalide, êtes-vous sûre que le jeton est correct ?"
|
||||
|
||||
|
@ -2799,22 +2799,26 @@ msgid "default language"
|
|||
msgstr "langage par défaut"
|
||||
|
||||
#: taiga/users/models.py:122
|
||||
msgid "default theme"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/users/models.py:124
|
||||
msgid "default timezone"
|
||||
msgstr "Fuseau horaire par défaut"
|
||||
|
||||
#: taiga/users/models.py:124
|
||||
#: taiga/users/models.py:126
|
||||
msgid "colorize tags"
|
||||
msgstr "changer la couleur des tags"
|
||||
|
||||
#: taiga/users/models.py:129
|
||||
#: taiga/users/models.py:131
|
||||
msgid "email token"
|
||||
msgstr "jeton email"
|
||||
|
||||
#: taiga/users/models.py:131
|
||||
#: taiga/users/models.py:133
|
||||
msgid "new email address"
|
||||
msgstr "nouvelle adresse email"
|
||||
|
||||
#: taiga/users/models.py:185
|
||||
#: taiga/users/models.py:188
|
||||
msgid "permissions"
|
||||
msgstr "permissions"
|
||||
|
||||
|
|
|
@ -11,9 +11,9 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: taiga-back\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-05-25 17:31+0200\n"
|
||||
"PO-Revision-Date: 2015-05-25 15:44+0000\n"
|
||||
"Last-Translator: David Barragán <bameda@gmail.com>\n"
|
||||
"POT-Creation-Date: 2015-06-09 09:47+0200\n"
|
||||
"PO-Revision-Date: 2015-06-09 07:47+0000\n"
|
||||
"Last-Translator: Taiga Dev Team <support@taiga.io>\n"
|
||||
"Language-Team: Chinese Traditional (http://www.transifex.com/projects/p/"
|
||||
"taiga-back/language/zh-Hant/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
|
@ -463,15 +463,12 @@ msgstr "更新"
|
|||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" <h3>comment:"
|
||||
" <h3>comment:"
|
||||
"</h3>\n"
|
||||
" <p>"
|
||||
" <p>"
|
||||
"%(comment)s</p>\n"
|
||||
" "
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
"<h3>評論:</h3>\n"
|
||||
"<p>%(comment)s</p>"
|
||||
|
||||
#: taiga/base/templates/emails/updates-body-text.jinja:6
|
||||
#, python-format
|
||||
|
@ -1205,7 +1202,7 @@ msgstr "所有者"
|
|||
#: taiga/projects/models.py:507 taiga/projects/models.py:538
|
||||
#: taiga/projects/notifications/models.py:69 taiga/projects/tasks/models.py:41
|
||||
#: taiga/projects/userstories/models.py:62 taiga/projects/wiki/models.py:28
|
||||
#: taiga/projects/wiki/models.py:66 taiga/users/models.py:193
|
||||
#: taiga/projects/wiki/models.py:66 taiga/users/models.py:196
|
||||
msgid "project"
|
||||
msgstr "專案"
|
||||
|
||||
|
@ -1249,7 +1246,7 @@ msgstr "描述"
|
|||
#: taiga/projects/models.py:391 taiga/projects/models.py:418
|
||||
#: taiga/projects/models.py:453 taiga/projects/models.py:476
|
||||
#: taiga/projects/models.py:501 taiga/projects/models.py:534
|
||||
#: taiga/projects/wiki/models.py:71 taiga/users/models.py:188
|
||||
#: taiga/projects/wiki/models.py:71 taiga/users/models.py:191
|
||||
msgid "order"
|
||||
msgstr "次序"
|
||||
|
||||
|
@ -1271,7 +1268,7 @@ msgstr "Talky"
|
|||
#: taiga/projects/models.py:414 taiga/projects/models.py:451
|
||||
#: taiga/projects/models.py:474 taiga/projects/models.py:497
|
||||
#: taiga/projects/models.py:532 taiga/projects/models.py:555
|
||||
#: taiga/users/models.py:180 taiga/webhooks/models.py:27
|
||||
#: taiga/users/models.py:183 taiga/webhooks/models.py:27
|
||||
msgid "name"
|
||||
msgstr "姓名"
|
||||
|
||||
|
@ -1494,7 +1491,7 @@ msgstr "外部參考"
|
|||
#: taiga/projects/milestones/models.py:37 taiga/projects/models.py:125
|
||||
#: taiga/projects/models.py:352 taiga/projects/models.py:416
|
||||
#: taiga/projects/models.py:499 taiga/projects/models.py:557
|
||||
#: taiga/projects/wiki/models.py:30 taiga/users/models.py:182
|
||||
#: taiga/projects/wiki/models.py:30 taiga/users/models.py:185
|
||||
msgid "slug"
|
||||
msgstr "代稱"
|
||||
|
||||
|
@ -1544,7 +1541,7 @@ msgstr "電子郵件"
|
|||
msgid "create at"
|
||||
msgstr "創建於"
|
||||
|
||||
#: taiga/projects/models.py:63 taiga/users/models.py:126
|
||||
#: taiga/projects/models.py:63 taiga/users/models.py:128
|
||||
msgid "token"
|
||||
msgstr "代號"
|
||||
|
||||
|
@ -2474,15 +2471,15 @@ msgstr "監督者包含無效使用者"
|
|||
msgid "The version must be an integer"
|
||||
msgstr "版本須為整數值 "
|
||||
|
||||
#: taiga/projects/occ/mixins.py:56
|
||||
msgid "The version is not valid"
|
||||
msgstr "版本無效"
|
||||
#: taiga/projects/occ/mixins.py:58
|
||||
msgid "The version parameter is not valid"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/projects/occ/mixins.py:72
|
||||
#: taiga/projects/occ/mixins.py:74
|
||||
msgid "The version doesn't match with the current one"
|
||||
msgstr "版本與目前使用不相符"
|
||||
|
||||
#: taiga/projects/occ/mixins.py:92
|
||||
#: taiga/projects/occ/mixins.py:93
|
||||
msgid "version"
|
||||
msgstr "版本"
|
||||
|
||||
|
@ -2498,43 +2495,43 @@ msgstr "電子郵件已使用"
|
|||
msgid "Invalid role for the project"
|
||||
msgstr "專案無效的角色"
|
||||
|
||||
#: taiga/projects/serializers.py:343
|
||||
#: taiga/projects/serializers.py:340
|
||||
msgid "Total milestones must be major or equal to zero"
|
||||
msgstr "Kanban"
|
||||
|
||||
#: taiga/projects/serializers.py:400
|
||||
#: taiga/projects/serializers.py:402
|
||||
msgid "Default options"
|
||||
msgstr "預設選項"
|
||||
|
||||
#: taiga/projects/serializers.py:401
|
||||
#: taiga/projects/serializers.py:403
|
||||
msgid "User story's statuses"
|
||||
msgstr "使用者故事狀態"
|
||||
|
||||
#: taiga/projects/serializers.py:402
|
||||
#: taiga/projects/serializers.py:404
|
||||
msgid "Points"
|
||||
msgstr "點數"
|
||||
|
||||
#: taiga/projects/serializers.py:403
|
||||
#: taiga/projects/serializers.py:405
|
||||
msgid "Task's statuses"
|
||||
msgstr "任務狀態"
|
||||
|
||||
#: taiga/projects/serializers.py:404
|
||||
#: taiga/projects/serializers.py:406
|
||||
msgid "Issue's statuses"
|
||||
msgstr "問題狀態"
|
||||
|
||||
#: taiga/projects/serializers.py:405
|
||||
#: taiga/projects/serializers.py:407
|
||||
msgid "Issue's types"
|
||||
msgstr "問題類型"
|
||||
|
||||
#: taiga/projects/serializers.py:406
|
||||
#: taiga/projects/serializers.py:408
|
||||
msgid "Priorities"
|
||||
msgstr "優先性"
|
||||
|
||||
#: taiga/projects/serializers.py:407
|
||||
#: taiga/projects/serializers.py:409
|
||||
msgid "Severities"
|
||||
msgstr "嚴重性"
|
||||
|
||||
#: taiga/projects/serializers.py:408
|
||||
#: taiga/projects/serializers.py:410
|
||||
msgid "Roles"
|
||||
msgstr "角色"
|
||||
|
||||
|
@ -3043,56 +3040,56 @@ msgstr "許可"
|
|||
msgid "Important dates"
|
||||
msgstr "重要日期"
|
||||
|
||||
#: taiga/users/api.py:112 taiga/users/api.py:119
|
||||
#: taiga/users/api.py:124 taiga/users/api.py:131
|
||||
msgid "Invalid username or email"
|
||||
msgstr "無效使用者或郵件"
|
||||
|
||||
#: taiga/users/api.py:128
|
||||
#: taiga/users/api.py:140
|
||||
msgid "Mail sended successful!"
|
||||
msgstr "成功送出郵件"
|
||||
|
||||
#: taiga/users/api.py:140 taiga/users/api.py:145
|
||||
#: taiga/users/api.py:152 taiga/users/api.py:157
|
||||
msgid "Token is invalid"
|
||||
msgstr "代號無效"
|
||||
|
||||
#: taiga/users/api.py:166
|
||||
#: taiga/users/api.py:178
|
||||
msgid "Current password parameter needed"
|
||||
msgstr "需要目前密碼之參數"
|
||||
|
||||
#: taiga/users/api.py:169
|
||||
#: taiga/users/api.py:181
|
||||
msgid "New password parameter needed"
|
||||
msgstr "需要新密碼參數"
|
||||
|
||||
#: taiga/users/api.py:172
|
||||
#: taiga/users/api.py:184
|
||||
msgid "Invalid password length at least 6 charaters needed"
|
||||
msgstr "無效密碼長度,至少需6個字元"
|
||||
|
||||
#: taiga/users/api.py:175
|
||||
#: taiga/users/api.py:187
|
||||
msgid "Invalid current password"
|
||||
msgstr "無效密碼"
|
||||
|
||||
#: taiga/users/api.py:191
|
||||
#: taiga/users/api.py:203
|
||||
msgid "Incomplete arguments"
|
||||
msgstr "不完整參數"
|
||||
|
||||
#: taiga/users/api.py:196
|
||||
#: taiga/users/api.py:208
|
||||
msgid "Invalid image format"
|
||||
msgstr "無效的圖片檔案"
|
||||
|
||||
#: taiga/users/api.py:249
|
||||
#: taiga/users/api.py:261
|
||||
msgid "Duplicated email"
|
||||
msgstr "複製電子郵件"
|
||||
|
||||
#: taiga/users/api.py:251
|
||||
#: taiga/users/api.py:263
|
||||
msgid "Not valid email"
|
||||
msgstr "非有效電子郵性"
|
||||
|
||||
#: taiga/users/api.py:271 taiga/users/api.py:277
|
||||
#: taiga/users/api.py:283 taiga/users/api.py:289
|
||||
msgid ""
|
||||
"Invalid, are you sure the token is correct and you didn't use it before?"
|
||||
msgstr "無效,請確認代號正確,之前是否曾使用過?"
|
||||
|
||||
#: taiga/users/api.py:304 taiga/users/api.py:312 taiga/users/api.py:315
|
||||
#: taiga/users/api.py:316 taiga/users/api.py:324 taiga/users/api.py:327
|
||||
msgid "Invalid, are you sure the token is correct?"
|
||||
msgstr "無效,請確認代號是否正確?"
|
||||
|
||||
|
@ -3146,22 +3143,26 @@ msgid "default language"
|
|||
msgstr "預設語言 "
|
||||
|
||||
#: taiga/users/models.py:122
|
||||
msgid "default theme"
|
||||
msgstr ""
|
||||
|
||||
#: taiga/users/models.py:124
|
||||
msgid "default timezone"
|
||||
msgstr "預設時區"
|
||||
|
||||
#: taiga/users/models.py:124
|
||||
#: taiga/users/models.py:126
|
||||
msgid "colorize tags"
|
||||
msgstr "顏色標籤"
|
||||
|
||||
#: taiga/users/models.py:129
|
||||
#: taiga/users/models.py:131
|
||||
msgid "email token"
|
||||
msgstr "電子郵件符號 "
|
||||
|
||||
#: taiga/users/models.py:131
|
||||
#: taiga/users/models.py:133
|
||||
msgid "new email address"
|
||||
msgstr "新電子郵件地址"
|
||||
|
||||
#: taiga/users/models.py:185
|
||||
#: taiga/users/models.py:188
|
||||
msgid "permissions"
|
||||
msgstr "許可"
|
||||
|
||||
|
|
|
@ -25,22 +25,22 @@
|
|||
|
||||
from markdown.extensions import Extension
|
||||
from markdown.inlinepatterns import Pattern
|
||||
from markdown.util import etree
|
||||
from markdown.util import etree, AtomicString
|
||||
|
||||
from taiga.users.models import User
|
||||
|
||||
|
||||
class MentionsExtension(Extension):
|
||||
def extendMarkdown(self, md, md_globals):
|
||||
MENTION_RE = r'(?<=^|(?<=[^a-zA-Z0-9-_\.]))@([A-Za-z]+[A-Za-z0-9-]+)'
|
||||
MENTION_RE = r'(@)([a-z0-9.-\.]+)'
|
||||
mentionsPattern = MentionsPattern(MENTION_RE)
|
||||
mentionsPattern.md = md
|
||||
md.inlinePatterns.add('mentions', mentionsPattern, '_begin')
|
||||
md.inlinePatterns.add('mentions', mentionsPattern, '_end')
|
||||
|
||||
|
||||
class MentionsPattern(Pattern):
|
||||
def handleMatch(self, m):
|
||||
username = m.group(2)
|
||||
username = m.group(3)
|
||||
|
||||
try:
|
||||
user = User.objects.get(username=username)
|
||||
|
@ -49,10 +49,11 @@ class MentionsPattern(Pattern):
|
|||
|
||||
url = "/profile/{}".format(username)
|
||||
|
||||
link_text = "@{}".format(username)
|
||||
link_text = "@{}".format(username)
|
||||
|
||||
a = etree.Element('a')
|
||||
a.text = link_text
|
||||
a.text = AtomicString(link_text)
|
||||
|
||||
a.set('href', url)
|
||||
a.set('title', user.get_full_name())
|
||||
a.set('class', "mention")
|
||||
|
|
|
@ -28,7 +28,7 @@ from markdown.inlinepatterns import Pattern
|
|||
from markdown.util import etree
|
||||
|
||||
from taiga.projects.references.services import get_instance_by_ref
|
||||
from taiga.front import resolve
|
||||
from taiga.front.templatetags.functions import resolve
|
||||
|
||||
|
||||
class TaigaReferencesExtension(Extension):
|
||||
|
|
|
@ -21,7 +21,7 @@ import markdown
|
|||
|
||||
from markdown.treeprocessors import Treeprocessor
|
||||
|
||||
from taiga.front import resolve
|
||||
from taiga.front.templatetags.functions import resolve
|
||||
|
||||
|
||||
class TargetBlankLinkExtension(markdown.Extension):
|
||||
|
|
|
@ -21,7 +21,7 @@ from markdown.treeprocessors import Treeprocessor
|
|||
|
||||
from markdown.util import etree
|
||||
|
||||
from taiga.front import resolve
|
||||
from taiga.front.templatetags.functions import resolve
|
||||
from taiga.base.utils.slug import slugify
|
||||
|
||||
import re
|
||||
|
|
|
@ -96,7 +96,7 @@
|
|||
{% set values_removed = lists_diff(values_from, values_to) %}
|
||||
|
||||
<tr>
|
||||
<td valign="middle" rowspan="2" class="update-row-name">
|
||||
<td valign="middle" class="update-row-name">
|
||||
<h3>{{ verbose_name(obj_class, field_name) }}</h3>
|
||||
</td>
|
||||
<td valign="top" class="update-row-from">
|
||||
|
|
|
@ -110,7 +110,7 @@ class IssueViewSet(OCCResourceMixin, HistoryResourceMixin, WatchedResourceMixin,
|
|||
IssuesFilter, IssuesOrdering,)
|
||||
retrieve_exclude_filters = (IssuesFilter,)
|
||||
|
||||
filter_fields = ("project", "assigned_to", "status__is_closed", "watchers")
|
||||
filter_fields = ("project", "status__is_closed", "watchers")
|
||||
order_by_fields = ("type",
|
||||
"severity",
|
||||
"status",
|
||||
|
|
|
@ -37,7 +37,9 @@ class OCCResourceMixin(object):
|
|||
return param_version
|
||||
|
||||
def _validate_param_version(self, param_version, current_version):
|
||||
if param_version is not None:
|
||||
if param_version is None:
|
||||
return False
|
||||
else:
|
||||
if param_version < 0:
|
||||
return False
|
||||
if current_version is not None and param_version > current_version:
|
||||
|
@ -50,28 +52,27 @@ class OCCResourceMixin(object):
|
|||
if obj.id:
|
||||
current_version = type(obj).objects.model.objects.get(id=obj.id).version
|
||||
|
||||
# Extract param version
|
||||
param_version = self._extract_param_version()
|
||||
if not self._validate_param_version(param_version, current_version):
|
||||
raise exc.WrongArguments({"version": _("The version is not valid")})
|
||||
# Extract param version
|
||||
param_version = self._extract_param_version()
|
||||
if not self._validate_param_version(param_version, current_version):
|
||||
raise exc.WrongArguments({"version": _("The version parameter is not valid")})
|
||||
|
||||
if current_version != param_version:
|
||||
diff_versions = current_version - param_version
|
||||
if current_version != param_version:
|
||||
diff_versions = current_version - param_version
|
||||
|
||||
modifying_fields = set(self.request.DATA.keys())
|
||||
if "version" in modifying_fields:
|
||||
modifying_fields.remove("version")
|
||||
modifying_fields = set(self.request.DATA.keys())
|
||||
if "version" in modifying_fields:
|
||||
modifying_fields.remove("version")
|
||||
|
||||
modified_fields = set(get_modified_fields(obj, diff_versions))
|
||||
if "version" in modifying_fields:
|
||||
modified_fields.remove("version")
|
||||
modified_fields = set(get_modified_fields(obj, diff_versions))
|
||||
if "version" in modifying_fields:
|
||||
modified_fields.remove("version")
|
||||
|
||||
both_modified = modifying_fields & modified_fields
|
||||
both_modified = modifying_fields & modified_fields
|
||||
|
||||
if both_modified:
|
||||
raise exc.WrongArguments({"version": _("The version doesn't match with the current one")})
|
||||
if both_modified:
|
||||
raise exc.WrongArguments({"version": _("The version doesn't match with the current one")})
|
||||
|
||||
if obj.id:
|
||||
obj.version = models.F('version') + 1
|
||||
|
||||
def pre_save(self, obj):
|
||||
|
|
|
@ -305,7 +305,6 @@ class ProjectSerializer(serializers.ModelSerializer):
|
|||
my_permissions = serializers.SerializerMethodField("get_my_permissions")
|
||||
i_am_owner = serializers.SerializerMethodField("get_i_am_owner")
|
||||
tags_colors = TagsColorsField(required=False)
|
||||
users = serializers.SerializerMethodField("get_users")
|
||||
total_closed_milestones = serializers.SerializerMethodField("get_total_closed_milestones")
|
||||
|
||||
class Meta:
|
||||
|
@ -328,9 +327,6 @@ class ProjectSerializer(serializers.ModelSerializer):
|
|||
return is_project_owner(self.context["request"].user, obj)
|
||||
return False
|
||||
|
||||
def get_users(self, obj):
|
||||
return UserSerializer(obj.members.all(), many=True).data
|
||||
|
||||
def get_total_closed_milestones(self, obj):
|
||||
return obj.milestones.filter(closed=True).count()
|
||||
|
||||
|
@ -355,18 +351,20 @@ class ProjectDetailSerializer(ProjectSerializer):
|
|||
issue_types = IssueTypeSerializer(many=True, required=False)
|
||||
priorities = PrioritySerializer(many=True, required=False) # Issues
|
||||
severities = SeveritySerializer(many=True, required=False)
|
||||
|
||||
userstory_custom_attributes = UserStoryCustomAttributeSerializer(source="userstorycustomattributes",
|
||||
many=True, required=False)
|
||||
task_custom_attributes = TaskCustomAttributeSerializer(source="taskcustomattributes",
|
||||
many=True, required=False)
|
||||
issue_custom_attributes = IssueCustomAttributeSerializer(source="issuecustomattributes",
|
||||
many=True, required=False)
|
||||
users = serializers.SerializerMethodField("get_users")
|
||||
|
||||
def get_memberships(self, obj):
|
||||
qs = obj.memberships.filter(user__isnull=False)
|
||||
qs = qs.order_by('user__full_name', 'user__username')
|
||||
qs = qs.extra(select={"complete_user_name":"concat(full_name, username)"})
|
||||
qs = qs.order_by("complete_user_name")
|
||||
qs = qs.select_related("role", "user")
|
||||
|
||||
serializer = ProjectMembershipSerializer(qs, many=True)
|
||||
return serializer.data
|
||||
|
||||
|
@ -374,6 +372,9 @@ class ProjectDetailSerializer(ProjectSerializer):
|
|||
serializer = ProjectRoleSerializer(obj.roles.all(), many=True)
|
||||
return serializer.data
|
||||
|
||||
def get_users(self, obj):
|
||||
return UserSerializer(obj.members.all(), many=True).data
|
||||
|
||||
|
||||
class ProjectDetailAdminSerializer(ProjectDetailSerializer):
|
||||
class Meta:
|
||||
|
|
|
@ -50,12 +50,13 @@ class UserStoryViewSet(OCCResourceMixin, HistoryResourceMixin, WatchedResourceMi
|
|||
list_serializer_class = serializers.UserStorySerializer
|
||||
permission_classes = (permissions.UserStoryPermission,)
|
||||
|
||||
filter_backends = (filters.CanViewUsFilterBackend, filters.TagsFilter,
|
||||
filter_backends = (filters.StatusFilter, filters.CanViewUsFilterBackend, filters.TagsFilter,
|
||||
filters.QFilter, filters.OrderByFilterMixin)
|
||||
retrieve_exclude_filters = (filters.TagsFilter,)
|
||||
filter_fields = ["project", "milestone", "milestone__isnull", "status",
|
||||
|
||||
retrieve_exclude_filters = (filters.StatusFilter, filters.TagsFilter,)
|
||||
filter_fields = ["project", "milestone", "milestone__isnull",
|
||||
"is_archived", "status__is_archived", "assigned_to",
|
||||
"status__is_closed", "watchers"]
|
||||
"status__is_closed", "watchers", "is_closed"]
|
||||
order_by_fields = ["backlog_order", "sprint_order", "kanban_order"]
|
||||
|
||||
# Specific filter used for filtering neighbor user stories
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
# Copyright (C) 2014 Andrey Antukh <niwi@niwi.be>
|
||||
# Copyright (C) 2014 Jesús Espino <jespinog@gmail.com>
|
||||
# Copyright (C) 2014 David Barragán <bameda@dbarragan.com>
|
||||
# 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/>.
|
||||
from django.conf import settings
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db.models import Prefetch, F
|
||||
|
||||
from taiga.timeline.models import Timeline
|
||||
from taiga.timeline.timeline_implementations import userstory_timeline
|
||||
from optparse import make_option
|
||||
from taiga.projects.tasks.models import Task
|
||||
from taiga.projects.userstories.models import UserStory
|
||||
|
||||
|
||||
def update_timeline(initial_date, final_date):
|
||||
timelines = Timeline.objects.all()
|
||||
if initial_date:
|
||||
timelines = timelines.filter(created__gte=initial_date)
|
||||
if final_date:
|
||||
timelines = timelines.filter(created__lt=final_date)
|
||||
|
||||
timelines = timelines.filter(event_type="tasks.task.change")
|
||||
|
||||
print("Generating tasks indexed by id dict")
|
||||
task_ids = timelines.values_list("object_id", flat=True)
|
||||
tasks_per_id = {task.id: task for task in Task.objects.filter(id__in=task_ids).select_related("user_story").iterator()}
|
||||
del task_ids
|
||||
|
||||
counter = 1
|
||||
total = timelines.count()
|
||||
print("Updating timelines")
|
||||
for timeline in timelines.iterator():
|
||||
print("%s/%s"%(counter, total))
|
||||
task_id = timeline.object_id
|
||||
task = tasks_per_id.get(task_id, None)
|
||||
if not task:
|
||||
counter += 1
|
||||
continue
|
||||
|
||||
user_story = tasks_per_id[task_id].user_story
|
||||
if not user_story:
|
||||
counter += 1
|
||||
continue
|
||||
|
||||
timeline.data["task"]["userstory"] = userstory_timeline(user_story)
|
||||
timeline.save(update_fields=["data"])
|
||||
counter += 1
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Regenerate project timeline'
|
||||
option_list = BaseCommand.option_list + (
|
||||
make_option('--initial_date',
|
||||
action='store',
|
||||
dest='initial_date',
|
||||
default=None,
|
||||
help='Initial date for timeline update'),
|
||||
) + (
|
||||
make_option('--final_date',
|
||||
action='store',
|
||||
dest='final_date',
|
||||
default=None,
|
||||
help='Final date for timeline update'),
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
debug_enabled = settings.DEBUG
|
||||
if debug_enabled:
|
||||
print("Please, execute this script only with DEBUG mode disabled (DEBUG=False)")
|
||||
return
|
||||
|
||||
update_timeline(options["initial_date"], options["final_date"])
|
|
@ -36,11 +36,6 @@ class Timeline(models.Model):
|
|||
data_content_type = models.ForeignKey(ContentType, related_name="data_timelines")
|
||||
created = models.DateTimeField(default=timezone.now)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if self.id:
|
||||
raise ValidationError("Not modify allowed for timeline entries")
|
||||
return super().save(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
index_together = [('content_type', 'object_id', 'namespace'), ]
|
||||
|
||||
|
|
|
@ -76,10 +76,13 @@ def task_timeline(instance, extra_data={}):
|
|||
"task": service.extract_task_info(instance),
|
||||
"project": service.extract_project_info(instance.project),
|
||||
}
|
||||
|
||||
if instance.user_story:
|
||||
result["task"]["userstory"] = service.extract_userstory_info(instance.user_story)
|
||||
|
||||
result.update(extra_data)
|
||||
return result
|
||||
|
||||
|
||||
@register_timeline_implementation("wiki.wikipage", "create")
|
||||
@register_timeline_implementation("wiki.wikipage", "change")
|
||||
@register_timeline_implementation("wiki.wikipage", "delete")
|
||||
|
|
|
@ -16,12 +16,16 @@
|
|||
|
||||
from django.conf import settings
|
||||
from django.conf.urls import patterns, include, url
|
||||
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
||||
from django.contrib import admin
|
||||
|
||||
from .routers import router
|
||||
from .contrib_routers import router as contrib_router
|
||||
|
||||
|
||||
##############################################
|
||||
# Default
|
||||
##############################################
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^api/v1/', include(router.urls)),
|
||||
url(r'^api/v1/', include(contrib_router.urls)),
|
||||
|
@ -29,21 +33,51 @@ urlpatterns = [
|
|||
url(r'^admin/', include(admin.site.urls)),
|
||||
]
|
||||
|
||||
def mediafiles_urlpatterns(prefix):
|
||||
"""
|
||||
Method for serve media files with runserver.
|
||||
"""
|
||||
import re
|
||||
from django.views.static import serve
|
||||
handler500 = "taiga.base.api.views.api_server_error"
|
||||
|
||||
return [
|
||||
url(r'^%s(?P<path>.*)$' % re.escape(prefix.lstrip('/')), serve,
|
||||
{'document_root': settings.MEDIA_ROOT})
|
||||
|
||||
##############################################
|
||||
# Front sitemap
|
||||
##############################################
|
||||
|
||||
if settings.FRONT_SITEMAP_ENABLED:
|
||||
from django.contrib.sitemaps.views import index
|
||||
from django.contrib.sitemaps.views import sitemap
|
||||
from django.views.decorators.cache import cache_page
|
||||
|
||||
from taiga.front.sitemaps import sitemaps
|
||||
|
||||
urlpatterns += [
|
||||
url(r"^front/sitemap\.xml$",
|
||||
cache_page(settings.FRONT_SITEMAP_CACHE_TIMEOUT)(index),
|
||||
{"sitemaps": sitemaps, 'sitemap_url_name': 'front-sitemap'},
|
||||
name="front-sitemap-index"),
|
||||
url(r"^front/sitemap-(?P<section>.+)\.xml$",
|
||||
cache_page(settings.FRONT_SITEMAP_CACHE_TIMEOUT)(sitemap),
|
||||
{"sitemaps": sitemaps},
|
||||
name="front-sitemap")
|
||||
]
|
||||
|
||||
|
||||
##############################################
|
||||
# Static and media files in debug mode
|
||||
##############################################
|
||||
|
||||
if settings.DEBUG:
|
||||
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
||||
|
||||
def mediafiles_urlpatterns(prefix):
|
||||
"""
|
||||
Method for serve media files with runserver.
|
||||
"""
|
||||
import re
|
||||
from django.views.static import serve
|
||||
|
||||
return [
|
||||
url(r'^%s(?P<path>.*)$' % re.escape(prefix.lstrip('/')), serve,
|
||||
{'document_root': settings.MEDIA_ROOT})
|
||||
]
|
||||
|
||||
# Hardcoded only for development server
|
||||
urlpatterns += staticfiles_urlpatterns(prefix="/static/")
|
||||
urlpatterns += mediafiles_urlpatterns(prefix="/media/")
|
||||
|
||||
handler500 = "taiga.base.api.views.api_server_error"
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
import uuid
|
||||
|
||||
from django.apps import apps
|
||||
from django.db.models import Q
|
||||
from django.db.models import Q, F
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.core.validators import validate_email
|
||||
from django.core.exceptions import ValidationError
|
||||
|
@ -97,7 +97,8 @@ class UsersViewSet(ModelCrudViewSet):
|
|||
self.check_permissions(request, 'contacts', user)
|
||||
|
||||
self.object_list = user_filters.ContactsFilterBackend().filter_queryset(
|
||||
user, request, self.get_queryset(), self)
|
||||
user, request, self.get_queryset(), self).extra(
|
||||
select={"complete_user_name":"concat(full_name, username)"}).order_by("complete_user_name")
|
||||
|
||||
page = self.paginate_queryset(self.object_list)
|
||||
if page is not None:
|
||||
|
@ -111,7 +112,7 @@ class UsersViewSet(ModelCrudViewSet):
|
|||
def stats(self, request, *args, **kwargs):
|
||||
user = get_object_or_404(models.User, **kwargs)
|
||||
self.check_permissions(request, "stats", user)
|
||||
return response.Ok(services.get_stats_for_user(user))
|
||||
return response.Ok(services.get_stats_for_user(user, request.user))
|
||||
|
||||
@list_route(methods=["POST"])
|
||||
def password_recovery(self, request, pk=None):
|
||||
|
|
|
@ -15,30 +15,14 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from django.apps import apps
|
||||
from django.db.models import Q
|
||||
|
||||
from taiga.base.filters import PermissionBasedFilterBackend
|
||||
from . import services
|
||||
|
||||
class ContactsFilterBackend(PermissionBasedFilterBackend):
|
||||
permission = "view_project"
|
||||
|
||||
def filter_queryset(self, user, request, queryset, view):
|
||||
qs = queryset.filter(is_active=True)
|
||||
Membership = apps.get_model('projects', 'Membership')
|
||||
memberships_qs = Membership.objects.filter(user=user)
|
||||
|
||||
# Authenticated
|
||||
if request.user.is_authenticated():
|
||||
# if super user we don't need to filter anything
|
||||
if not request.user.is_superuser:
|
||||
memberships_qs = memberships_qs.filter(Q(role__permissions__contains=[self.permission]) |
|
||||
Q(is_owner=True))
|
||||
|
||||
# Anonymous
|
||||
else:
|
||||
memberships_qs = memberships_qs.filter(project__anon_permissions__contains=[self.permission])
|
||||
|
||||
projects_list = [membership.project_id for membership in memberships_qs]
|
||||
qs = qs.filter(memberships__project_id__in=projects_list)
|
||||
project_ids = services.get_visible_project_ids(user, request.user)
|
||||
qs = qs.filter(memberships__project_id__in=project_ids)
|
||||
qs = qs.exclude(id=user.id)
|
||||
return qs.distinct()
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('users', '0010_auto_20150414_0936'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='user',
|
||||
name='theme',
|
||||
field=models.CharField(null=True, blank=True, max_length=100, default='', verbose_name='default theme'),
|
||||
preserve_default=True,
|
||||
),
|
||||
]
|
|
@ -118,6 +118,8 @@ class User(AbstractBaseUser, PermissionsMixin):
|
|||
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
|
||||
lang = models.CharField(max_length=20, null=True, blank=True, default="",
|
||||
verbose_name=_("default language"))
|
||||
theme = models.CharField(max_length=100, null=True, blank=True, default="",
|
||||
verbose_name=_("default theme"))
|
||||
timezone = models.CharField(max_length=20, null=True, blank=True, default="",
|
||||
verbose_name=_("default timezone"))
|
||||
colorize_tags = models.BooleanField(null=False, blank=True, default=False,
|
||||
|
@ -167,6 +169,7 @@ class User(AbstractBaseUser, PermissionsMixin):
|
|||
self.color = ""
|
||||
self.bio = ""
|
||||
self.lang = ""
|
||||
self.theme = ""
|
||||
self.timezone = ""
|
||||
self.colorize_tags = True
|
||||
self.token = None
|
||||
|
|
|
@ -49,7 +49,7 @@ class UserSerializer(serializers.ModelSerializer):
|
|||
# IMPORTANT: Maintain the UserAdminSerializer Meta up to date
|
||||
# with this info (including there the email)
|
||||
fields = ("id", "username", "full_name", "full_name_display",
|
||||
"color", "bio", "lang", "timezone", "is_active",
|
||||
"color", "bio", "lang", "theme", "timezone", "is_active",
|
||||
"photo", "big_photo", "roles", "projects_with_me")
|
||||
read_only_fields = ("id",)
|
||||
|
||||
|
@ -103,7 +103,7 @@ class UserAdminSerializer(UserSerializer):
|
|||
# IMPORTANT: Maintain the UserSerializer Meta up to date
|
||||
# with this info (including here the email)
|
||||
fields = ("id", "username", "full_name", "full_name_display", "email",
|
||||
"color", "bio", "lang", "timezone", "is_active", "photo",
|
||||
"color", "bio", "lang", "theme", "timezone", "is_active", "photo",
|
||||
"big_photo")
|
||||
read_only_fields = ("id", "email")
|
||||
|
||||
|
|
|
@ -89,21 +89,51 @@ def get_big_photo_or_gravatar_url(user):
|
|||
else:
|
||||
return get_gravatar_url(user.email, size=settings.DEFAULT_BIG_AVATAR_SIZE)
|
||||
|
||||
def get_stats_for_user(user):
|
||||
"""Get the user stats"""
|
||||
|
||||
project_ids = user.memberships.values_list("project__id", flat=True).distinct()
|
||||
total_num_projects = project_ids.count()
|
||||
roles = [_(r) for r in user.memberships.values_list("role__name", flat=True)]
|
||||
def get_visible_project_ids(from_user, by_user):
|
||||
"""Calculate the project_ids from one user visible by another"""
|
||||
required_permissions = ["view_project"]
|
||||
#Or condition for membership filtering, the basic one is the access to projects allowing anonymous visualization
|
||||
member_perm_conditions = Q(project__anon_permissions__contains=required_permissions)
|
||||
|
||||
# Authenticated
|
||||
if by_user.is_authenticated():
|
||||
#Calculating the projects wich from_user user is member
|
||||
by_user_project_ids = by_user.memberships.values_list("project__id", flat=True)
|
||||
#Adding to the condition two OR situations:
|
||||
#- The from user has a role that allows access to the project
|
||||
#- The to user is the owner
|
||||
member_perm_conditions |= \
|
||||
Q(project__id__in=by_user_project_ids, role__permissions__contains=required_permissions) |\
|
||||
Q(project__id__in=by_user_project_ids, is_owner=True)
|
||||
|
||||
Membership = apps.get_model('projects', 'Membership')
|
||||
#Calculating the user memberships adding the permission filter for the by user
|
||||
memberships_qs = Membership.objects.filter(member_perm_conditions, user=from_user)
|
||||
project_ids = memberships_qs.values_list("project__id", flat=True)
|
||||
return project_ids
|
||||
|
||||
|
||||
def get_stats_for_user(from_user, by_user):
|
||||
"""Get the user stats"""
|
||||
project_ids = get_visible_project_ids(from_user, by_user)
|
||||
|
||||
total_num_projects = len(project_ids)
|
||||
|
||||
roles = [_(r) for r in from_user.memberships.filter(project__id__in=project_ids).values_list("role__name", flat=True)]
|
||||
roles = list(set(roles))
|
||||
|
||||
User = apps.get_model('users', 'User')
|
||||
total_num_contacts = User.objects.filter(memberships__project__id__in=project_ids)\
|
||||
.exclude(id=user.id)\
|
||||
.exclude(id=from_user.id)\
|
||||
.distinct()\
|
||||
.count()
|
||||
|
||||
UserStory = apps.get_model('userstories', 'UserStory')
|
||||
total_num_closed_userstories = UserStory.objects.filter(is_closed=True, assigned_to=user).count()
|
||||
total_num_closed_userstories = UserStory.objects.filter(
|
||||
is_closed=True,
|
||||
project__id__in=project_ids,
|
||||
assigned_to=from_user).count()
|
||||
|
||||
project_stats = {
|
||||
'total_num_projects': total_num_projects,
|
||||
|
|
|
@ -46,3 +46,8 @@ def test_render_and_extract_mentions():
|
|||
user = factories.UserFactory(username="user1", full_name="test")
|
||||
(_, extracted) = render_and_extract(dummy_project, "**@user1**")
|
||||
assert extracted['mentions'] == [user]
|
||||
|
||||
def test_proccessor_valid_email():
|
||||
result = render(dummy_project, "**beta.tester@taiga.io**")
|
||||
expected_result = "<p><strong><a href=\"mailto:beta.tester@taiga.io\" target=\"_blank\">beta.tester@taiga.io</a></strong></p>"
|
||||
assert result == expected_result
|
||||
|
|
|
@ -333,3 +333,26 @@ def test_valid_concurrent_save_for_task_different_fields(client):
|
|||
data = {"version": 1, "description": "test 2"}
|
||||
response = client.patch(url, json.dumps(data), content_type="application/json")
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
|
||||
def test_invalid_save_without_version_parameter(client):
|
||||
user = f.UserFactory.create()
|
||||
project = f.ProjectFactory.create(owner=user)
|
||||
f.MembershipFactory.create(project=project, user=user, is_owner=True)
|
||||
client.login(user)
|
||||
|
||||
mock_path = "taiga.projects.tasks.api.TaskViewSet.pre_conditions_on_save"
|
||||
with patch(mock_path):
|
||||
url = reverse("tasks-list")
|
||||
data = {"subject": "test",
|
||||
"project": project.id,
|
||||
"status": f.TaskStatusFactory.create(project=project).id}
|
||||
response = client.json.post(url, json.dumps(data))
|
||||
assert response.status_code == 201
|
||||
|
||||
task_id = json.loads(response.content)["id"]
|
||||
url = reverse("tasks-detail", args=(task_id,))
|
||||
data = {"subject": "test 1"}
|
||||
response = client.patch(url, json.dumps(data), content_type="application/json")
|
||||
assert response.status_code == 400
|
||||
|
|
|
@ -214,6 +214,25 @@ def test_archived_filter(client):
|
|||
assert len(json.loads(response.content)) == 1
|
||||
|
||||
|
||||
def test_filter_by_multiple_status(client):
|
||||
user = f.UserFactory.create()
|
||||
project = f.ProjectFactory.create(owner=user)
|
||||
f.MembershipFactory.create(project=project, user=user, is_owner=True)
|
||||
f.UserStoryFactory.create(project=project)
|
||||
us1 = f.UserStoryFactory.create(project=project)
|
||||
us2 = f.UserStoryFactory.create(project=project)
|
||||
|
||||
client.login(user)
|
||||
|
||||
url = reverse("userstories-list")
|
||||
url = "{}?status={},{}".format(reverse("userstories-list"), us1.status.id, us2.status.id)
|
||||
|
||||
|
||||
data = {}
|
||||
response = client.get(url, data)
|
||||
assert len(json.loads(response.content)) == 2
|
||||
|
||||
|
||||
def test_get_total_points(client):
|
||||
project = f.ProjectFactory.create()
|
||||
|
||||
|
|
|
@ -57,13 +57,6 @@ def test_add_to_objects_timeline():
|
|||
service.push_to_timeline(None, project, "test")
|
||||
|
||||
|
||||
def test_modify_created_timeline_entry():
|
||||
timeline = Timeline()
|
||||
timeline.pk = 3
|
||||
with pytest.raises(ValidationError):
|
||||
timeline.save()
|
||||
|
||||
|
||||
def test_get_impl_key_from_model():
|
||||
assert service._get_impl_key_from_model(Timeline, "test") == "timeline.timeline.test"
|
||||
with pytest.raises(Exception):
|
||||
|
|
Loading…
Reference in New Issue