Fix User model: delete first_name, last_name, permisions and groups, add full_name, and github_id, change description to bio

remotes/origin/enhancement/email-actions
David Barragán Merino 2014-06-11 14:16:48 +02:00
parent 8562127c91
commit f9327c7069
20 changed files with 457 additions and 195 deletions

View File

@ -46,3 +46,10 @@ from .development import *
#EMAIL_HOST_USER = 'youremail@gmail.com' #EMAIL_HOST_USER = 'youremail@gmail.com'
#EMAIL_HOST_PASSWORD = 'yourpassword' #EMAIL_HOST_PASSWORD = 'yourpassword'
#EMAIL_PORT = 587 #EMAIL_PORT = 587
# GITHUP SETTINGS
#GITHUB_URL = "https://github.com/"
#GITHUB_API_URL = "https://api.github.com/"
#GITHUB_API_CLIENT_ID = "yourgithubclientid"
#GITHUB_API_CLIENT_SECRET = "yourgithubclientsecret"

View File

@ -17,8 +17,7 @@
from rest_framework import serializers from rest_framework import serializers
class BaseRegisterSerializer(serializers.Serializer): class BaseRegisterSerializer(serializers.Serializer):
first_name = serializers.CharField(max_length=200) full_name = serializers.CharField(max_length=256)
last_name = serializers.CharField(max_length=200)
email = serializers.EmailField(max_length=200) email = serializers.EmailField(max_length=200)
username = serializers.CharField(max_length=200) username = serializers.CharField(max_length=200)
password = serializers.CharField(min_length=4) password = serializers.CharField(min_length=4)

View File

@ -105,15 +105,13 @@ class AuthServicesTests(test.TestCase):
username=self.user1.username, username=self.user1.username,
password="secret", password="secret",
email=self.user1.email, email=self.user1.email,
first_name="foo", full_name="foo")
last_name="bar")
user = services.public_register(self.domain, user = services.public_register(self.domain,
username="foousername", username="foousername",
password="foosecret", password="foosecret",
email="foo@bar.ca", email="foo@bar.ca",
first_name="Foo", full_name="Foo")
last_name="Bar")
self.assertEqual(user.username, "foousername") self.assertEqual(user.username, "foousername")
self.assertTrue(user.check_password("foosecret")) self.assertTrue(user.check_password("foosecret"))
self.assertTrue(is_user_exists_on_domain(self.domain, user)) self.assertTrue(is_user_exists_on_domain(self.domain, user))
@ -153,8 +151,7 @@ class AuthServicesTests(test.TestCase):
username="user2", username="user2",
password="user2", password="user2",
email="user2@bar.ca", email="user2@bar.ca",
first_name="Foo", full_name="Foo")
last_name="Bar")
membership = membership.__class__.objects.get(pk=membership.pk) membership = membership.__class__.objects.get(pk=membership.pk)
@ -195,8 +192,7 @@ class RegisterApiTests(test.TestCase):
data = { data = {
"username": "pepe", "username": "pepe",
"password": "pepepepe", "password": "pepepepe",
"first_name": "pepe", "full_name": "pepe",
"last_name": "pepe",
"email": "pepe@pepe.com", "email": "pepe@pepe.com",
"type": "public", "type": "public",
} }
@ -213,8 +209,7 @@ class RegisterApiTests(test.TestCase):
data = { data = {
"username": "pepe", "username": "pepe",
"password": "pepepepe", "password": "pepepepe",
"first_name": "pepe", "full_name": "pepe",
"last_name": "pepe",
"email": "pepe@pepe.com", "email": "pepe@pepe.com",
"type": "public", "type": "public",
} }
@ -227,8 +222,7 @@ class RegisterApiTests(test.TestCase):
data = { data = {
"username": "pepe", "username": "pepe",
"password": "pepepepe", "password": "pepepepe",
"first_name": "pepe", "full_name": "pepe",
"last_name": "pepe",
"email": "pepe@pepe.com", "email": "pepe@pepe.com",
"type": "private", "type": "private",
} }
@ -243,8 +237,7 @@ class RegisterApiTests(test.TestCase):
data = { data = {
"username": "pepe", "username": "pepe",
"password": "pepepepe", "password": "pepepepe",
"first_name": "pepe", "full_name": "pepe",
"last_name": "pepe",
"email": "pepe@pepe.com", "email": "pepe@pepe.com",
"type": "private", "type": "private",
"existing": False, "existing": False,

View File

@ -96,8 +96,7 @@ class IssuesOrdering(filters.FilterBackend):
if order_by in ['owner', '-owner', 'assigned_to', '-assigned_to']: if order_by in ['owner', '-owner', 'assigned_to', '-assigned_to']:
return queryset.order_by( return queryset.order_by(
'{}__first_name'.format(order_by), '{}__full_name'.format(order_by)
'{}__last_name'.format(order_by)
) )
return queryset return queryset

View File

@ -290,8 +290,7 @@ class Command(BaseCommand):
def create_user(self, counter): def create_user(self, counter):
user = User.objects.create( user = User.objects.create(
username='user-{0}'.format(counter), username='user-{0}'.format(counter),
first_name=self.sd.name('es'), full_name="{} {}".format(self.sd.name('es'), self.sd.surname('es', number=1)),
last_name=self.sd.surname('es', number=1),
email=self.sd.email(), email=self.sd.email(),
token=''.join(random.sample('abcdef0123456789', 10)), token=''.join(random.sample('abcdef0123456789', 10)),
color=self.sd.choice(COLOR_CHOICES)) color=self.sd.choice(COLOR_CHOICES))

View File

@ -109,7 +109,7 @@ class ProjectDetailSerializer(ProjectSerializer):
issue_types = IssueTypeSerializer(many=True, required=False) issue_types = IssueTypeSerializer(many=True, required=False)
def get_membership(self, obj): def get_membership(self, obj):
qs = obj.memberships.order_by('user__first_name', 'user__last_name', 'user__username') qs = obj.memberships.order_by('user__full_name', 'user__username')
qs = qs.select_related("role", "user") qs = qs.select_related("role", "user")
serializer = ProjectMembershipSerializer(qs, many=True) serializer = ProjectMembershipSerializer(qs, many=True)
@ -117,7 +117,7 @@ class ProjectDetailSerializer(ProjectSerializer):
def get_active_membership(self, obj): def get_active_membership(self, obj):
qs = obj.memberships.filter(user__isnull=False) qs = obj.memberships.filter(user__isnull=False)
qs = qs.order_by('user__first_name', 'user__last_name', 'user__username') qs = qs.order_by('user__full_name', 'user__username')
qs = qs.select_related("role", "user") qs = qs.select_related("role", "user")
serializer = ProjectMembershipSerializer(qs, many=True) serializer = ProjectMembershipSerializer(qs, many=True)

View File

@ -73,7 +73,7 @@ class ProfileTestCase(test.TestCase):
password=self.user3.username) password=self.user3.username)
self.assertTrue(response) self.assertTrue(response)
data = {"first_name": "Foo Bar"} data = {"full_name": "Foo Bar"}
response = self.client.patch( response = self.client.patch(
reverse("users-detail", args=[self.user2.pk]), reverse("users-detail", args=[self.user2.pk]),
@ -86,7 +86,7 @@ class ProfileTestCase(test.TestCase):
password=self.user3.username) password=self.user3.username)
self.assertTrue(response) self.assertTrue(response)
data = {"first_name": "Foo Bar"} data = {"full_name": "Foo Bar"}
response = self.client.patch( response = self.client.patch(
reverse("users-detail", args=[self.user3.pk]), reverse("users-detail", args=[self.user3.pk]),
content_type="application/json", content_type="application/json",
@ -99,7 +99,7 @@ class ProfileTestCase(test.TestCase):
password=self.user1.username) password=self.user1.username)
self.assertTrue(response) self.assertTrue(response)
data = {"first_name": "Foo Bar"} data = {"full_name": "Foo Bar"}
response = self.client.patch( response = self.client.patch(
reverse("users-detail", args=[self.user3.pk]), reverse("users-detail", args=[self.user3.pk]),
content_type="application/json", content_type="application/json",
@ -112,7 +112,7 @@ class ProfileTestCase(test.TestCase):
password=self.user3.username) password=self.user3.username)
self.assertTrue(response) self.assertTrue(response)
data = {"first_name": "Foo Bar"} data = {"full_name": "Foo Bar"}
response = self.client.delete( response = self.client.delete(
reverse("users-detail", args=[self.user2.pk])) reverse("users-detail", args=[self.user2.pk]))
self.assertEqual(response.status_code, 404) self.assertEqual(response.status_code, 404)
@ -122,7 +122,7 @@ class ProfileTestCase(test.TestCase):
password=self.user3.username) password=self.user3.username)
self.assertTrue(response) self.assertTrue(response)
data = {"first_name": "Foo Bar"} data = {"full_name": "Foo Bar"}
response = self.client.delete( response = self.client.delete(
reverse("users-detail", args=[self.user3.pk])) reverse("users-detail", args=[self.user3.pk]))
@ -134,7 +134,7 @@ class ProfileTestCase(test.TestCase):
password=self.user1.username) password=self.user1.username)
self.assertTrue(response) self.assertTrue(response)
data = {"first_name": "Foo Bar"} data = {"full_name": "Foo Bar"}
response = self.client.delete( response = self.client.delete(
reverse("users-detail", args=[self.user3.pk])) reverse("users-detail", args=[self.user3.pk]))

View File

@ -8,4 +8,4 @@ class VoterSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = User model = User
fields = ('id', 'username', 'first_name', 'last_name', 'full_name') fields = ('id', 'username', 'full_name')

View File

@ -20,11 +20,9 @@ router = routers.DefaultRouter(trailing_slash=False)
# taiga.users # taiga.users
from taiga.users.api import UsersViewSet from taiga.users.api import UsersViewSet
from taiga.users.api import PermissionsViewSet
from taiga.auth.api import AuthViewSet from taiga.auth.api import AuthViewSet
router.register(r"users", UsersViewSet, base_name="users") router.register(r"users", UsersViewSet, base_name="users")
router.register(r"permissions", PermissionsViewSet, base_name="permissions")
router.register(r"auth", AuthViewSet, base_name="auth") router.register(r"auth", AuthViewSet, base_name="auth")

View File

@ -47,20 +47,19 @@ admin.site.register(Role, RoleAdmin)
class UserAdmin(DjangoUserAdmin): class UserAdmin(DjangoUserAdmin):
fieldsets = ( fieldsets = (
(None, {'fields': ('username', 'password')}), (None, {'fields': ('username', 'password')}),
(_('Personal info'), {'fields': ('first_name', 'last_name', 'email', 'description', 'photo')}), (_('Personal info'), {'fields': ('full_name', 'email', 'bio', 'photo')}),
(_('Extra info'), {'fields': ('color', 'default_language', 'default_timezone', 'token', 'colorize_tags')}), (_('Extra info'), {'fields': ('color', 'default_language', 'default_timezone', 'token', 'colorize_tags')}),
(_('Notifications info'), {'fields': ("notify_level", "notify_changes_by_me",)}), (_('Notifications info'), {'fields': ("notify_level", "notify_changes_by_me",)}),
(_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser',)}), (_('Permissions'), {'fields': ('is_active', 'is_superuser',)}),
(_('Important dates'), {'fields': ('last_login', 'date_joined')}), (_('Important dates'), {'fields': ('last_login', 'date_joined')}),
) )
form = UserChangeForm form = UserChangeForm
add_form = UserCreationForm add_form = UserCreationForm
list_display = ('username', 'email', 'full_name')
list_filter = ('is_superuser', 'is_active')
class PermissionAdmin(admin.ModelAdmin): search_fields = ('username', 'full_name', 'email')
list_display = ['name', 'content_type', 'codename'] ordering = ('username',)
list_filter = ['content_type'] filter_horizontal = ()
class RoleInline(admin.TabularInline): class RoleInline(admin.TabularInline):
model = Role model = Role
@ -68,4 +67,3 @@ class RoleInline(admin.TabularInline):
admin.site.register(User, UserAdmin) admin.site.register(User, UserAdmin)
admin.site.register(Permission, PermissionAdmin)

View File

@ -20,7 +20,6 @@ from django.db.models.loading import get_model
from django.db.models import Q from django.db.models import Q
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.contrib.auth import logout, login, authenticate from django.contrib.auth import logout, login, authenticate
from django.contrib.auth.models import Permission
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from rest_framework.response import Response from rest_framework.response import Response
@ -35,7 +34,8 @@ from taiga.base import exceptions as exc
from taiga.base.api import ModelCrudViewSet, RetrieveModelMixin, ModelListViewSet from taiga.base.api import ModelCrudViewSet, RetrieveModelMixin, ModelListViewSet
from .models import User, Role from .models import User, Role
from .serializers import UserSerializer, RecoverySerializer, PermissionSerializer from .serializers import UserSerializer, RecoverySerializer
class MembersFilterBackend(BaseFilterBackend): class MembersFilterBackend(BaseFilterBackend):
def filter_queryset(self, request, queryset, view): def filter_queryset(self, request, queryset, view):
@ -53,27 +53,6 @@ class MembersFilterBackend(BaseFilterBackend):
else: else:
return queryset.filter(pk=request.user.id) return queryset.filter(pk=request.user.id)
class PermissionsViewSet(ModelListViewSet):
permission_classes = (IsAuthenticated,)
serializer_class = PermissionSerializer
paginate_by = 0
excluded_codenames = [
"add_logentry", "change_logentry", "delete_logentry",
"add_group", "change_group", "delete_group",
"add_permission", "change_permission", "delete_permission",
"add_contenttype", "change_contenttype", "delete_contenttype",
"add_message", "change_message", "delete_message",
"add_session", "change_session", "delete_session",
"add_migrationhistory", "change_migrationhistory", "delete_migrationhistory",
"add_version", "change_version", "delete_version",
"add_revision", "change_revision", "delete_revision",
"add_user", "delete_user",
"add_project",
]
def get_queryset(self):
return Permission.objects.exclude(codename__in=self.excluded_codenames)
class UsersViewSet(ModelCrudViewSet): class UsersViewSet(ModelCrudViewSet):
permission_classes = (IsAuthenticated,) permission_classes = (IsAuthenticated,)

View File

@ -4,9 +4,8 @@
"model": "users.user", "model": "users.user",
"fields": { "fields": {
"username": "admin", "username": "admin",
"first_name": "", "full_name": "",
"last_name": "", "bio": "",
"description": "",
"default_language": "", "default_language": "",
"color": "", "color": "",
"photo": "", "photo": "",
@ -15,10 +14,8 @@
"default_timezone": "", "default_timezone": "",
"is_superuser": true, "is_superuser": true,
"token": "", "token": "",
"is_staff": true, "github_id": null,
"last_login": "2013-04-04T07:36:09.880Z", "last_login": "2013-04-04T07:36:09.880Z",
"groups": [],
"user_permissions": [],
"password": "pbkdf2_sha256$10000$oRIbCKOL1U3w$/gaYMnOlc/GnN4mn3UUXvXpk2Hx0vvht6Uqhu46aikI=", "password": "pbkdf2_sha256$10000$oRIbCKOL1U3w$/gaYMnOlc/GnN4mn3UUXvXpk2Hx0vvht6Uqhu46aikI=",
"email": "niwi@niwi.be", "email": "niwi@niwi.be",
"date_joined": "2013-04-01T13:48:21.711Z" "date_joined": "2013-04-01T13:48:21.711Z"

View File

@ -0,0 +1,282 @@
# -*- coding: utf-8 -*-
from south.utils import datetime_utils as datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Deleting field 'User.notify_changes_by_me'
db.delete_column('users_user', 'notify_changes_by_me')
# Deleting field 'User.notify_level'
db.delete_column('users_user', 'notify_level')
# Deleting field 'User.is_staff'
db.delete_column('users_user', 'is_staff')
# Adding field 'User.github_id'
db.add_column('users_user', 'github_id',
self.gf('django.db.models.fields.IntegerField')(null=True, blank=True),
keep_default=False)
# Removing M2M table for field groups on 'User'
db.delete_table(db.shorten_name('users_user_groups'))
# Removing M2M table for field user_permissions on 'User'
db.delete_table(db.shorten_name('users_user_user_permissions'))
# Adding field 'User.full_name'
db.add_column('users_user', 'full_name',
self.gf('django.db.models.fields.CharField')(default='', max_length=256, blank=True),
keep_default=False)
#Copy first_name and last_name into full_name
for user in orm.Users.exclude(first_name="", last_name=""):
if user.first_name and user.last_name:
user.full_name = "{} {}".format(user.first_name, user.last_name)
elif not user.last_name:
user.full_name = user.first_name
else:
user.full_name = user.last_name
user.save()
# Deleting field 'User.first_name'
db.delete_column('users_user', 'first_name')
# Deleting field 'User.last_name'
db.delete_column('users_user', 'last_name')
def backwards(self, orm):
# Adding field 'User.notify_changes_by_me'
db.add_column('users_user', 'notify_changes_by_me',
self.gf('django.db.models.fields.BooleanField')(default=False),
keep_default=False)
# Adding field 'User.notify_level'
db.add_column('users_user', 'notify_level',
self.gf('django.db.models.fields.CharField')(default='all_owned_projects', max_length=32),
keep_default=False)
# Deleting field 'User.github_id'
db.delete_column('users_user', 'github_id')
# Adding M2M table for field groups on 'User'
m2m_table_name = db.shorten_name('users_user_groups')
db.create_table(m2m_table_name, (
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
('user', models.ForeignKey(orm['users.user'], null=False)),
('group', models.ForeignKey(orm['auth.group'], null=False))
))
db.create_unique(m2m_table_name, ['user_id', 'group_id'])
# Adding M2M table for field user_permissions on 'User'
m2m_table_name = db.shorten_name('users_user_user_permissions')
db.create_table(m2m_table_name, (
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
('user', models.ForeignKey(orm['users.user'], null=False)),
('permission', models.ForeignKey(orm['auth.permission'], null=False))
))
db.create_unique(m2m_table_name, ['user_id', 'permission_id'])
# Adding field 'User.first_name'
db.add_column('users_user', 'first_name',
self.gf('django.db.models.fields.CharField')(default='', max_length=30, blank=True),
keep_default=False)
# Adding field 'User.last_name'
db.add_column('users_user', 'last_name',
self.gf('django.db.models.fields.CharField')(default='', max_length=30, blank=True),
keep_default=False)
#Copy full_name into first_name and last_name
for user in orm.Users.exclude(full_name=""):
first_name, last_name = user.full_name.split(maxsplit=1)
user.first_name = first_name[:30]
user.last_name = last_name[:30]
user.save()
# Deleting field 'User.full_name'
db.delete_column('users_user', 'full_name')
# Adding field 'User.is_staff'
db.add_column('users_user', 'is_staff',
self.gf('django.db.models.fields.BooleanField')(default=False),
keep_default=False)
models = {
'auth.permission': {
'Meta': {'unique_together': "(('content_type', 'codename'),)", 'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'contenttypes.contenttype': {
'Meta': {'db_table': "'django_content_type'", 'ordering': "('name',)", 'object_name': 'ContentType', 'unique_together': "(('app_label', 'model'),)"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'projects.issuestatus': {
'Meta': {'unique_together': "(('project', 'name'),)", 'ordering': "['project', 'order', 'name']", 'object_name': 'IssueStatus'},
'color': ('django.db.models.fields.CharField', [], {'default': "'#999999'", 'max_length': '20'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['projects.Project']", 'related_name': "'issue_statuses'"})
},
'projects.issuetype': {
'Meta': {'unique_together': "(('project', 'name'),)", 'ordering': "['project', 'order', 'name']", 'object_name': 'IssueType'},
'color': ('django.db.models.fields.CharField', [], {'default': "'#999999'", 'max_length': '20'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['projects.Project']", 'related_name': "'issue_types'"})
},
'projects.membership': {
'Meta': {'unique_together': "(('user', 'project'),)", 'ordering': "['project', 'role']", 'object_name': 'Membership'},
'created_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'blank': 'True', 'auto_now_add': 'True'}),
'email': ('django.db.models.fields.EmailField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['projects.Project']", 'related_name': "'memberships'"}),
'role': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['users.Role']", 'related_name': "'memberships'"}),
'token': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '60', 'null': 'True', 'blank': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['users.User']", 'null': 'True', 'blank': 'True', 'related_name': "'memberships'"})
},
'projects.points': {
'Meta': {'unique_together': "(('project', 'name'),)", 'ordering': "['project', 'order', 'name']", 'object_name': 'Points'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['projects.Project']", 'related_name': "'points'"}),
'value': ('django.db.models.fields.FloatField', [], {'default': 'None', 'null': 'True', 'blank': 'True'})
},
'projects.priority': {
'Meta': {'unique_together': "(('project', 'name'),)", 'ordering': "['project', 'order', 'name']", 'object_name': 'Priority'},
'color': ('django.db.models.fields.CharField', [], {'default': "'#999999'", 'max_length': '20'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['projects.Project']", 'related_name': "'priorities'"})
},
'projects.project': {
'Meta': {'ordering': "['name']", 'object_name': 'Project'},
'created_date': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'auto_now_add': 'True'}),
'creation_template': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['projects.ProjectTemplate']", 'null': 'True', 'blank': 'True', 'related_name': "'projects'"}),
'default_issue_status': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['projects.IssueStatus']", 'on_delete': 'models.SET_NULL', 'unique': 'True', 'blank': 'True', 'null': 'True', 'related_name': "'+'"}),
'default_issue_type': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['projects.IssueType']", 'on_delete': 'models.SET_NULL', 'unique': 'True', 'blank': 'True', 'null': 'True', 'related_name': "'+'"}),
'default_points': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['projects.Points']", 'on_delete': 'models.SET_NULL', 'unique': 'True', 'blank': 'True', 'null': 'True', 'related_name': "'+'"}),
'default_priority': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['projects.Priority']", 'on_delete': 'models.SET_NULL', 'unique': 'True', 'blank': 'True', 'null': 'True', 'related_name': "'+'"}),
'default_severity': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['projects.Severity']", 'on_delete': 'models.SET_NULL', 'unique': 'True', 'blank': 'True', 'null': 'True', 'related_name': "'+'"}),
'default_task_status': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['projects.TaskStatus']", 'on_delete': 'models.SET_NULL', 'unique': 'True', 'blank': 'True', 'null': 'True', 'related_name': "'+'"}),
'default_us_status': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['projects.UserStoryStatus']", 'on_delete': 'models.SET_NULL', 'unique': 'True', 'blank': 'True', 'null': 'True', 'related_name': "'+'"}),
'description': ('django.db.models.fields.TextField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_backlog_activated': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_issues_activated': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_kanban_activated': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_wiki_activated': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'members': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['users.User']", 'through': "orm['projects.Membership']", 'symmetrical': 'False', 'related_name': "'projects'"}),
'modified_date': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'auto_now': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '250', 'unique': 'True'}),
'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['users.User']", 'related_name': "'owned_projects'"}),
'public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '250', 'unique': 'True', 'blank': 'True'}),
'tags': ('picklefield.fields.PickledObjectField', [], {'blank': 'True'}),
'total_milestones': ('django.db.models.fields.IntegerField', [], {'default': '0', 'null': 'True', 'blank': 'True'}),
'total_story_points': ('django.db.models.fields.FloatField', [], {'default': 'None', 'null': 'True'}),
'videoconferences': ('django.db.models.fields.CharField', [], {'max_length': '250', 'null': 'True', 'blank': 'True'}),
'videoconferences_salt': ('django.db.models.fields.CharField', [], {'max_length': '250', 'null': 'True', 'blank': 'True'})
},
'projects.projecttemplate': {
'Meta': {'ordering': "['name']", 'object_name': 'ProjectTemplate'},
'created_date': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'auto_now_add': 'True'}),
'default_options': ('django_pgjson.fields.JsonField', [], {}),
'default_owner_role': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'description': ('django.db.models.fields.TextField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_backlog_activated': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_issues_activated': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_kanban_activated': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_wiki_activated': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'issue_statuses': ('django_pgjson.fields.JsonField', [], {}),
'issue_types': ('django_pgjson.fields.JsonField', [], {}),
'modified_date': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'auto_now': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '250'}),
'points': ('django_pgjson.fields.JsonField', [], {}),
'priorities': ('django_pgjson.fields.JsonField', [], {}),
'roles': ('django_pgjson.fields.JsonField', [], {}),
'severities': ('django_pgjson.fields.JsonField', [], {}),
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '250', 'unique': 'True', 'blank': 'True'}),
'task_statuses': ('django_pgjson.fields.JsonField', [], {}),
'us_statuses': ('django_pgjson.fields.JsonField', [], {}),
'videoconferences': ('django.db.models.fields.CharField', [], {'max_length': '250', 'null': 'True', 'blank': 'True'}),
'videoconferences_salt': ('django.db.models.fields.CharField', [], {'max_length': '250', 'null': 'True', 'blank': 'True'})
},
'projects.severity': {
'Meta': {'unique_together': "(('project', 'name'),)", 'ordering': "['project', 'order', 'name']", 'object_name': 'Severity'},
'color': ('django.db.models.fields.CharField', [], {'default': "'#999999'", 'max_length': '20'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['projects.Project']", 'related_name': "'severities'"})
},
'projects.taskstatus': {
'Meta': {'unique_together': "(('project', 'name'),)", 'ordering': "['project', 'order', 'name']", 'object_name': 'TaskStatus'},
'color': ('django.db.models.fields.CharField', [], {'default': "'#999999'", 'max_length': '20'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['projects.Project']", 'related_name': "'task_statuses'"})
},
'projects.userstorystatus': {
'Meta': {'unique_together': "(('project', 'name'),)", 'ordering': "['project', 'order', 'name']", 'object_name': 'UserStoryStatus'},
'color': ('django.db.models.fields.CharField', [], {'default': "'#999999'", 'max_length': '20'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['projects.Project']", 'related_name': "'us_statuses'"}),
'wip_limit': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True', 'blank': 'True'})
},
'users.role': {
'Meta': {'unique_together': "(('slug', 'project'),)", 'ordering': "['order', 'slug']", 'object_name': 'Role'},
'computable': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'related_name': "'roles'"}),
'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['projects.Project']", 'related_name': "'roles'"}),
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '250', 'blank': 'True'})
},
'users.user': {
'Meta': {'ordering': "['username']", 'object_name': 'User'},
'color': ('django.db.models.fields.CharField', [], {'default': "'#be719b'", 'max_length': '9', 'blank': 'True'}),
'colorize_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'default_language': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '20', 'blank': 'True'}),
'default_timezone': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '20', 'blank': 'True'}),
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'full_name': ('django.db.models.fields.CharField', [], {'max_length': '256', 'blank': 'True'}),
'github_id': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'photo': ('django.db.models.fields.files.FileField', [], {'max_length': '500', 'null': 'True', 'blank': 'True'}),
'token': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '200', 'null': 'True', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'max_length': '30', 'unique': 'True'})
}
}
complete_apps = ['users']

View File

@ -8,48 +8,28 @@ from django.db import models
class Migration(SchemaMigration): class Migration(SchemaMigration):
def forwards(self, orm): def forwards(self, orm):
# Deleting field 'User.notify_changes_by_me' db.rename_column(u'users_user', 'description', 'bio')
db.delete_column('users_user', 'notify_changes_by_me')
# Deleting field 'User.notify_level'
db.delete_column('users_user', 'notify_level')
def backwards(self, orm): def backwards(self, orm):
# Adding field 'User.notify_changes_by_me' db.rename_column(u'users_user', 'bio', 'description')
db.add_column('users_user', 'notify_changes_by_me',
self.gf('django.db.models.fields.BooleanField')(default=False),
keep_default=False)
# Adding field 'User.notify_level'
db.add_column('users_user', 'notify_level',
self.gf('django.db.models.fields.CharField')(default='all_owned_projects', max_length=32),
keep_default=False)
models = { models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['auth.Permission']", 'blank': 'True'})
},
'auth.permission': { 'auth.permission': {
'Meta': {'object_name': 'Permission', 'unique_together': "(('content_type', 'codename'),)", 'ordering': "('content_type__app_label', 'content_type__model', 'codename')"}, 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission', 'ordering': "('content_type__app_label', 'content_type__model', 'codename')"},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
}, },
'contenttypes.contenttype': { 'contenttypes.contenttype': {
'Meta': {'db_table': "'django_content_type'", 'object_name': 'ContentType', 'unique_together': "(('app_label', 'model'),)", 'ordering': "('name',)"}, 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'ordering': "('name',)", 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
}, },
'projects.issuestatus': { 'projects.issuestatus': {
'Meta': {'object_name': 'IssueStatus', 'unique_together': "(('project', 'name'),)", 'ordering': "['project', 'order', 'name']"}, 'Meta': {'unique_together': "(('project', 'name'),)", 'object_name': 'IssueStatus', 'ordering': "['project', 'order', 'name']"},
'color': ('django.db.models.fields.CharField', [], {'default': "'#999999'", 'max_length': '20'}), 'color': ('django.db.models.fields.CharField', [], {'default': "'#999999'", 'max_length': '20'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), 'is_closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
@ -58,7 +38,7 @@ class Migration(SchemaMigration):
'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'issue_statuses'", 'to': "orm['projects.Project']"}) 'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'issue_statuses'", 'to': "orm['projects.Project']"})
}, },
'projects.issuetype': { 'projects.issuetype': {
'Meta': {'object_name': 'IssueType', 'unique_together': "(('project', 'name'),)", 'ordering': "['project', 'order', 'name']"}, 'Meta': {'unique_together': "(('project', 'name'),)", 'object_name': 'IssueType', 'ordering': "['project', 'order', 'name']"},
'color': ('django.db.models.fields.CharField', [], {'default': "'#999999'", 'max_length': '20'}), 'color': ('django.db.models.fields.CharField', [], {'default': "'#999999'", 'max_length': '20'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
@ -66,17 +46,17 @@ class Migration(SchemaMigration):
'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'issue_types'", 'to': "orm['projects.Project']"}) 'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'issue_types'", 'to': "orm['projects.Project']"})
}, },
'projects.membership': { 'projects.membership': {
'Meta': {'object_name': 'Membership', 'unique_together': "(('user', 'project'),)", 'ordering': "['project', 'role']"}, 'Meta': {'unique_together': "(('user', 'project'),)", 'object_name': 'Membership', 'ordering': "['project', 'role']"},
'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'default': 'datetime.datetime.now', 'blank': 'True'}), 'created_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'blank': 'True', 'auto_now_add': 'True'}),
'email': ('django.db.models.fields.EmailField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}), 'email': ('django.db.models.fields.EmailField', [], {'default': 'None', 'null': 'True', 'blank': 'True', 'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'memberships'", 'to': "orm['projects.Project']"}), 'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'memberships'", 'to': "orm['projects.Project']"}),
'role': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'memberships'", 'to': "orm['users.Role']"}), 'role': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'memberships'", 'to': "orm['users.Role']"}),
'token': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '60', 'null': 'True', 'blank': 'True'}), 'token': ('django.db.models.fields.CharField', [], {'default': 'None', 'null': 'True', 'blank': 'True', 'max_length': '60'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'memberships'", 'to': "orm['users.User']", 'null': 'True', 'blank': 'True'}) 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'memberships'", 'null': 'True', 'blank': 'True', 'to': "orm['users.User']"})
}, },
'projects.points': { 'projects.points': {
'Meta': {'object_name': 'Points', 'unique_together': "(('project', 'name'),)", 'ordering': "['project', 'order', 'name']"}, 'Meta': {'unique_together': "(('project', 'name'),)", 'object_name': 'Points', 'ordering': "['project', 'order', 'name']"},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '10'}), 'order': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
@ -84,7 +64,7 @@ class Migration(SchemaMigration):
'value': ('django.db.models.fields.FloatField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}) 'value': ('django.db.models.fields.FloatField', [], {'default': 'None', 'null': 'True', 'blank': 'True'})
}, },
'projects.priority': { 'projects.priority': {
'Meta': {'object_name': 'Priority', 'unique_together': "(('project', 'name'),)", 'ordering': "['project', 'order', 'name']"}, 'Meta': {'unique_together': "(('project', 'name'),)", 'object_name': 'Priority', 'ordering': "['project', 'order', 'name']"},
'color': ('django.db.models.fields.CharField', [], {'default': "'#999999'", 'max_length': '20'}), 'color': ('django.db.models.fields.CharField', [], {'default': "'#999999'", 'max_length': '20'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
@ -93,36 +73,36 @@ class Migration(SchemaMigration):
}, },
'projects.project': { 'projects.project': {
'Meta': {'object_name': 'Project', 'ordering': "['name']"}, 'Meta': {'object_name': 'Project', 'ordering': "['name']"},
'created_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), 'created_date': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'auto_now_add': 'True'}),
'creation_template': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'projects'", 'to': "orm['projects.ProjectTemplate']", 'null': 'True', 'blank': 'True'}), 'creation_template': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'projects'", 'null': 'True', 'blank': 'True', 'to': "orm['projects.ProjectTemplate']"}),
'default_issue_status': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'+'", 'to': "orm['projects.IssueStatus']", 'blank': 'True', 'unique': 'True', 'on_delete': 'models.SET_NULL', 'null': 'True'}), 'default_issue_status': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'to': "orm['projects.IssueStatus']", 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'unique': 'True'}),
'default_issue_type': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'+'", 'to': "orm['projects.IssueType']", 'blank': 'True', 'unique': 'True', 'on_delete': 'models.SET_NULL', 'null': 'True'}), 'default_issue_type': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'to': "orm['projects.IssueType']", 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'unique': 'True'}),
'default_points': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'+'", 'to': "orm['projects.Points']", 'blank': 'True', 'unique': 'True', 'on_delete': 'models.SET_NULL', 'null': 'True'}), 'default_points': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'to': "orm['projects.Points']", 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'unique': 'True'}),
'default_priority': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'+'", 'to': "orm['projects.Priority']", 'blank': 'True', 'unique': 'True', 'on_delete': 'models.SET_NULL', 'null': 'True'}), 'default_priority': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'to': "orm['projects.Priority']", 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'unique': 'True'}),
'default_severity': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'+'", 'to': "orm['projects.Severity']", 'blank': 'True', 'unique': 'True', 'on_delete': 'models.SET_NULL', 'null': 'True'}), 'default_severity': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'to': "orm['projects.Severity']", 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'unique': 'True'}),
'default_task_status': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'+'", 'to': "orm['projects.TaskStatus']", 'blank': 'True', 'unique': 'True', 'on_delete': 'models.SET_NULL', 'null': 'True'}), 'default_task_status': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'to': "orm['projects.TaskStatus']", 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'unique': 'True'}),
'default_us_status': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'+'", 'to': "orm['projects.UserStoryStatus']", 'blank': 'True', 'unique': 'True', 'on_delete': 'models.SET_NULL', 'null': 'True'}), 'default_us_status': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'to': "orm['projects.UserStoryStatus']", 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'unique': 'True'}),
'description': ('django.db.models.fields.TextField', [], {}), 'description': ('django.db.models.fields.TextField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_backlog_activated': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), 'is_backlog_activated': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_issues_activated': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), 'is_issues_activated': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_kanban_activated': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), 'is_kanban_activated': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_wiki_activated': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), 'is_wiki_activated': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'members': ('django.db.models.fields.related.ManyToManyField', [], {'through': "orm['projects.Membership']", 'related_name': "'projects'", 'to': "orm['users.User']", 'symmetrical': 'False'}), 'members': ('django.db.models.fields.related.ManyToManyField', [], {'through': "orm['projects.Membership']", 'to': "orm['users.User']", 'symmetrical': 'False', 'related_name': "'projects'"}),
'modified_date': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'auto_now': 'True'}), 'modified_date': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'auto_now': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '250'}), 'name': ('django.db.models.fields.CharField', [], {'max_length': '250', 'unique': 'True'}),
'owner': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'owned_projects'", 'to': "orm['users.User']"}), 'owner': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'owned_projects'", 'to': "orm['users.User']"}),
'public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '250', 'blank': 'True'}), 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '250', 'blank': 'True', 'unique': 'True'}),
'tags': ('picklefield.fields.PickledObjectField', [], {'blank': 'True'}), 'tags': ('picklefield.fields.PickledObjectField', [], {'blank': 'True'}),
'total_milestones': ('django.db.models.fields.IntegerField', [], {'default': '0', 'null': 'True', 'blank': 'True'}), 'total_milestones': ('django.db.models.fields.IntegerField', [], {'default': '0', 'null': 'True', 'blank': 'True'}),
'total_story_points': ('django.db.models.fields.FloatField', [], {'default': 'None', 'null': 'True'}), 'total_story_points': ('django.db.models.fields.FloatField', [], {'default': 'None', 'null': 'True'}),
'videoconferences': ('django.db.models.fields.CharField', [], {'max_length': '250', 'null': 'True', 'blank': 'True'}), 'videoconferences': ('django.db.models.fields.CharField', [], {'null': 'True', 'blank': 'True', 'max_length': '250'}),
'videoconferences_salt': ('django.db.models.fields.CharField', [], {'max_length': '250', 'null': 'True', 'blank': 'True'}) 'videoconferences_salt': ('django.db.models.fields.CharField', [], {'null': 'True', 'blank': 'True', 'max_length': '250'})
}, },
'projects.projecttemplate': { 'projects.projecttemplate': {
'Meta': {'object_name': 'ProjectTemplate', 'ordering': "['name']"}, 'Meta': {'object_name': 'ProjectTemplate', 'ordering': "['name']"},
'created_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), 'created_date': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'auto_now_add': 'True'}),
'default_options': ('django_pgjson.fields.JsonField', [], {}), 'default_options': ('django_pgjson.fields.JsonField', [], {}),
'default_owner_role': ('django.db.models.fields.CharField', [], {'max_length': '50'}), 'default_owner_role': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'description': ('django.db.models.fields.TextField', [], {}), 'description': ('django.db.models.fields.TextField', [], {}),
@ -139,14 +119,14 @@ class Migration(SchemaMigration):
'priorities': ('django_pgjson.fields.JsonField', [], {}), 'priorities': ('django_pgjson.fields.JsonField', [], {}),
'roles': ('django_pgjson.fields.JsonField', [], {}), 'roles': ('django_pgjson.fields.JsonField', [], {}),
'severities': ('django_pgjson.fields.JsonField', [], {}), 'severities': ('django_pgjson.fields.JsonField', [], {}),
'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '250', 'blank': 'True'}), 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '250', 'blank': 'True', 'unique': 'True'}),
'task_statuses': ('django_pgjson.fields.JsonField', [], {}), 'task_statuses': ('django_pgjson.fields.JsonField', [], {}),
'us_statuses': ('django_pgjson.fields.JsonField', [], {}), 'us_statuses': ('django_pgjson.fields.JsonField', [], {}),
'videoconferences': ('django.db.models.fields.CharField', [], {'max_length': '250', 'null': 'True', 'blank': 'True'}), 'videoconferences': ('django.db.models.fields.CharField', [], {'null': 'True', 'blank': 'True', 'max_length': '250'}),
'videoconferences_salt': ('django.db.models.fields.CharField', [], {'max_length': '250', 'null': 'True', 'blank': 'True'}) 'videoconferences_salt': ('django.db.models.fields.CharField', [], {'null': 'True', 'blank': 'True', 'max_length': '250'})
}, },
'projects.severity': { 'projects.severity': {
'Meta': {'object_name': 'Severity', 'unique_together': "(('project', 'name'),)", 'ordering': "['project', 'order', 'name']"}, 'Meta': {'unique_together': "(('project', 'name'),)", 'object_name': 'Severity', 'ordering': "['project', 'order', 'name']"},
'color': ('django.db.models.fields.CharField', [], {'default': "'#999999'", 'max_length': '20'}), 'color': ('django.db.models.fields.CharField', [], {'default': "'#999999'", 'max_length': '20'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
@ -154,7 +134,7 @@ class Migration(SchemaMigration):
'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'severities'", 'to': "orm['projects.Project']"}) 'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'severities'", 'to': "orm['projects.Project']"})
}, },
'projects.taskstatus': { 'projects.taskstatus': {
'Meta': {'object_name': 'TaskStatus', 'unique_together': "(('project', 'name'),)", 'ordering': "['project', 'order', 'name']"}, 'Meta': {'unique_together': "(('project', 'name'),)", 'object_name': 'TaskStatus', 'ordering': "['project', 'order', 'name']"},
'color': ('django.db.models.fields.CharField', [], {'default': "'#999999'", 'max_length': '20'}), 'color': ('django.db.models.fields.CharField', [], {'default': "'#999999'", 'max_length': '20'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), 'is_closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
@ -163,7 +143,7 @@ class Migration(SchemaMigration):
'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'task_statuses'", 'to': "orm['projects.Project']"}) 'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'task_statuses'", 'to': "orm['projects.Project']"})
}, },
'projects.userstorystatus': { 'projects.userstorystatus': {
'Meta': {'object_name': 'UserStoryStatus', 'unique_together': "(('project', 'name'),)", 'ordering': "['project', 'order', 'name']"}, 'Meta': {'unique_together': "(('project', 'name'),)", 'object_name': 'UserStoryStatus', 'ordering': "['project', 'order', 'name']"},
'color': ('django.db.models.fields.CharField', [], {'default': "'#999999'", 'max_length': '20'}), 'color': ('django.db.models.fields.CharField', [], {'default': "'#999999'", 'max_length': '20'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), 'is_closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
@ -173,38 +153,37 @@ class Migration(SchemaMigration):
'wip_limit': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}) 'wip_limit': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True', 'blank': 'True'})
}, },
'users.role': { 'users.role': {
'Meta': {'object_name': 'Role', 'unique_together': "(('slug', 'project'),)", 'ordering': "['order', 'slug']"}, 'Meta': {'unique_together': "(('slug', 'project'),)", 'object_name': 'Role', 'ordering': "['order', 'slug']"},
'computable': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), 'computable': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}), 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '10'}), 'order': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'roles'", 'to': "orm['auth.Permission']", 'symmetrical': 'False'}), 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'roles'", 'to': "orm['auth.Permission']", 'symmetrical': 'False'}),
'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'roles'", 'to': "orm['projects.Project']"}), 'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'roles'", 'to': "orm['projects.Project']"}),
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '250', 'blank': 'True'}) 'slug': ('django.db.models.fields.SlugField', [], {'blank': 'True', 'max_length': '250'})
}, },
'users.user': { 'users.user': {
'Meta': {'object_name': 'User', 'ordering': "['username']"}, 'Meta': {'object_name': 'User', 'ordering': "['username']"},
'color': ('django.db.models.fields.CharField', [], {'default': "'#e6748a'", 'max_length': '9', 'blank': 'True'}), 'bio': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'color': ('django.db.models.fields.CharField', [], {'default': "'#f18e35'", 'blank': 'True', 'max_length': '9'}),
'colorize_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), 'colorize_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'default_language': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '20', 'blank': 'True'}), 'default_language': ('django.db.models.fields.CharField', [], {'default': "''", 'blank': 'True', 'max_length': '20'}),
'default_timezone': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '20', 'blank': 'True'}), 'default_timezone': ('django.db.models.fields.CharField', [], {'default': "''", 'blank': 'True', 'max_length': '20'}),
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), 'email': ('django.db.models.fields.EmailField', [], {'blank': 'True', 'max_length': '75'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), 'full_name': ('django.db.models.fields.CharField', [], {'blank': 'True', 'max_length': '256'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), 'github_id': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'user_set'", 'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), 'notify_changes_by_me': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'notify_level': ('django.db.models.fields.CharField', [], {'default': "'all_owned_projects'", 'max_length': '32'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'photo': ('django.db.models.fields.files.FileField', [], {'max_length': '500', 'null': 'True', 'blank': 'True'}), 'photo': ('django.db.models.fields.files.FileField', [], {'null': 'True', 'blank': 'True', 'max_length': '500'}),
'token': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '200', 'null': 'True', 'blank': 'True'}), 'token': ('django.db.models.fields.CharField', [], {'default': 'None', 'null': 'True', 'blank': 'True', 'max_length': '200'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'user_set'", 'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), 'username': ('django.db.models.fields.CharField', [], {'max_length': '30', 'unique': 'True'})
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
} }
} }
complete_apps = ['users'] complete_apps = ['users']

View File

@ -17,32 +17,83 @@
from django.db import models from django.db import models
from django.dispatch import receiver from django.dispatch import receiver
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import UserManager, AbstractUser from django.contrib.auth.models import UserManager, AbstractBaseUser
from django.core import validators
from django.utils import timezone
from taiga.base.utils.slug import slugify_uniquely from taiga.base.utils.slug import slugify_uniquely
import random import random
import re
def generate_random_hex_color(): def generate_random_hex_color():
return "#{:06x}".format(random.randint(0,0xFFFFFF)) return "#{:06x}".format(random.randint(0,0xFFFFFF))
class User(AbstractUser): class PermissionsMixin(models.Model):
"""
A mixin class that adds the fields and methods necessary to support
Django's Permission model using the ModelBackend.
"""
is_superuser = models.BooleanField(_('superuser status'), default=False,
help_text=_('Designates that this user has all permissions without '
'explicitly assigning them.'))
class Meta:
abstract = True
def has_perm(self, perm, obj=None):
"""
Returns True if the user is superadmin and is active
"""
return self.is_active and self.is_superuser
def has_perms(self, perm_list, obj=None):
"""
Returns True if the user is superadmin and is active
"""
return self.is_active and self.is_superuser
def has_module_perms(self, app_label):
"""
Returns True if the user is superadmin and is active
"""
return self.is_active and self.is_superuser
class User(AbstractBaseUser, PermissionsMixin):
username = models.CharField(_('username'), max_length=30, unique=True,
help_text=_('Required. 30 characters or fewer. Letters, numbers and '
'@/./+/-/_ characters'),
validators=[
validators.RegexValidator(re.compile('^[\w.@+-]+$'), _('Enter a valid username.'), 'invalid')
])
email = models.EmailField(_('email address'), blank=True)
is_active = models.BooleanField(_('active'), default=True,
help_text=_('Designates whether this user should be treated as '
'active. Unselect this instead of deleting accounts.'))
full_name = models.CharField(_('full name'), max_length=256, blank=True)
color = models.CharField(max_length=9, null=False, blank=True, default=generate_random_hex_color, color = models.CharField(max_length=9, null=False, blank=True, default=generate_random_hex_color,
verbose_name=_("color")) verbose_name=_("color"))
description = models.TextField(null=False, blank=True, bio = models.TextField(null=False, blank=True, default="", verbose_name=_("biography"))
verbose_name=_("description")) photo = models.FileField(upload_to="users/photo", max_length=500, null=True, blank=True,
photo = models.FileField(upload_to="files/msg", max_length=500, null=True, blank=True,
verbose_name=_("photo")) verbose_name=_("photo"))
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
default_language = models.CharField(max_length=20, null=False, blank=True, default="", default_language = models.CharField(max_length=20, null=False, blank=True, default="",
verbose_name=_("default language")) verbose_name=_("default language"))
default_timezone = models.CharField(max_length=20, null=False, blank=True, default="", default_timezone = models.CharField(max_length=20, null=False, blank=True, default="",
verbose_name=_("default timezone")) verbose_name=_("default timezone"))
token = models.CharField(max_length=200, null=True, blank=True, default=None,
verbose_name=_("token"))
colorize_tags = models.BooleanField(null=False, blank=True, default=False, colorize_tags = models.BooleanField(null=False, blank=True, default=False,
verbose_name=_("colorize tags")) verbose_name=_("colorize tags"))
token = models.CharField(max_length=200, null=True, blank=True, default=None,
verbose_name=_("token"))
github_id = models.IntegerField(null=True, blank=True, verbose_name=_("github ID"))
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email']
objects = UserManager() objects = UserManager()
class Meta: class Meta:
@ -56,8 +107,12 @@ class User(AbstractUser):
def __str__(self): def __str__(self):
return self.get_full_name() return self.get_full_name()
def get_short_name(self):
"Returns the short name for the user."
return self.username
def get_full_name(self): def get_full_name(self):
return super().get_full_name() or self.username or self.email return self.full_name or self.username or self.email
class Role(models.Model): class Role(models.Model):
@ -104,4 +159,3 @@ def role_post_save(sender, instance, created, **kwargs):
unique_projects = set(map(lambda x: x.project, instance.memberships.all())) unique_projects = set(map(lambda x: x.project, instance.memberships.all()))
for project in unique_projects: for project in unique_projects:
project.update_role_points() project.update_role_points()

View File

@ -15,7 +15,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import Permission
from rest_framework import serializers from rest_framework import serializers
@ -23,20 +22,12 @@ from taiga.projects.models import Project
from .models import User, Role from .models import User, Role
class PermissionSerializer(serializers.ModelSerializer):
class Meta:
model = Permission
fields = ("id", "name", "codename")
class UserSerializer(serializers.ModelSerializer): class UserSerializer(serializers.ModelSerializer):
full_name = serializers.CharField(source="get_full_name", required=False)
class Meta: class Meta:
model = User model = User
fields = ("id", "username", "first_name", "last_name", "full_name", "email", fields = ('id', 'username', 'full_name', 'email', 'github_id',
"color", "description", "default_language", "default_timezone", 'color', 'bio', 'default_language', 'default_timezone',
"is_active", "photo",) 'is_active', 'photo')
class RecoverySerializer(serializers.Serializer): class RecoverySerializer(serializers.Serializer):

View File

@ -25,8 +25,7 @@ def create_user(id, save=True, is_superuser=False):
instance = model( instance = model(
username="user{0}".format(id), username="user{0}".format(id),
email="user{0}@taiga.io".format(id), email="user{0}@taiga.io".format(id),
first_name="Foo{0}".format(id), full_name="Foo{0} Bar{0}".format(id)
last_name="Bar{0}".format(id)
) )
instance.set_password(instance.username) instance.set_password(instance.username)
@ -46,14 +45,3 @@ def create_user(id, save=True, is_superuser=False):
dm.save() dm.save()
return instance return instance
def create_domain(name, public_register=False):
domain_model = get_model("domains", "Domain")
instance = domain_model(name=name,
domain=name,
public_register=public_register)
instance.save()
return instance

View File

@ -10,8 +10,7 @@ pytestmark = pytest.mark.django_db
def register_form(): def register_form():
return {"username": "username", return {"username": "username",
"password": "password", "password": "password",
"first_name": "fname", "full_name": "fname",
"last_name": "lname",
"email": "user@email.com", "email": "user@email.com",
"type": "public"} "type": "public"}

View File

@ -14,7 +14,7 @@ dummy_project.slug = "test"
def test_proccessor_valid_user_mention(): def test_proccessor_valid_user_mention():
factories.UserFactory(username="user1", first_name="test", last_name="name") factories.UserFactory(username="user1", full_name="test name")
result = render(dummy_project, "**@user1**") result = render(dummy_project, "**@user1**")
expected_result = "<p><strong><a alt=\"test name\" class=\"mention\" href=\"/#/profile/user1\" title=\"test name\">&commat;user1</a></strong></p>" expected_result = "<p><strong><a alt=\"test name\" class=\"mention\" href=\"/#/profile/user1\" title=\"test name\">&commat;user1</a></strong></p>"
assert result == expected_result assert result == expected_result
@ -26,6 +26,6 @@ def test_proccessor_invalid_user_mention():
def test_render_and_extract_mentions(): def test_render_and_extract_mentions():
user = factories.UserFactory(username="user1", first_name="test", last_name="name") user = factories.UserFactory(username="user1", full_name="test")
(_, extracted) = render_and_extract(dummy_project, "**@user1**") (_, extracted) = render_and_extract(dummy_project, "**@user1**")
assert extracted['mentions'] == [user] assert extracted['mentions'] == [user]

View File

@ -22,12 +22,12 @@ def teardown_module():
class TestGetAttribute: class TestGetAttribute:
def test_no_attribute(self, object): def test_no_attribute(self, object):
object.first_name = "name" object.full_name = "name"
with pytest.raises(AttributeError): with pytest.raises(AttributeError):
n.get_attribute(object, "name") n.get_attribute(object, "name")
with pytest.raises(AttributeError): with pytest.raises(AttributeError):
n.get_attribute(object, "first_name__last_name") n.get_attribute(object, "full_name__last_name")
def test_one_level(self, object): def test_one_level(self, object):
object.name = "name" object.name = "name"
@ -35,14 +35,14 @@ class TestGetAttribute:
def test_two_levels(self, object): def test_two_levels(self, object):
object.name = object object.name = object
object.name.first_name = "first name" object.name.full_name = "first name"
assert n.get_attribute(object, "name__first_name") == object.name.first_name assert n.get_attribute(object, "name__full_name") == object.name.full_name
def test_three_levels(self, object): def test_three_levels(self, object):
object.info = object object.info = object
object.info.name = object object.info.name = object
object.info.name.first_name = "first name" object.info.name.full_name = "first name"
assert n.get_attribute(object, "info__name__first_name") == object.info.name.first_name assert n.get_attribute(object, "info__name__full_name") == object.info.name.full_name
def test_transform_field_into_lookup(): def test_transform_field_into_lookup():
@ -237,14 +237,14 @@ class TestIssues:
def test_ordering_by_owner(self): def test_ordering_by_owner(self):
project = f.ProjectFactory.create() project = f.ProjectFactory.create()
owner1 = f.UserFactory.create(first_name="Chuck", last_name="Norris") owner1 = f.UserFactory.create(full_name="Chuck Norris")
owner2 = f.UserFactory.create(first_name="George", last_name="Of The Jungle") owner2 = f.UserFactory.create(full_name="George Of The Jungle")
issue1 = f.IssueFactory.create(project=project, owner=owner2) issue1 = f.IssueFactory.create(project=project, owner=owner2)
issue2 = f.IssueFactory.create(project=project, owner=owner1) issue2 = f.IssueFactory.create(project=project, owner=owner1)
issue3 = f.IssueFactory.create(project=project, owner=owner1) issue3 = f.IssueFactory.create(project=project, owner=owner1)
issues = Issue.objects.filter(project=project).order_by("owner__first_name") issues = Issue.objects.filter(project=project).order_by("owner__full_name")
issue2_neighbors = n.get_neighbors(issue2, results_set=issues) issue2_neighbors = n.get_neighbors(issue2, results_set=issues)
issue3_neighbors = n.get_neighbors(issue3, results_set=issues) issue3_neighbors = n.get_neighbors(issue3, results_set=issues)
@ -256,14 +256,14 @@ class TestIssues:
def test_ordering_by_owner_desc(self): def test_ordering_by_owner_desc(self):
project = f.ProjectFactory.create() project = f.ProjectFactory.create()
owner1 = f.UserFactory.create(first_name="Chuck", last_name="Norris") owner1 = f.UserFactory.create(full_name="Chuck Norris")
owner2 = f.UserFactory.create(first_name="George", last_name="Of The Jungle") owner2 = f.UserFactory.create(full_name="George Of The Jungle")
issue1 = f.IssueFactory.create(project=project, owner=owner2) issue1 = f.IssueFactory.create(project=project, owner=owner2)
issue2 = f.IssueFactory.create(project=project, owner=owner1) issue2 = f.IssueFactory.create(project=project, owner=owner1)
issue3 = f.IssueFactory.create(project=project, owner=owner1) issue3 = f.IssueFactory.create(project=project, owner=owner1)
issues = Issue.objects.filter(project=project).order_by("-owner__first_name") issues = Issue.objects.filter(project=project).order_by("-owner__full_name")
issue1_neighbors = n.get_neighbors(issue1, results_set=issues) issue1_neighbors = n.get_neighbors(issue1, results_set=issues)
issue3_neighbors = n.get_neighbors(issue3, results_set=issues) issue3_neighbors = n.get_neighbors(issue3, results_set=issues)
@ -275,14 +275,14 @@ class TestIssues:
def test_ordering_by_assigned_to(self): def test_ordering_by_assigned_to(self):
project = f.ProjectFactory.create() project = f.ProjectFactory.create()
assigned_to1 = f.UserFactory.create(first_name="Chuck", last_name="Norris") assigned_to1 = f.UserFactory.create(full_name="Chuck Norris")
assigned_to2 = f.UserFactory.create(first_name="George", last_name="Of The Jungle") assigned_to2 = f.UserFactory.create(full_name="George Of The Jungle")
issue1 = f.IssueFactory.create(project=project, assigned_to=assigned_to2) issue1 = f.IssueFactory.create(project=project, assigned_to=assigned_to2)
issue2 = f.IssueFactory.create(project=project, assigned_to=assigned_to1) issue2 = f.IssueFactory.create(project=project, assigned_to=assigned_to1)
issue3 = f.IssueFactory.create(project=project, assigned_to=assigned_to1) issue3 = f.IssueFactory.create(project=project, assigned_to=assigned_to1)
issues = Issue.objects.filter(project=project).order_by("assigned_to__first_name") issues = Issue.objects.filter(project=project).order_by("assigned_to__full_name")
issue2_neighbors = n.get_neighbors(issue2, results_set=issues) issue2_neighbors = n.get_neighbors(issue2, results_set=issues)
issue3_neighbors = n.get_neighbors(issue3, results_set=issues) issue3_neighbors = n.get_neighbors(issue3, results_set=issues)
@ -294,14 +294,14 @@ class TestIssues:
def test_ordering_by_assigned_to_desc(self): def test_ordering_by_assigned_to_desc(self):
project = f.ProjectFactory.create() project = f.ProjectFactory.create()
assigned_to1 = f.UserFactory.create(first_name="Chuck", last_name="Norris") assigned_to1 = f.UserFactory.create(full_name="Chuck Norris")
assigned_to2 = f.UserFactory.create(first_name="George", last_name="Of The Jungle") assigned_to2 = f.UserFactory.create(full_name="George Of The Jungle")
issue1 = f.IssueFactory.create(project=project, assigned_to=assigned_to2) issue1 = f.IssueFactory.create(project=project, assigned_to=assigned_to2)
issue2 = f.IssueFactory.create(project=project, assigned_to=assigned_to1) issue2 = f.IssueFactory.create(project=project, assigned_to=assigned_to1)
issue3 = f.IssueFactory.create(project=project, assigned_to=assigned_to1) issue3 = f.IssueFactory.create(project=project, assigned_to=assigned_to1)
issues = Issue.objects.filter(project=project).order_by("-assigned_to__first_name") issues = Issue.objects.filter(project=project).order_by("-assigned_to__full_name")
issue1_neighbors = n.get_neighbors(issue1, results_set=issues) issue1_neighbors = n.get_neighbors(issue1, results_set=issues)
issue3_neighbors = n.get_neighbors(issue3, results_set=issues) issue3_neighbors = n.get_neighbors(issue3, results_set=issues)