diff --git a/taiga/auth/api.py b/taiga/auth/api.py index 2663b3e0..48c1041d 100644 --- a/taiga/auth/api.py +++ b/taiga/auth/api.py @@ -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 diff --git a/taiga/auth/backends.py b/taiga/auth/backends.py index b514f1e7..7f156c08 100644 --- a/taiga/auth/backends.py +++ b/taiga/auth/backends.py @@ -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,8 +82,8 @@ 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) def authenticate_header(self, request): diff --git a/taiga/auth/tokens.py b/taiga/auth/tokens.py index 680e70fc..75d36e21 100644 --- a/taiga/auth/tokens.py +++ b/taiga/auth/tokens.py @@ -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: diff --git a/taiga/base/api/generics.py b/taiga/base/api/generics.py index 752ae201..a5b40c18 100644 --- a/taiga/base/api/generics.py +++ b/taiga/base/api/generics.py @@ -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): diff --git a/taiga/base/api/permissions.py b/taiga/base/api/permissions.py index 95f8028d..ff1f8bef 100644 --- a/taiga/base/api/permissions.py +++ b/taiga/base/api/permissions.py @@ -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() diff --git a/taiga/base/api/views.py b/taiga/base/api/views.py index 638245a0..26cc5970 100644 --- a/taiga/base/api/views.py +++ b/taiga/base/api/views.py @@ -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) diff --git a/taiga/base/api/viewsets.py b/taiga/base/api/viewsets.py index edb8cfff..b2fbdd50 100644 --- a/taiga/base/api/viewsets.py +++ b/taiga/base/api/viewsets.py @@ -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): diff --git a/taiga/base/apps.py b/taiga/base/apps.py index 1b6c9027..f2719c55 100644 --- a/taiga/base/apps.py +++ b/taiga/base/apps.py @@ -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() - diff --git a/taiga/base/connectors/exceptions.py b/taiga/base/connectors/exceptions.py index ae2cf2bb..1619abba 100644 --- a/taiga/base/connectors/exceptions.py +++ b/taiga/base/connectors/exceptions.py @@ -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.") diff --git a/taiga/base/decorators.py b/taiga/base/decorators.py index bf706df3..d11b97f9 100644 --- a/taiga/base/decorators.py +++ b/taiga/base/decorators.py @@ -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 diff --git a/taiga/base/exceptions.py b/taiga/base/exceptions.py index 3eb05f5f..2d3d5f33 100644 --- a/taiga/base/exceptions.py +++ b/taiga/base/exceptions.py @@ -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): diff --git a/taiga/base/filters.py b/taiga/base/filters.py index fa6ff9b8..5b487496 100644 --- a/taiga/base/filters.py +++ b/taiga/base/filters.py @@ -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 diff --git a/taiga/base/management/commands/test_emails.py b/taiga/base/management/commands/test_emails.py index 6b7f8bf5..29752dd4 100644 --- a/taiga/base/management/commands/test_emails.py +++ b/taiga/base/management/commands/test_emails.py @@ -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: diff --git a/taiga/base/middleware/cors.py b/taiga/base/middleware/cors.py index 03145e10..83031b73 100644 --- a/taiga/base/middleware/cors.py +++ b/taiga/base/middleware/cors.py @@ -14,8 +14,6 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -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) diff --git a/taiga/base/monkey.py b/taiga/base/monkey.py index 91d1be35..c956cab4 100644 --- a/taiga/base/monkey.py +++ b/taiga/base/monkey.py @@ -15,7 +15,7 @@ # along with this program. If not, see . from __future__ import print_function -import sys + def patch_serializer(): from rest_framework import serializers diff --git a/taiga/base/neighbors.py b/taiga/base/neighbors.py index d803b4ae..80ee6844 100644 --- a/taiga/base/neighbors.py +++ b/taiga/base/neighbors.py @@ -15,10 +15,8 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -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] diff --git a/taiga/base/storage.py b/taiga/base/storage.py index 1b99f53f..acf93306 100644 --- a/taiga/base/storage.py +++ b/taiga/base/storage.py @@ -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) diff --git a/taiga/base/tags.py b/taiga/base/tags.py index 9575f090..4b7c6409 100644 --- a/taiga/base/tags.py +++ b/taiga/base/tags.py @@ -15,9 +15,6 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -import re -from functools import partial - from django.db import models from django.utils.translation import ugettext_lazy as _ diff --git a/taiga/base/utils/db.py b/taiga/base/utils/db.py index 02f25d11..a9663751 100644 --- a/taiga/base/utils/db.py +++ b/taiga/base/utils/db.py @@ -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. diff --git a/taiga/base/utils/dicts.py b/taiga/base/utils/dicts.py index 2d7e7077..512a044d 100644 --- a/taiga/base/utils/dicts.py +++ b/taiga/base/utils/dicts.py @@ -16,6 +16,7 @@ import collections + def dict_sum(*args): result = collections.Counter() for arg in args: diff --git a/taiga/base/utils/functions.py b/taiga/base/utils/functions.py index 5c8fae97..d20f824a 100644 --- a/taiga/base/utils/functions.py +++ b/taiga/base/utils/functions.py @@ -15,6 +15,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . + def noop(*args, **kwargs): """The noop function.""" return None diff --git a/taiga/base/utils/json.py b/taiga/base/utils/json.py index bb8dde78..9404febd 100644 --- a/taiga/base/utils/json.py +++ b/taiga/base/utils/json.py @@ -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) diff --git a/taiga/base/utils/sequence.py b/taiga/base/utils/sequence.py index bdec27b6..18af3e2f 100644 --- a/taiga/base/utils/sequence.py +++ b/taiga/base/utils/sequence.py @@ -20,6 +20,7 @@ def first(iterable): return None return iterable[0] + def next(data:list): return data[1:] diff --git a/taiga/base/utils/signals.py b/taiga/base/utils/signals.py index 9a457fe0..64cc580a 100644 --- a/taiga/base/utils/signals.py +++ b/taiga/base/utils/signals.py @@ -36,4 +36,3 @@ def without_signals(*disablers): for disabler in disablers: signal, *ids = disabler signal.receivers = signal.backup_receivers - diff --git a/taiga/base/utils/slug.py b/taiga/base/utils/slug.py index d017664a..03b95767 100644 --- a/taiga/base/utils/slug.py +++ b/taiga/base/utils/slug.py @@ -14,7 +14,6 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from django.utils import baseconv from django.template.defaultfilters import slugify as django_slugify import time diff --git a/taiga/events/middleware.py b/taiga/events/middleware.py index c222d9f9..9dbfb103 100644 --- a/taiga/events/middleware.py +++ b/taiga/events/middleware.py @@ -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 diff --git a/taiga/export_import/api.py b/taiga/export_import/api.py index edf8911d..f05993df 100644 --- a/taiga/export_import/api.py +++ b/taiga/export_import/api.py @@ -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()) diff --git a/taiga/export_import/dump_service.py b/taiga/export_import/dump_service.py index b300ab84..09a9f0d9 100644 --- a/taiga/export_import/dump_service.py +++ b/taiga/export_import/dump_service.py @@ -14,8 +14,6 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from django.db.models import signals - from taiga.projects.models import Membership from . import serializers diff --git a/taiga/export_import/management/commands/load_dump.py b/taiga/export_import/management/commands/load_dump.py index 3840e349..4566cf88 100644 --- a/taiga/export_import/management/commands/load_dump.py +++ b/taiga/export_import/management/commands/load_dump.py @@ -14,19 +14,19 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -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 = ' ' 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): diff --git a/taiga/export_import/renderers.py b/taiga/export_import/renderers.py index 3d906f7a..8f540d07 100644 --- a/taiga/export_import/renderers.py +++ b/taiga/export_import/renderers.py @@ -16,5 +16,6 @@ from rest_framework.renderers import UnicodeJSONRenderer + class ExportRenderer(UnicodeJSONRenderer): pass diff --git a/taiga/export_import/tasks.py b/taiga/export_import/tasks.py index 3158f7ba..635eb63e 100644 --- a/taiga/export_import/tasks.py +++ b/taiga/export_import/tasks.py @@ -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, diff --git a/taiga/export_import/throttling.py b/taiga/export_import/throttling.py index 77b1bb34..a59d7e33 100644 --- a/taiga/export_import/throttling.py +++ b/taiga/export_import/throttling.py @@ -20,5 +20,6 @@ from taiga.base import throttling class ImportModeRateThrottle(throttling.UserRateThrottle): scope = "import-mode" + class ImportDumpModeRateThrottle(throttling.UserRateThrottle): scope = "import-dump-mode" diff --git a/taiga/hooks/bitbucket/api.py b/taiga/hooks/bitbucket/api.py index a73e9958..562b5763 100644 --- a/taiga/hooks/bitbucket/api.py +++ b/taiga/hooks/bitbucket/api.py @@ -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 diff --git a/taiga/hooks/bitbucket/event_hooks.py b/taiga/hooks/bitbucket/event_hooks.py index a149923d..d82d3d4e 100644 --- a/taiga/hooks/bitbucket/event_hooks.py +++ b/taiga/hooks/bitbucket/event_hooks.py @@ -15,12 +15,11 @@ # along with this program. If not, see . 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: diff --git a/taiga/hooks/bitbucket/migrations/0001_initial.py b/taiga/hooks/bitbucket/migrations/0001_initial.py index 372d93bb..9836b8d5 100644 --- a/taiga/hooks/bitbucket/migrations/0001_initial.py +++ b/taiga/hooks/bitbucket/migrations/0001_initial.py @@ -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 diff --git a/taiga/hooks/bitbucket/services.py b/taiga/hooks/bitbucket/services.py index bcb74f56..625c91a8 100644 --- a/taiga/hooks/bitbucket/services.py +++ b/taiga/hooks/bitbucket/services.py @@ -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 diff --git a/taiga/hooks/github/api.py b/taiga/hooks/github/api.py index 767aefd4..8251858f 100644 --- a/taiga/hooks/github/api.py +++ b/taiga/hooks/github/api.py @@ -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): diff --git a/taiga/hooks/github/event_hooks.py b/taiga/hooks/github/event_hooks.py index d7231d72..8123bf00 100644 --- a/taiga/hooks/github/event_hooks.py +++ b/taiga/hooks/github/event_hooks.py @@ -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 diff --git a/taiga/hooks/github/migrations/0001_initial.py b/taiga/hooks/github/migrations/0001_initial.py index 75e43abf..ba41a989 100644 --- a/taiga/hooks/github/migrations/0001_initial.py +++ b/taiga/hooks/github/migrations/0001_initial.py @@ -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 diff --git a/taiga/hooks/github/services.py b/taiga/hooks/github/services.py index a02482af..e7924734 100644 --- a/taiga/hooks/github/services.py +++ b/taiga/hooks/github/services.py @@ -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 diff --git a/taiga/hooks/gitlab/api.py b/taiga/hooks/gitlab/api.py index 1f776b8e..01e455c5 100644 --- a/taiga/hooks/gitlab/api.py +++ b/taiga/hooks/gitlab/api.py @@ -14,7 +14,6 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from django.utils.translation import ugettext_lazy as _ from django.conf import settings from ipware.ip import get_real_ip diff --git a/taiga/hooks/gitlab/event_hooks.py b/taiga/hooks/gitlab/event_hooks.py index 3a84a20d..426ab259 100644 --- a/taiga/hooks/gitlab/event_hooks.py +++ b/taiga/hooks/gitlab/event_hooks.py @@ -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 diff --git a/taiga/hooks/gitlab/migrations/0001_initial.py b/taiga/hooks/gitlab/migrations/0001_initial.py index 683d3956..8002d965 100644 --- a/taiga/hooks/gitlab/migrations/0001_initial.py +++ b/taiga/hooks/gitlab/migrations/0001_initial.py @@ -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 diff --git a/taiga/mdrender/extensions/wikilinks.py b/taiga/mdrender/extensions/wikilinks.py index b2f58df2..1c16ae54 100644 --- a/taiga/mdrender/extensions/wikilinks.py +++ b/taiga/mdrender/extensions/wikilinks.py @@ -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 diff --git a/taiga/mdrender/service.py b/taiga/mdrender/service.py index 19715404..f4c12108 100644 --- a/taiga/mdrender/service.py +++ b/taiga/mdrender/service.py @@ -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 diff --git a/taiga/timeline/api.py b/taiga/timeline/api.py index 4d907a69..4845b82a 100644 --- a/taiga/timeline/api.py +++ b/taiga/timeline/api.py @@ -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): diff --git a/taiga/timeline/apps.py b/taiga/timeline/apps.py index 3b0d7d90..c5d8e4a2 100644 --- a/taiga/timeline/apps.py +++ b/taiga/timeline/apps.py @@ -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")) - - diff --git a/taiga/timeline/permissions.py b/taiga/timeline/permissions.py index 95110a61..f07ee929 100644 --- a/taiga/timeline/permissions.py +++ b/taiga/timeline/permissions.py @@ -15,7 +15,7 @@ # along with this program. If not, see . from taiga.base.api.permissions import (TaigaResourcePermission, HasProjectPerm, - IsProjectOwner, AllowAny) + AllowAny) class UserTimelinePermission(TaigaResourcePermission): diff --git a/taiga/userstorage/api.py b/taiga/userstorage/api.py index 1ed184a9..31324c17 100644 --- a/taiga/userstorage/api.py +++ b/taiga/userstorage/api.py @@ -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 diff --git a/taiga/userstorage/filters.py b/taiga/userstorage/filters.py index 265d7fb3..a46b1e61 100644 --- a/taiga/userstorage/filters.py +++ b/taiga/userstorage/filters.py @@ -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) diff --git a/taiga/userstorage/models.py b/taiga/userstorage/models.py index 15da5992..70dfb9ab 100644 --- a/taiga/userstorage/models.py +++ b/taiga/userstorage/models.py @@ -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, diff --git a/taiga/webhooks/api.py b/taiga/webhooks/api.py index 55f3fca4..cda88dd7 100644 --- a/taiga/webhooks/api.py +++ b/taiga/webhooks/api.py @@ -14,14 +14,11 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -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 diff --git a/taiga/webhooks/migrations/0004_auto_20150202_0834.py b/taiga/webhooks/migrations/0004_auto_20150202_0834.py index 0517c952..434eefce 100644 --- a/taiga/webhooks/migrations/0004_auto_20150202_0834.py +++ b/taiga/webhooks/migrations/0004_auto_20150202_0834.py @@ -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): diff --git a/taiga/webhooks/models.py b/taiga/webhooks/models.py index 6154b523..41f6fc84 100644 --- a/taiga/webhooks/models.py +++ b/taiga/webhooks/models.py @@ -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")) diff --git a/taiga/webhooks/serializers.py b/taiga/webhooks/serializers.py index ec087484..613e832a 100644 --- a/taiga/webhooks/serializers.py +++ b/taiga/webhooks/serializers.py @@ -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") diff --git a/taiga/webhooks/tasks.py b/taiga/webhooks/tasks.py index 7a0f6dcd..2692d15c 100644 --- a/taiga/webhooks/tasks.py +++ b/taiga/webhooks/tasks.py @@ -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) -