Merge pull request #266 from taigaio/more-flake8-fixes
Some flake8 fixesremotes/origin/enhancement/email-actions
commit
3dc143149f
|
@ -27,8 +27,6 @@ from taiga.base.decorators import list_route
|
|||
from taiga.base import exceptions as exc
|
||||
from taiga.base import response
|
||||
|
||||
from taiga.users.services import get_and_validate_user
|
||||
|
||||
from .serializers import PublicRegisterSerializer
|
||||
from .serializers import PrivateRegisterForExistingUserSerializer
|
||||
from .serializers import PrivateRegisterForNewUserSerializer
|
||||
|
|
|
@ -32,7 +32,6 @@ selfcontained tokens. This trust tokes from external
|
|||
fraudulent modifications.
|
||||
"""
|
||||
|
||||
import base64
|
||||
import re
|
||||
|
||||
from django.conf import settings
|
||||
|
@ -40,6 +39,7 @@ from rest_framework.authentication import BaseAuthentication
|
|||
|
||||
from .tokens import get_user_for_token
|
||||
|
||||
|
||||
class Session(BaseAuthentication):
|
||||
"""
|
||||
Session based authentication like the standard
|
||||
|
@ -82,7 +82,7 @@ class Token(BaseAuthentication):
|
|||
token = token_rx_match.group(1)
|
||||
max_age_auth_token = getattr(settings, "MAX_AGE_AUTH_TOKEN", None)
|
||||
user = get_user_for_token(token, "authentication",
|
||||
max_age=max_age_auth_token)
|
||||
max_age=max_age_auth_token)
|
||||
|
||||
return (user, token)
|
||||
|
||||
|
|
|
@ -19,12 +19,13 @@ from taiga.base import exceptions as exc
|
|||
from django.apps import apps
|
||||
from django.core import signing
|
||||
|
||||
|
||||
def get_token_for_user(user, scope):
|
||||
"""
|
||||
Generate a new signed token containing
|
||||
a specified user limited for a scope (identified as a string).
|
||||
"""
|
||||
data = {"user_%s_id"%(scope): user.id}
|
||||
data = {"user_%s_id" % (scope): user.id}
|
||||
return signing.dumps(data)
|
||||
|
||||
|
||||
|
@ -47,7 +48,7 @@ def get_user_for_token(token, scope, max_age=None):
|
|||
model_cls = apps.get_model("users", "User")
|
||||
|
||||
try:
|
||||
user = model_cls.objects.get(pk=data["user_%s_id"%(scope)])
|
||||
user = model_cls.objects.get(pk=data["user_%s_id" % (scope)])
|
||||
except (model_cls.DoesNotExist, KeyError):
|
||||
raise exc.NotAuthenticated("Invalid token")
|
||||
else:
|
||||
|
|
|
@ -19,13 +19,11 @@
|
|||
|
||||
import warnings
|
||||
|
||||
from django.core.exceptions import ImproperlyConfigured, PermissionDenied
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.core.paginator import Paginator, InvalidPage
|
||||
from django.http import Http404
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from rest_framework import exceptions
|
||||
from rest_framework.request import clone_request
|
||||
from rest_framework.settings import api_settings
|
||||
|
||||
from . import views
|
||||
|
@ -166,8 +164,8 @@ class GenericAPIView(views.APIView):
|
|||
page = paginator.page(page_number)
|
||||
except InvalidPage as e:
|
||||
raise Http404(_('Invalid page (%(page_number)s): %(message)s') % {
|
||||
'page_number': page_number,
|
||||
'message': str(e)
|
||||
'page_number': page_number,
|
||||
'message': str(e)
|
||||
})
|
||||
|
||||
if deprecated_style:
|
||||
|
@ -193,16 +191,16 @@ class GenericAPIView(views.APIView):
|
|||
"""
|
||||
filter_backends = self.filter_backends or []
|
||||
if not filter_backends and hasattr(self, 'filter_backend'):
|
||||
raise RuntimeException('The `filter_backend` attribute and `FILTER_BACKEND` setting '
|
||||
'are due to be deprecated in favor of a `filter_backends` '
|
||||
'attribute and `DEFAULT_FILTER_BACKENDS` setting, that take '
|
||||
'a *list* of filter backend classes.')
|
||||
raise RuntimeError('The `filter_backend` attribute and `FILTER_BACKEND` setting '
|
||||
'are due to be deprecated in favor of a `filter_backends` '
|
||||
'attribute and `DEFAULT_FILTER_BACKENDS` setting, that take '
|
||||
'a *list* of filter backend classes.')
|
||||
return filter_backends
|
||||
|
||||
|
||||
########################
|
||||
### The following methods provide default implementations
|
||||
### that you may want to override for more complex cases.
|
||||
###########################################################
|
||||
# The following methods provide default implementations #
|
||||
# that you may want to override for more complex cases. #
|
||||
###########################################################
|
||||
|
||||
def get_paginate_by(self, queryset=None):
|
||||
"""
|
||||
|
@ -214,8 +212,8 @@ class GenericAPIView(views.APIView):
|
|||
Otherwise defaults to using `self.paginate_by`.
|
||||
"""
|
||||
if queryset is not None:
|
||||
raise RuntimeException('The `queryset` parameter to `get_paginate_by()` '
|
||||
'is due to be deprecated.')
|
||||
raise RuntimeError('The `queryset` parameter to `get_paginate_by()` '
|
||||
'is due to be deprecated.')
|
||||
if self.paginate_by_param:
|
||||
try:
|
||||
return strict_positive_int(
|
||||
|
@ -263,8 +261,7 @@ class GenericAPIView(views.APIView):
|
|||
if self.model is not None:
|
||||
return self.model._default_manager.all()
|
||||
|
||||
raise ImproperlyConfigured("'%s' must define 'queryset' or 'model'"
|
||||
% self.__class__.__name__)
|
||||
raise ImproperlyConfigured("'%s' must define 'queryset' or 'model'" % self.__class__.__name__)
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
"""
|
||||
|
@ -280,7 +277,7 @@ class GenericAPIView(views.APIView):
|
|||
else:
|
||||
# NOTE: explicit exception for avoid and fix
|
||||
# usage of deprecated way of get_object
|
||||
raise RuntimeException("DEPRECATED")
|
||||
raise RuntimeError("DEPRECATED")
|
||||
|
||||
# Perform the lookup filtering.
|
||||
# Note that `pk` and `slug` are deprecated styles of lookup filtering.
|
||||
|
@ -292,11 +289,11 @@ class GenericAPIView(views.APIView):
|
|||
if lookup is not None:
|
||||
filter_kwargs = {self.lookup_field: lookup}
|
||||
elif pk is not None and self.lookup_field == 'pk':
|
||||
raise RuntimeException('The `pk_url_kwarg` attribute is due to be deprecated. '
|
||||
'Use the `lookup_field` attribute instead')
|
||||
raise RuntimeError('The `pk_url_kwarg` attribute is due to be deprecated. '
|
||||
'Use the `lookup_field` attribute instead')
|
||||
elif slug is not None and self.lookup_field == 'pk':
|
||||
raise RuntimeException('The `slug_url_kwarg` attribute is due to be deprecated. '
|
||||
'Use the `lookup_field` attribute instead')
|
||||
raise RuntimeError('The `slug_url_kwarg` attribute is due to be deprecated. '
|
||||
'Use the `lookup_field` attribute instead')
|
||||
else:
|
||||
raise ImproperlyConfigured(
|
||||
'Expected view %s to be called with a URL keyword argument '
|
||||
|
@ -314,12 +311,13 @@ class GenericAPIView(views.APIView):
|
|||
except Http404:
|
||||
return None
|
||||
|
||||
########################
|
||||
### The following are placeholder methods,
|
||||
### and are intended to be overridden.
|
||||
###
|
||||
### The are not called by GenericAPIView directly,
|
||||
### but are used by the mixin methods.
|
||||
###################################################
|
||||
# The following are placeholder methods, #
|
||||
# and are intended to be overridden. #
|
||||
# #
|
||||
# The are not called by GenericAPIView directly, #
|
||||
# but are used by the mixin methods. #
|
||||
###################################################
|
||||
|
||||
def pre_conditions_on_save(self, obj):
|
||||
"""
|
||||
|
@ -363,11 +361,11 @@ class GenericAPIView(views.APIView):
|
|||
pass
|
||||
|
||||
|
||||
##########################################################
|
||||
### Concrete view classes that provide method handlers ###
|
||||
### by composing the mixin classes with the base view. ###
|
||||
### NOTE: not used by taiga. ###
|
||||
##########################################################
|
||||
######################################################
|
||||
# Concrete view classes that provide method handlers #
|
||||
# by composing the mixin classes with the base view. #
|
||||
# NOTE: not used by taiga. #
|
||||
######################################################
|
||||
|
||||
class CreateAPIView(mixins.CreateModelMixin,
|
||||
GenericAPIView):
|
||||
|
|
|
@ -219,8 +219,10 @@ class IsObjectOwner(PermissionComponent):
|
|||
class AllowAnyPermission(ResourcePermission):
|
||||
enought_perms = AllowAny()
|
||||
|
||||
|
||||
class IsAuthenticatedPermission(ResourcePermission):
|
||||
enought_perms = IsAuthenticated()
|
||||
|
||||
|
||||
class TaigaResourcePermission(ResourcePermission):
|
||||
enought_perms = IsSuperUser()
|
||||
|
|
|
@ -56,6 +56,7 @@ def get_view_name(view_cls, suffix=None):
|
|||
|
||||
return name
|
||||
|
||||
|
||||
def get_view_description(view_cls, html=False):
|
||||
"""
|
||||
Given a view class, return a textual description to represent the view.
|
||||
|
@ -141,7 +142,6 @@ class APIView(View):
|
|||
headers['Vary'] = 'Accept'
|
||||
return headers
|
||||
|
||||
|
||||
def http_method_not_allowed(self, request, *args, **kwargs):
|
||||
"""
|
||||
If `request.method` does not correspond to a handler method,
|
||||
|
@ -445,7 +445,7 @@ class APIView(View):
|
|||
|
||||
|
||||
def api_server_error(request, *args, **kwargs):
|
||||
if settings.DEBUG == False and request.META['CONTENT_TYPE'] == "application/json":
|
||||
if settings.DEBUG is False and request.META['CONTENT_TYPE'] == "application/json":
|
||||
return HttpResponse(json.dumps({"error": "Server application error"}),
|
||||
status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
return server_error(request, *args, **kwargs)
|
||||
|
|
|
@ -124,6 +124,7 @@ class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
|
|||
"""
|
||||
pass
|
||||
|
||||
|
||||
class ReadOnlyListViewSet(pagination.HeadersPaginationMixin,
|
||||
pagination.ConditionalPaginationMixin,
|
||||
GenericViewSet):
|
||||
|
@ -132,6 +133,7 @@ class ReadOnlyListViewSet(pagination.HeadersPaginationMixin,
|
|||
"""
|
||||
pass
|
||||
|
||||
|
||||
class ReadOnlyModelViewSet(mixins.RetrieveModelMixin,
|
||||
mixins.ListModelMixin,
|
||||
GenericViewSet):
|
||||
|
|
|
@ -20,6 +20,7 @@ import sys
|
|||
from django.apps import AppConfig
|
||||
from . import monkey
|
||||
|
||||
|
||||
class BaseAppConfig(AppConfig):
|
||||
name = "taiga.base"
|
||||
verbose_name = "Base App Config"
|
||||
|
@ -28,4 +29,3 @@ class BaseAppConfig(AppConfig):
|
|||
print("Monkey patching...", file=sys.stderr)
|
||||
monkey.patch_restframework()
|
||||
monkey.patch_serializer()
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ from taiga.base.exceptions import BaseException
|
|||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
class ConnectorBaseException(BaseException):
|
||||
status_code = 400
|
||||
default_detail = _("Connection error.")
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
import warnings
|
||||
|
||||
|
||||
## Rest Framework 2.4 backport some decorators.
|
||||
# Rest Framework 2.4 backport some decorators.
|
||||
|
||||
def detail_route(methods=['get'], **kwargs):
|
||||
"""
|
||||
|
@ -51,12 +51,14 @@ def link(**kwargs):
|
|||
"""
|
||||
msg = 'link is pending deprecation. Use detail_route instead.'
|
||||
warnings.warn(msg, PendingDeprecationWarning, stacklevel=2)
|
||||
|
||||
def decorator(func):
|
||||
func.bind_to_methods = ['get']
|
||||
func.detail = True
|
||||
func.permission_classes = kwargs.get('permission_classes', [])
|
||||
func.kwargs = kwargs
|
||||
return func
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
|
@ -66,10 +68,12 @@ def action(methods=['post'], **kwargs):
|
|||
"""
|
||||
msg = 'action is pending deprecation. Use detail_route instead.'
|
||||
warnings.warn(msg, PendingDeprecationWarning, stacklevel=2)
|
||||
|
||||
def decorator(func):
|
||||
func.bind_to_methods = methods
|
||||
func.detail = True
|
||||
func.permission_classes = kwargs.get('permission_classes', [])
|
||||
func.kwargs = kwargs
|
||||
return func
|
||||
|
||||
return decorator
|
||||
|
|
|
@ -23,7 +23,6 @@ from django.utils.translation import ugettext_lazy as _
|
|||
from django.http import Http404
|
||||
|
||||
from taiga.base import response
|
||||
from taiga.base.utils.json import to_json
|
||||
|
||||
|
||||
class BaseException(exceptions.APIException):
|
||||
|
|
|
@ -102,7 +102,8 @@ class PermissionBasedFilterBackend(FilterBackend):
|
|||
project_id = int(request.QUERY_PARAMS["project"])
|
||||
except:
|
||||
logger.error("Filtering project diferent value than an integer: {}".format(
|
||||
request.QUERY_PARAMS["project"]))
|
||||
request.QUERY_PARAMS["project"]
|
||||
))
|
||||
raise exc.BadRequest("'project' must be an integer value.")
|
||||
|
||||
qs = queryset
|
||||
|
@ -190,7 +191,8 @@ class CanViewProjectObjFilterBackend(FilterBackend):
|
|||
project_id = int(request.QUERY_PARAMS["project"])
|
||||
except:
|
||||
logger.error("Filtering project diferent value than an integer: {}".format(
|
||||
request.QUERY_PARAMS["project"]))
|
||||
request.QUERY_PARAMS["project"]
|
||||
))
|
||||
raise exc.BadRequest("'project' must be an integer value.")
|
||||
|
||||
qs = queryset
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
import datetime
|
||||
|
||||
from django.db.models.loading import get_model
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.utils import timezone
|
||||
|
||||
from djmail.template_mail import MagicMailBuilder, InlineCSSTemplateMail
|
||||
|
@ -139,10 +139,10 @@ class Command(BaseCommand):
|
|||
]
|
||||
|
||||
context = {
|
||||
"project": Project.objects.all().order_by("?").first(),
|
||||
"changer": User.objects.all().order_by("?").first(),
|
||||
"history_entries": HistoryEntry.objects.all().order_by("?")[0:5],
|
||||
"user": User.objects.all().order_by("?").first(),
|
||||
"project": Project.objects.all().order_by("?").first(),
|
||||
"changer": User.objects.all().order_by("?").first(),
|
||||
"history_entries": HistoryEntry.objects.all().order_by("?")[0:5],
|
||||
"user": User.objects.all().order_by("?").first(),
|
||||
}
|
||||
|
||||
for notification_email in notification_emails:
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import json
|
||||
|
||||
from django import http
|
||||
|
||||
|
||||
|
@ -33,7 +31,7 @@ COORS_EXPOSE_HEADERS = ["x-pagination-count", "x-paginated", "x-paginated-by",
|
|||
|
||||
class CoorsMiddleware(object):
|
||||
def _populate_response(self, response):
|
||||
response["Access-Control-Allow-Origin"] = COORS_ALLOWED_ORIGINS
|
||||
response["Access-Control-Allow-Origin"] = COORS_ALLOWED_ORIGINS
|
||||
response["Access-Control-Allow-Methods"] = ",".join(COORS_ALLOWED_METHODS)
|
||||
response["Access-Control-Allow-Headers"] = ",".join(COORS_ALLOWED_HEADERS)
|
||||
response["Access-Control-Expose-Headers"] = ",".join(COORS_EXPOSE_HEADERS)
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import print_function
|
||||
import sys
|
||||
|
||||
|
||||
def patch_serializer():
|
||||
from rest_framework import serializers
|
||||
|
|
|
@ -15,10 +15,8 @@
|
|||
# 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 functools import partial
|
||||
from collections import namedtuple
|
||||
|
||||
from django.db.models import Q
|
||||
from django.db import connection
|
||||
|
||||
Neighbor = namedtuple("Neighbor", "left right")
|
||||
|
@ -46,7 +44,7 @@ def get_neighbors(obj, results_set=None):
|
|||
(SELECT "id" as id, ROW_NUMBER() OVER()
|
||||
FROM (%s) as ID_AND_ROW)
|
||||
AS SELECTED_ID_AND_ROW
|
||||
"""%(base_sql)
|
||||
""" % (base_sql)
|
||||
query += " WHERE id=%s;"
|
||||
params = list(base_params) + [obj.id]
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ from django.core.files import storage
|
|||
|
||||
import django_sites as sites
|
||||
|
||||
|
||||
class FileSystemStorage(storage.FileSystemStorage):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
|
|
@ -15,9 +15,6 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import re
|
||||
from functools import partial
|
||||
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ def get_typename_for_model_class(model:object, for_concrete_model=True) -> str:
|
|||
|
||||
return "{0}.{1}".format(model._meta.app_label, model._meta.model_name)
|
||||
|
||||
|
||||
def get_typename_for_model_instance(model_instance):
|
||||
"""
|
||||
Get content type tuple from model instance.
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
import collections
|
||||
|
||||
|
||||
def dict_sum(*args):
|
||||
result = collections.Counter()
|
||||
for arg in args:
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
# 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/>.
|
||||
|
||||
|
||||
def noop(*args, **kwargs):
|
||||
"""The noop function."""
|
||||
return None
|
||||
|
|
|
@ -22,6 +22,7 @@ from django.utils.encoding import force_text
|
|||
def dumps(data, ensure_ascii=True, encoder_class=encoders.JSONEncoder):
|
||||
return json.dumps(data, cls=encoder_class, indent=None, ensure_ascii=ensure_ascii)
|
||||
|
||||
|
||||
def loads(data):
|
||||
if isinstance(data, bytes):
|
||||
data = force_text(data)
|
||||
|
|
|
@ -20,6 +20,7 @@ def first(iterable):
|
|||
return None
|
||||
return iterable[0]
|
||||
|
||||
|
||||
def next(data:list):
|
||||
return data[1:]
|
||||
|
||||
|
|
|
@ -36,4 +36,3 @@ def without_signals(*disablers):
|
|||
for disabler in disablers:
|
||||
signal, *ids = disabler
|
||||
signal.receivers = signal.backup_receivers
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
# 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.utils import baseconv
|
||||
from django.template.defaultfilters import slugify as django_slugify
|
||||
|
||||
import time
|
||||
|
|
|
@ -30,9 +30,9 @@ def get_current_session_id() -> str:
|
|||
|
||||
global _local
|
||||
if not hasattr(_local, "session_id"):
|
||||
raise RuntimeException("No session identifier is found, "
|
||||
"ara you sure that session id middleware "
|
||||
"is active?")
|
||||
raise RuntimeError("No session identifier is found, "
|
||||
"are you sure that session id middleware "
|
||||
"is active?")
|
||||
return _local.session_id
|
||||
|
||||
|
||||
|
|
|
@ -26,8 +26,6 @@ from django.conf import settings
|
|||
from django.core.files.storage import default_storage
|
||||
from django.core.files.base import ContentFile
|
||||
|
||||
from rest_framework.decorators import throttle_classes
|
||||
|
||||
from taiga.base.decorators import detail_route, list_route
|
||||
from taiga.base import exceptions as exc
|
||||
from taiga.base import response
|
||||
|
@ -70,7 +68,7 @@ class ProjectExporterViewSet(mixins.ImportThrottlingPolicyMixin, GenericViewSet)
|
|||
|
||||
path = "exports/{}/{}-{}.json".format(project.pk, project.slug, uuid.uuid4().hex)
|
||||
content = ContentFile(ExportRenderer().render(service.project_to_dict(project),
|
||||
renderer_context={"indent": 4}).decode('utf-8'))
|
||||
renderer_context={"indent": 4}).decode('utf-8'))
|
||||
|
||||
default_storage.save(path, content)
|
||||
response_data = {
|
||||
|
@ -187,7 +185,6 @@ class ProjectImporterViewSet(mixins.ImportThrottlingPolicyMixin, CreateModelMixi
|
|||
response_data = ProjectSerializer(project).data
|
||||
return response.Created(response_data)
|
||||
|
||||
|
||||
@detail_route(methods=['post'])
|
||||
@method_decorator(atomic)
|
||||
def issue(self, request, *args, **kwargs):
|
||||
|
@ -195,7 +192,7 @@ class ProjectImporterViewSet(mixins.ImportThrottlingPolicyMixin, CreateModelMixi
|
|||
self.check_permissions(request, 'import_item', project)
|
||||
|
||||
signals.pre_save.disconnect(sender=Issue,
|
||||
dispatch_uid="set_finished_date_when_edit_issue")
|
||||
dispatch_uid="set_finished_date_when_edit_issue")
|
||||
|
||||
issue = service.store_issue(project, request.DATA.copy())
|
||||
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
# 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 signals
|
||||
|
||||
from taiga.projects.models import Membership
|
||||
|
||||
from . import serializers
|
||||
|
|
|
@ -14,19 +14,19 @@
|
|||
# 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.core.management.base import BaseCommand, CommandError
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import transaction
|
||||
from django.db.models import signals
|
||||
from optparse import make_option
|
||||
|
||||
import json
|
||||
import pprint
|
||||
|
||||
from taiga.projects.models import Project
|
||||
from taiga.export_import.renderers import ExportRenderer
|
||||
from taiga.export_import.dump_service import dict_to_project, TaigaImportError
|
||||
from taiga.export_import.service import get_errors
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
args = '<dump_file> <owner-email>'
|
||||
help = 'Export a project to json'
|
||||
|
@ -34,10 +34,10 @@ class Command(BaseCommand):
|
|||
renderer = ExportRenderer()
|
||||
option_list = BaseCommand.option_list + (
|
||||
make_option('--overwrite',
|
||||
action='store_true',
|
||||
dest='overwrite',
|
||||
default=False,
|
||||
help='Delete project if exists'),
|
||||
action='store_true',
|
||||
dest='overwrite',
|
||||
default=False,
|
||||
help='Delete project if exists'),
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
|
|
|
@ -16,5 +16,6 @@
|
|||
|
||||
from rest_framework.renderers import UnicodeJSONRenderer
|
||||
|
||||
|
||||
class ExportRenderer(UnicodeJSONRenderer):
|
||||
pass
|
||||
|
|
|
@ -53,7 +53,6 @@ def dump_project(self, user, project):
|
|||
email.send()
|
||||
return
|
||||
|
||||
|
||||
deletion_date = timezone.now() + datetime.timedelta(seconds=settings.EXPORTS_TTL)
|
||||
ctx = {
|
||||
"url": url,
|
||||
|
|
|
@ -20,5 +20,6 @@ from taiga.base import throttling
|
|||
class ImportModeRateThrottle(throttling.UserRateThrottle):
|
||||
scope = "import-mode"
|
||||
|
||||
|
||||
class ImportDumpModeRateThrottle(throttling.UserRateThrottle):
|
||||
scope = "import-dump-mode"
|
||||
|
|
|
@ -61,7 +61,7 @@ class BitBucketViewSet(BaseWebhookApiViewSet):
|
|||
valid_origin_ips = bitbucket_config.get("valid_origin_ips",
|
||||
settings.BITBUCKET_VALID_ORIGIN_IPS)
|
||||
origin_ip = get_real_ip(request)
|
||||
if valid_origin_ips and (not origin_ip or not origin_ip in valid_origin_ips):
|
||||
if valid_origin_ips and (not origin_ip or origin_ip not in valid_origin_ips):
|
||||
return False
|
||||
|
||||
return project_secret == secret_key
|
||||
|
|
|
@ -15,12 +15,11 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import re
|
||||
import os
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from taiga.base import exceptions as exc
|
||||
from taiga.projects.models import Project, IssueStatus, TaskStatus, UserStoryStatus
|
||||
from taiga.projects.models import IssueStatus, TaskStatus, UserStoryStatus
|
||||
from taiga.projects.issues.models import Issue
|
||||
from taiga.projects.tasks.models import Task
|
||||
from taiga.projects.userstories.models import UserStory
|
||||
|
@ -33,6 +32,7 @@ from .services import get_bitbucket_user
|
|||
|
||||
import json
|
||||
|
||||
|
||||
class PushEventHook(BaseEventHook):
|
||||
def process_event(self):
|
||||
if self.payload is None:
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.db import migrations
|
||||
from django.core.files import File
|
||||
|
||||
import uuid
|
||||
|
||||
|
||||
def create_github_system_user(apps, schema_editor):
|
||||
# We get the model from the versioned app registry;
|
||||
# if we directly import it, it'll be the wrong version
|
||||
|
|
|
@ -35,7 +35,7 @@ def get_or_generate_config(project):
|
|||
|
||||
url = reverse("bitbucket-hook-list")
|
||||
url = get_absolute_url(url)
|
||||
url = "%s?project=%s&key=%s"%(url, project.id, g_config["secret"])
|
||||
url = "%s?project=%s&key=%s" % (url, project.id, g_config["secret"])
|
||||
g_config["webhooks_url"] = url
|
||||
return g_config
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ class GitHubViewSet(BaseWebhookApiViewSet):
|
|||
|
||||
secret = project.modules_config.config.get("github", {}).get("secret", "")
|
||||
secret = bytes(secret.encode("utf-8"))
|
||||
mac = hmac.new(secret, msg=request.body,digestmod=hashlib.sha1)
|
||||
mac = hmac.new(secret, msg=request.body, digestmod=hashlib.sha1)
|
||||
return hmac.compare_digest(mac.hexdigest(), signature)
|
||||
|
||||
def _get_event_name(self, request):
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from taiga.projects.models import Project, IssueStatus, TaskStatus, UserStoryStatus
|
||||
from taiga.projects.models import IssueStatus, TaskStatus, UserStoryStatus
|
||||
|
||||
from taiga.projects.issues.models import Issue
|
||||
from taiga.projects.tasks.models import Task
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.db import migrations
|
||||
from django.core.files import File
|
||||
|
||||
import uuid
|
||||
|
||||
|
||||
def create_github_system_user(apps, schema_editor):
|
||||
# We get the model from the versioned app registry;
|
||||
# if we directly import it, it'll be the wrong version
|
||||
|
|
|
@ -27,11 +27,11 @@ def get_or_generate_config(project):
|
|||
if config and "github" in config:
|
||||
g_config = project.modules_config.config["github"]
|
||||
else:
|
||||
g_config = {"secret": uuid.uuid4().hex }
|
||||
g_config = {"secret": uuid.uuid4().hex}
|
||||
|
||||
url = reverse("github-hook-list")
|
||||
url = get_absolute_url(url)
|
||||
url = "%s?project=%s"%(url, project.id)
|
||||
url = "%s?project=%s" % (url, project.id)
|
||||
g_config["webhooks_url"] = url
|
||||
return g_config
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
# 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.utils.translation import ugettext_lazy as _
|
||||
from django.conf import settings
|
||||
|
||||
from ipware.ip import get_real_ip
|
||||
|
|
|
@ -19,7 +19,7 @@ import os
|
|||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from taiga.projects.models import Project, IssueStatus, TaskStatus, UserStoryStatus
|
||||
from taiga.projects.models import IssueStatus, TaskStatus, UserStoryStatus
|
||||
|
||||
from taiga.projects.issues.models import Issue
|
||||
from taiga.projects.tasks.models import Task
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.db import migrations
|
||||
from django.core.files import File
|
||||
|
||||
import uuid
|
||||
|
||||
|
||||
def create_github_system_user(apps, schema_editor):
|
||||
# We get the model from the versioned app registry;
|
||||
# if we directly import it, it'll be the wrong version
|
||||
|
|
|
@ -26,6 +26,7 @@ from taiga.base.utils.slug import slugify
|
|||
|
||||
import re
|
||||
|
||||
|
||||
class WikiLinkExtension(Extension):
|
||||
def __init__(self, project, *args, **kwargs):
|
||||
self.project = project
|
||||
|
@ -66,6 +67,7 @@ class WikiLinksPattern(Pattern):
|
|||
|
||||
SLUG_RE = re.compile(r"^[-a-zA-Z0-9_]+$")
|
||||
|
||||
|
||||
class RelativeLinksTreeprocessor(Treeprocessor):
|
||||
def __init__(self, md, project):
|
||||
self.project = project
|
||||
|
|
|
@ -22,6 +22,7 @@ import bleach
|
|||
import html5lib
|
||||
from html5lib.serializer.htmlserializer import HTMLSerializer
|
||||
|
||||
|
||||
def _serialize(domtree):
|
||||
walker = html5lib.treewalkers.getTreeWalker('etree')
|
||||
stream = walker(domtree)
|
||||
|
@ -32,7 +33,7 @@ def _serialize(domtree):
|
|||
return serializer.render(stream)
|
||||
|
||||
bleach._serialize = _serialize
|
||||
### END PATCH
|
||||
# END PATCH
|
||||
|
||||
from django.core.cache import cache
|
||||
from django.utils.encoding import force_bytes
|
||||
|
|
|
@ -23,7 +23,6 @@ from taiga.base.api import GenericViewSet
|
|||
from . import serializers
|
||||
from . import service
|
||||
from . import permissions
|
||||
from . import models
|
||||
|
||||
|
||||
class TimelineViewSet(GenericViewSet):
|
||||
|
|
|
@ -36,5 +36,3 @@ class TimelineAppConfig(AppConfig):
|
|||
sender=apps.get_model("projects", "Membership"))
|
||||
signals.post_delete.connect(handlers.delete_membership_push_to_timeline,
|
||||
sender=apps.get_model("projects", "Membership"))
|
||||
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from taiga.base.api.permissions import (TaigaResourcePermission, HasProjectPerm,
|
||||
IsProjectOwner, AllowAny)
|
||||
AllowAny)
|
||||
|
||||
|
||||
class UserTimelinePermission(TaigaResourcePermission):
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.db import IntegrityError
|
||||
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
|
||||
from taiga.base.api import ModelCrudViewSet
|
||||
from taiga.base import exceptions as exc
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
from taiga.base import filters
|
||||
|
||||
|
||||
class StorageEntriesFilterBackend(filters.FilterBackend):
|
||||
def filter_queryset(self, request, queryset, view):
|
||||
queryset = super().filter_queryset(request, queryset, view)
|
||||
|
|
|
@ -22,7 +22,7 @@ from django_pgjson.fields import JsonField
|
|||
|
||||
class StorageEntry(models.Model):
|
||||
owner = models.ForeignKey(settings.AUTH_USER_MODEL, blank=False, null=False,
|
||||
related_name="storage_entries", verbose_name=_("owner"))
|
||||
related_name="storage_entries", verbose_name=_("owner"))
|
||||
created_date = models.DateTimeField(auto_now_add=True, null=False, blank=False,
|
||||
verbose_name=_("created date"))
|
||||
modified_date = models.DateTimeField(auto_now=True, null=False, blank=False,
|
||||
|
|
|
@ -14,14 +14,11 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import json
|
||||
|
||||
from taiga.base import filters
|
||||
from taiga.base import response
|
||||
from taiga.base.api import ModelCrudViewSet
|
||||
from taiga.base.api import ModelListViewSet
|
||||
|
||||
from taiga.base.api.utils import get_object_or_404
|
||||
from taiga.base.decorators import detail_route
|
||||
|
||||
from . import models
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
|
@ -24,7 +24,7 @@ class Webhook(models.Model):
|
|||
project = models.ForeignKey("projects.Project", null=False, blank=False,
|
||||
related_name="webhooks")
|
||||
name = models.CharField(max_length=250, null=False, blank=False,
|
||||
verbose_name=_("name"))
|
||||
verbose_name=_("name"))
|
||||
url = models.URLField(null=False, blank=False, verbose_name=_("URL"))
|
||||
key = models.TextField(null=False, blank=False, verbose_name=_("secret key"))
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ class HistoryDiffField(serializers.Field):
|
|||
|
||||
class WebhookSerializer(serializers.ModelSerializer):
|
||||
logs_counter = serializers.SerializerMethodField("get_logs_counter")
|
||||
|
||||
class Meta:
|
||||
model = Webhook
|
||||
|
||||
|
@ -61,6 +62,7 @@ class UserSerializer(serializers.Serializer):
|
|||
def get_name(self, obj):
|
||||
return obj.full_name
|
||||
|
||||
|
||||
class PointSerializer(serializers.Serializer):
|
||||
id = serializers.SerializerMethodField("get_pk")
|
||||
name = serializers.SerializerMethodField("get_name")
|
||||
|
|
|
@ -86,7 +86,7 @@ def _send_request(webhook_id, url, key, data):
|
|||
duration=0)
|
||||
session.close()
|
||||
|
||||
ids = [webhook_log.id for webhook_log in WebhookLog.objects.filter(webhook_id=webhook_id).order_by("-id")[10:]]
|
||||
ids = [log.id for log in WebhookLog.objects.filter(webhook_id=webhook_id).order_by("-id")[10:]]
|
||||
WebhookLog.objects.filter(id__in=ids).delete()
|
||||
return webhook_log
|
||||
|
||||
|
@ -135,4 +135,3 @@ def test_webhook(webhook_id, url, key):
|
|||
data['type'] = "test"
|
||||
|
||||
return _send_request(webhook_id, url, key, data)
|
||||
|
||||
|
|
Loading…
Reference in New Issue