diff --git a/CHANGELOG.md b/CHANGELOG.md index 275e949b..734a282d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ - -# 1.0.0 taiga-back (2014-10-07) +# Changelog # + +## 1.1.0 (2014-10-13) + +### Misc +- Fix bugs related to unicode chars on attachments. +- Fix wrong static url resolve usage on emails. +- Fix some bugs on import/export api related with attachments. + +## 1.0.0 (2014-10-07) ### Misc - Lots of small and not so small bugfixes diff --git a/requirements.txt b/requirements.txt index 1fd56ec2..ad35c9ee 100644 --- a/requirements.txt +++ b/requirements.txt @@ -20,9 +20,10 @@ fn==0.2.13 diff-match-patch==20121119 requests==2.4.1 -# Comment it if you are using python >= 3.4 -enum34==1.0 easy-thumbnails==2.1 celery==3.1.12 redis==2.10.3 Unidecode==0.04.16 + +# Comment it if you are using python >= 3.4 +enum34==1.0 diff --git a/taiga/auth/services.py b/taiga/auth/services.py index fe07b1bf..10c4e573 100644 --- a/taiga/auth/services.py +++ b/taiga/auth/services.py @@ -36,7 +36,7 @@ from taiga.users.serializers import UserSerializer from taiga.users.services import get_and_validate_user from .backends import get_token_for_user - +from .signals import user_registered as user_registered_signal def send_public_register_email(user) -> bool: """ @@ -126,6 +126,7 @@ def public_register(username:str, password:str, email:str, full_name:str): raise exc.WrongArguments("User is already register.") # send_public_register_email(user) + user_registered_signal.send(sender=user.__class__, user=user) return user @@ -177,6 +178,7 @@ def private_register_for_new_user(token:str, username:str, email:str, membership = get_membership_by_token(token) membership.user = user membership.save(update_fields=["user"]) + user_registered_signal.send(sender=user.__class__, user=user) return user @@ -202,6 +204,9 @@ def github_register(username:str, email:str, full_name:str, github_id:int, bio:s membership.user = user membership.save(update_fields=["user"]) + if created: + user_registered_signal.send(sender=user.__class__, user=user) + return user diff --git a/taiga/base/templatetags/functions.py b/taiga/auth/signals.py similarity index 81% rename from taiga/base/templatetags/functions.py rename to taiga/auth/signals.py index 678630c0..9c5b9ca0 100644 --- a/taiga/base/templatetags/functions.py +++ b/taiga/auth/signals.py @@ -14,11 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from django_jinja import library -from django_sites.utils import static +import django.dispatch -register = library.Library() -@register.global_function -def full_url_static(text) -> str: - return static(text) +user_registered = django.dispatch.Signal(providing_args=["user"]) diff --git a/taiga/base/templates/emails/base.jinja b/taiga/base/templates/emails/base.jinja index 014b1aed..0138a1b7 100644 --- a/taiga/base/templates/emails/base.jinja +++ b/taiga/base/templates/emails/base.jinja @@ -95,7 +95,7 @@ - Taiga + Taiga diff --git a/taiga/base/templatetags/__init__.py b/taiga/base/templatetags/__init__.py deleted file mode 100644 index 8b137891..00000000 --- a/taiga/base/templatetags/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/taiga/base/utils/diff.py b/taiga/base/utils/diff.py index 3d4f0aa8..7c8ea034 100644 --- a/taiga/base/utils/diff.py +++ b/taiga/base/utils/diff.py @@ -15,7 +15,7 @@ # along with this program. If not, see . -def make_diff(first:dict, second:dict, not_found_value=None) -> dict: +def make_diff(first:dict, second:dict, not_found_value=None, excluded_keys:tuple=()) -> dict: """ Compute a diff between two dicts. """ @@ -39,4 +39,9 @@ def make_diff(first:dict, second:dict, not_found_value=None) -> dict: if frst == scnd: del diff[key] + # Removed excluded keys + for key in excluded_keys: + if key in diff: + del diff[key] + return diff diff --git a/taiga/export_import/service.py b/taiga/export_import/service.py index d2ed7dec..24d44aea 100644 --- a/taiga/export_import/service.py +++ b/taiga/export_import/service.py @@ -15,6 +15,7 @@ # along with this program. If not, see . import uuid +import os.path as path from django.contrib.contenttypes.models import ContentType @@ -206,6 +207,8 @@ def store_attachment(project, obj, attachment): if serialized.object.owner is None: serialized.object.owner = serialized.object.project.owner serialized.object._importing = True + serialized.object.size = serialized.object.attached_file.size + serialized.object.name = path.basename(serialized.object.attached_file.name).lower() serialized.save() return serialized add_errors("attachments", serialized.errors) diff --git a/taiga/projects/history/freeze_impl.py b/taiga/projects/history/freeze_impl.py index 2d350340..1af7bcf0 100644 --- a/taiga/projects/history/freeze_impl.py +++ b/taiga/projects/history/freeze_impl.py @@ -162,6 +162,7 @@ def extract_attachments(obj) -> list: for attach in obj.attachments.all(): yield {"id": attach.id, "filename": os.path.basename(attach.attached_file.name), + "url": attach.attached_file.url, "description": attach.description, "is_deprecated": attach.is_deprecated, "description": attach.description, diff --git a/taiga/projects/history/models.py b/taiga/projects/history/models.py index 9fa3deb5..809cae1c 100644 --- a/taiga/projects/history/models.py +++ b/taiga/projects/history/models.py @@ -166,10 +166,14 @@ class HistoryEntry(models.Model): for aid in set(tuple(oldattachs.keys()) + tuple(newattachs.keys())): if aid in oldattachs and aid in newattachs: - if oldattachs[aid] != newattachs[aid]: + changes = make_diff_from_dicts(oldattachs[aid], newattachs[aid], + excluded_keys=("filename", "url")) + + if changes: change = { - "filename": oldattachs[aid]["filename"], - "changes": make_diff_from_dicts(oldattachs[aid], newattachs[aid]) + "filename": newattachs[aid]["filename"], + "url": newattachs[aid]["url"], + "changes": changes } attachments["changed"].append(change) elif aid in oldattachs and aid not in newattachs: diff --git a/taiga/projects/history/templates/emails/includes/fields_diff-html.jinja b/taiga/projects/history/templates/emails/includes/fields_diff-html.jinja index ebd2cce4..049bf6cc 100644 --- a/taiga/projects/history/templates/emails/includes/fields_diff-html.jinja +++ b/taiga/projects/history/templates/emails/includes/fields_diff-html.jinja @@ -37,9 +37,10 @@ {% for att in values['new']%}
- - {{ att.filename|linebreaksbr }} {% if att.description %}({{ att.description|linebreaksbr }}){% endif %} - + + {{ att.filename|linebreaksbr }} + + {% if att.description %} {{ att.description|linebreaksbr }}{% endif %}
{% endfor %} {% endif %} @@ -51,7 +52,9 @@ {% for att in values['changed'] %}
- {{ att.filename|linebreaksbr }} + + {{ att.filename|linebreaksbr }} +
    {% if att.changes.is_deprecated %} {% if att.changes.is_deprecated.1 %} diff --git a/taiga/projects/userstories/migrations/0005_auto_20141009_1656.py b/taiga/projects/userstories/migrations/0005_auto_20141009_1656.py new file mode 100644 index 00000000..f8a2efda --- /dev/null +++ b/taiga/projects/userstories/migrations/0005_auto_20141009_1656.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('userstories', '0004_auto_20141001_1817'), + ] + + operations = [ + migrations.AlterField( + model_name='userstory', + name='generated_from_issue', + field=models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, blank=True, to='issues.Issue', verbose_name='generated from issue', related_name='generated_user_stories', null=True), + ), + ] diff --git a/taiga/projects/userstories/models.py b/taiga/projects/userstories/models.py index a520b3df..7f824c84 100644 --- a/taiga/projects/userstories/models.py +++ b/taiga/projects/userstories/models.py @@ -94,6 +94,7 @@ class UserStory(OCCModelMixin, WatchedModelMixin, BlockedMixin, TaggedMixin, mod verbose_name=_("is team requirement")) attachments = generic.GenericRelation("attachments.Attachment") generated_from_issue = models.ForeignKey("issues.Issue", null=True, blank=True, + on_delete=models.SET_NULL, related_name="generated_user_stories", verbose_name=_("generated from issue")) _importing = None diff --git a/taiga/users/api.py b/taiga/users/api.py index 8c602b89..50855b13 100644 --- a/taiga/users/api.py +++ b/taiga/users/api.py @@ -50,7 +50,7 @@ class MembersFilterBackend(BaseFilterBackend): if project_id: Project = apps.get_model('projects', 'Project') project = get_object_or_404(Project, pk=project_id) - if project.memberships.filter(user=request.user).exists() or project.owner == request.user: + if request.user.is_authenticated() and (project.memberships.filter(user=request.user).exists() or project.owner == request.user): return queryset.filter(Q(memberships__project=project) | Q(id=project.owner.id)).distinct() else: raise exc.PermissionDenied(_("You don't have permisions to see this project users.")) diff --git a/taiga/users/models.py b/taiga/users/models.py index 2a3c35eb..3c1698ea 100644 --- a/taiga/users/models.py +++ b/taiga/users/models.py @@ -20,6 +20,8 @@ import os.path as path import random import re +from unidecode import unidecode + from django.db import models from django.dispatch import receiver from django.utils.translation import ugettext_lazy as _ @@ -27,6 +29,7 @@ from django.contrib.auth.models import UserManager, AbstractBaseUser from django.core import validators from django.utils import timezone from django.utils.encoding import force_bytes +from django.template.defaultfilters import slugify from djorm_pgarray.fields import TextArrayField @@ -41,6 +44,9 @@ def generate_random_hex_color(): def get_user_file_path(instance, filename): basename = path.basename(filename).lower() + base, ext = path.splitext(basename) + base = slugify(unidecode(base)) + basename = "".join([base, ext]) hs = hashlib.sha256() hs.update(force_bytes(timezone.now().isoformat()))