Merge commit 'master' into stable

remotes/origin/enhancement/email-actions 1.1.0
Andrey Antukh 2014-10-13 10:31:01 +02:00
commit fb7dfd2bc4
15 changed files with 74 additions and 22 deletions

View File

@ -1,5 +1,13 @@
<a name="1.0.0"></a>
# 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

View File

@ -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

View File

@ -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

View File

@ -14,11 +14,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/>.
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"])

View File

@ -95,7 +95,7 @@
<td>
<a href="{{ home_url }}"
title="{{ home_url_name }}">
<img src="{{ full_url_static("emails/email-logo.png") }}" alt="Taiga" height="32" />
<img src="{{ static("emails/email-logo.png") }}" alt="Taiga" height="32" />
</a>
</td>
</tr>

View File

@ -1 +0,0 @@

View File

@ -15,7 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
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

View File

@ -15,6 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
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)

View File

@ -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,

View File

@ -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:

View File

@ -37,9 +37,10 @@
{% for att in values['new']%}
<dd style="background: #eee; padding: 5px 15px; color: #444">
<i>
{{ att.filename|linebreaksbr }} {% if att.description %}({{ att.description|linebreaksbr }}){% endif %}
</i>
<a href="{{ att.url }}" target="_blank" style="font-weight: bold; color: #444">
{{ att.filename|linebreaksbr }}
</a>
{% if att.description %}<i> {{ att.description|linebreaksbr }}</i>{% endif %}
</dd>
{% endfor %}
{% endif %}
@ -51,7 +52,9 @@
{% for att in values['changed'] %}
<dd style="background: #eee; padding: 5px 15px; color: #444">
<b>{{ att.filename|linebreaksbr }}</b>
<a href="{{ att.url }}" target="_blank" style="font-weight: bold; color: #444">
{{ att.filename|linebreaksbr }}
</a>
<ul>
{% if att.changes.is_deprecated %}
{% if att.changes.is_deprecated.1 %}

View File

@ -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),
),
]

View File

@ -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

View File

@ -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."))

View File

@ -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()))