user profile

This commit is contained in:
esteban 2015-03-30 03:07:50 -03:00
parent 1074898854
commit fba524786e
38 changed files with 321 additions and 169 deletions

View File

@ -9,27 +9,13 @@ To see it in action, please visit [The Spirit Project](http://spirit-project.com
Spirit requires the following software to be installed:
* Python 2.7, 3.3 or 3.4 (recommended)
* Django 1.7
* Django 1.8
* PostgreSQL or MySQL or Oracle Database
## Dependencies
Check out the [requirements](https://github.com/nitely/Spirit/blob/master/requirements.txt) provided.
## Integration
Spirit can be integrated with any other Django application without much of a hassle.
The only thing to notice is that Spirit uses its own *AUTH_USER_MODEL*.
If you want to roll your own user app, your user model must inherit from `spirit.models.user.AbstractForumUser`.
If you want to extend the Spirit user model (adding new fields or methods),
your model must inherit from `spirit.models.user.AbstractUser`.
If you just want to integrate Spirit's user profile to your *existing* project
and you are using the default Django's user model, check out the [Spirit-User-Profile](https://github.com/nitely/Spirit-User-Profile) app.
## Installing (Advanced)
Check out the [example](https://github.com/nitely/Spirit/tree/master/example) provided.

View File

@ -10,17 +10,24 @@ from django.contrib.auth import get_user_model
from spirit.models.category import Category
from spirit.models.comment_flag import CommentFlag
from spirit.models.user import UserProfile
User = get_user_model()
class UserEditForm(forms.ModelForm):
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ("username", "email", "location",
"timezone", "is_administrator", "is_moderator", "is_active")
fields = ("username", "email", "is_active")
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ("location", "timezone", "is_administrator", "is_moderator")
class CategoryForm(forms.ModelForm):

View File

@ -27,7 +27,7 @@ class TopicForm(forms.ModelForm):
label=_("Category"),
empty_label=_("Chose a category"))
if self.instance.pk and not user.is_moderator:
if self.instance.pk and not user.st.is_moderator:
del self.fields['category']
def save(self, commit=True):

View File

@ -9,6 +9,8 @@ from django.contrib.auth import get_user_model
from django.utils import timezone
from django.template import defaultfilters
from ..models.user import UserProfile
User = get_user_model()
@ -22,7 +24,7 @@ class RegistrationForm(UserCreationForm):
fields = ("username", "email")
def clean_honeypot(self):
"""Check that nothing's been entered into the honeypot."""
"""Check that nothing has been entered into the honeypot."""
value = self.cleaned_data["honeypot"]
if value:
@ -41,16 +43,25 @@ class RegistrationForm(UserCreationForm):
raise forms.ValidationError(_("The username is taken."))
# TODO: check email is unique
def save(self, commit=True):
self.instance.is_active = False
return super(RegistrationForm, self).save(commit)
class UserProfileForm(forms.ModelForm):
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ("first_name", "last_name", "location", "timezone")
fields = ("first_name", "last_name")
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ("location", "timezone")
def __init__(self, *args, **kwargs):
super(UserProfileForm, self).__init__(*args, **kwargs)
@ -108,7 +119,7 @@ class ResendActivationForm(forms.Form):
except User.DoesNotExist:
raise forms.ValidationError(_("The provided email does not exists."))
if self.user.is_verified:
if self.user.st.is_verified:
raise forms.ValidationError(_("This account is verified, try logging-in."))
return email

View File

@ -48,7 +48,7 @@ class CommentQuerySet(models.QuerySet):
return self.unremoved()._access(user=user)
def for_update_or_404(self, pk, user):
if user.is_moderator:
if user.st.is_moderator:
return get_object_or_404(self._access(user=user), pk=pk)
else:
return get_object_or_404(self.for_access(user), user=user, pk=pk)

View File

@ -52,7 +52,7 @@ class TopicQuerySet(models.QuerySet):
return self.prefetch_related(prefetch)
def get_public_or_404(self, pk, user):
if user.is_authenticated() and user.is_moderator:
if user.is_authenticated() and user.st.is_moderator:
return get_object_or_404(self.public()
.select_related('category__parent'),
pk=pk)
@ -62,7 +62,7 @@ class TopicQuerySet(models.QuerySet):
pk=pk)
def for_update_or_404(self, pk, user):
if user.is_moderator:
if user.st.is_moderator:
return get_object_or_404(self.public(), pk=pk)
else:
return get_object_or_404(self.visible().opened(), pk=pk, user=user)

View File

@ -10,6 +10,8 @@ from django.contrib.auth import logout
from django.core.urlresolvers import resolve
from django.contrib.auth.views import redirect_to_login
from .models.user import UserProfile
User = get_user_model()
@ -25,7 +27,7 @@ class TimezoneMiddleware(object):
def process_request(self, request):
if request.user.is_authenticated():
timezone.activate(request.user.timezone)
timezone.activate(request.user.st.timezone)
else:
timezone.deactivate()
@ -38,10 +40,10 @@ class LastIPMiddleware(object):
last_ip = request.META['REMOTE_ADDR'].strip()
if request.user.last_ip == last_ip:
if request.user.st.last_ip == last_ip:
return
User.objects.filter(pk=request.user.pk)\
UserProfile.objects.filter(user__pk=request.user.pk)\
.update(last_ip=last_ip)
@ -52,12 +54,12 @@ class LastSeenMiddleware(object):
return
threshold = settings.ST_USER_LAST_SEEN_THRESHOLD_MINUTES * 60
delta = timezone.now() - request.user.last_seen
delta = timezone.now() - request.user.st.last_seen
if delta.seconds < threshold:
return
User.objects.filter(pk=request.user.pk)\
UserProfile.objects.filter(user__pk=request.user.pk)\
.update(last_seen=timezone.now())

View File

@ -7,7 +7,9 @@ from django.conf import settings
def verify_active_users(apps, schema_editor):
User = apps.get_model(settings.AUTH_USER_MODEL)
User.objects.filter(is_active=True).update(is_verified=True)
if hasattr(User, 'is_verified'):
User.objects.filter(is_active=True).update(is_verified=True)
class Migration(migrations.Migration):

View File

@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import spirit.utils.models
from django.conf import settings
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('spirit', '0006_auto_20150327_0204'),
]
operations = [
migrations.CreateModel(
name='UserProfile',
fields=[
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
('slug', spirit.utils.models.AutoSlugField(db_index=False, blank=True, populate_from='user.username')),
('location', models.CharField(blank=True, verbose_name='location', max_length=75)),
('last_seen', models.DateTimeField(auto_now=True, verbose_name='last seen')),
('last_ip', models.GenericIPAddressField(blank=True, verbose_name='last ip', null=True)),
('timezone', models.CharField(max_length=32, verbose_name='time zone', choices=[('Etc/GMT+12', '(GMT -12:00) Eniwetok, Kwajalein'), ('Etc/GMT+11', '(GMT -11:00) Midway Island, Samoa'), ('Etc/GMT+10', '(GMT -10:00) Hawaii'), ('Pacific/Marquesas', '(GMT -9:30) Marquesas Islands'), ('Etc/GMT+9', '(GMT -9:00) Alaska'), ('Etc/GMT+8', '(GMT -8:00) Pacific Time (US & Canada)'), ('Etc/GMT+7', '(GMT -7:00) Mountain Time (US & Canada)'), ('Etc/GMT+6', '(GMT -6:00) Central Time (US & Canada), Mexico City'), ('Etc/GMT+5', '(GMT -5:00) Eastern Time (US & Canada), Bogota, Lima'), ('America/Caracas', '(GMT -4:30) Venezuela'), ('Etc/GMT+4', '(GMT -4:00) Atlantic Time (Canada), Caracas, La Paz'), ('Etc/GMT+3', '(GMT -3:00) Brazil, Buenos Aires, Georgetown'), ('Etc/GMT+2', '(GMT -2:00) Mid-Atlantic'), ('Etc/GMT+1', '(GMT -1:00) Azores, Cape Verde Islands'), ('UTC', '(GMT) Western Europe Time, London, Lisbon, Casablanca'), ('Etc/GMT-1', '(GMT +1:00) Brussels, Copenhagen, Madrid, Paris'), ('Etc/GMT-2', '(GMT +2:00) Kaliningrad, South Africa'), ('Etc/GMT-3', '(GMT +3:00) Baghdad, Riyadh, Moscow, St. Petersburg'), ('Etc/GMT-4', '(GMT +4:00) Abu Dhabi, Muscat, Baku, Tbilisi'), ('Asia/Kabul', '(GMT +4:30) Afghanistan'), ('Etc/GMT-5', '(GMT +5:00) Ekaterinburg, Islamabad, Karachi, Tashkent'), ('Asia/Kolkata', '(GMT +5:30) India, Sri Lanka'), ('Asia/Kathmandu', '(GMT +5:45) Nepal'), ('Etc/GMT-6', '(GMT +6:00) Almaty, Dhaka, Colombo'), ('Indian/Cocos', '(GMT +6:30) Cocos Islands, Myanmar'), ('Etc/GMT-7', '(GMT +7:00) Bangkok, Hanoi, Jakarta'), ('Etc/GMT-8', '(GMT +8:00) Beijing, Perth, Singapore, Hong Kong'), ('Australia/Eucla', '(GMT +8:45) Australia (Eucla)'), ('Etc/GMT-9', '(GMT +9:00) Tokyo, Seoul, Osaka, Sapporo, Yakutsk'), ('Australia/North', '(GMT +9:30) Australia (Northern Territory)'), ('Etc/GMT-10', '(GMT +10:00) Eastern Australia, Guam, Vladivostok'), ('Etc/GMT-11', '(GMT +11:00) Magadan, Solomon Islands, New Caledonia'), ('Pacific/Norfolk', '(GMT +11:30) Norfolk Island'), ('Etc/GMT-12', '(GMT +12:00) Auckland, Wellington, Fiji, Kamchatka')], default='UTC')),
('is_administrator', models.BooleanField(verbose_name='administrator status', default=False)),
('is_moderator', models.BooleanField(verbose_name='moderator status', default=False)),
('is_verified', models.BooleanField(verbose_name='verified', help_text='Designates whether the user has verified his account by email or by other means. Un-select this to let the user activate his account.', default=False)),
('topic_count', models.PositiveIntegerField(verbose_name='topic count', default=0)),
('comment_count', models.PositiveIntegerField(verbose_name='comment count', default=0)),
('user', models.OneToOneField(to=settings.AUTH_USER_MODEL, verbose_name='profile', related_name='st')),
],
options={
'verbose_name': 'forum profile',
'verbose_name_plural': 'forum profiles',
},
bases=(models.Model,),
),
]

View File

@ -11,11 +11,49 @@ from django.core.mail import send_mail
from django.core import validators
from django.utils.translation import ugettext_lazy as _
from django.utils import timezone
from django.conf import settings
from spirit.utils.timezone import TIMEZONE_CHOICES
from spirit.utils.models import AutoSlugField
class UserProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, verbose_name=_("profile"), related_name='st')
slug = AutoSlugField(populate_from="user.username", db_index=False, blank=True)
location = models.CharField(_("location"), max_length=75, blank=True)
last_seen = models.DateTimeField(_("last seen"), auto_now=True)
last_ip = models.GenericIPAddressField(_("last ip"), blank=True, null=True)
timezone = models.CharField(_("time zone"), max_length=32, choices=TIMEZONE_CHOICES, default='UTC')
is_administrator = models.BooleanField(_('administrator status'), default=False)
is_moderator = models.BooleanField(_('moderator status'), default=False)
is_verified = models.BooleanField(_('verified'), default=False,
help_text=_('Designates whether the user has verified his '
'account by email or by other means. Un-select this '
'to let the user activate his account.'))
topic_count = models.PositiveIntegerField(_("topic count"), default=0)
comment_count = models.PositiveIntegerField(_("comment count"), default=0)
class Meta:
verbose_name = _("forum profile")
verbose_name_plural = _("forum profiles")
def save(self, *args, **kwargs):
if self.user.is_superuser:
self.is_administrator = True
if self.is_administrator:
self.is_moderator = True
super(UserProfile, self).save(*args, **kwargs)
def get_absolute_url(self):
return reverse('spirit:profile-detail', kwargs={'pk': self.pk,
'slug': self.slug})
class AbstractForumUser(models.Model):
slug = AutoSlugField(populate_from="username", db_index=False, blank=True)
location = models.CharField(_("location"), max_length=75, blank=True)
@ -46,12 +84,6 @@ class AbstractForumUser(models.Model):
class AbstractUser(AbstractBaseUser, PermissionsMixin, AbstractForumUser):
# almost verbatim copy from the auth user model
# adds email(unique=True, blank=False, max_length=254)
# TODO: Django 1.8 sets email to max_length=254, so there is no point in keeping this,
# uniqueness can be checked at app level, although it's better to have a db index (for login)
# this should be change to the good old OneToOneField.
username = models.CharField(_("username"), max_length=30, unique=True, db_index=True,
help_text=_('Required. 30 characters or fewer. Letters, numbers and '
'@/./+/-/_ characters'),

View File

@ -55,8 +55,6 @@ CACHES = {
},
}
AUTH_USER_MODEL = 'spirit.User'
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
'spirit.backends.user.EmailAuthBackend',

View File

@ -7,3 +7,4 @@ from . import topic
from . import topic_notification
from . import topic_poll
from . import topic_unread
from . import user

View File

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db.models.signals import post_save
from django.contrib.auth import get_user_model
from ...models.user import UserProfile
User = get_user_model()
def update_or_create_user_profile(sender, instance, created, **kwargs):
user = instance
if created:
UserProfile.objects.create(user=user)
else:
user.st.save()
post_save.connect(update_or_create_user_profile, sender=User, dispatch_uid=__name__)

View File

@ -36,7 +36,7 @@
<script src="{% static "spirit/scripts/notification.js" %}"></script>
{% endif %}
{% if user.is_moderator %}
{% if user.st.is_moderator %}
<script src="{% static "spirit/scripts/move_comments.js" %}"></script>
{% endif %}

View File

@ -17,12 +17,12 @@
<div class="header-tab-content js-tab-content js-user-content">
<nav class="header-nav">
<ul class="menu">
<li><a class="menu-link" href="{% url "spirit:profile-detail" pk=user.pk slug=user.slug %}">{% trans "Profile" %}</a></li>
<li><a class="menu-link" href="{% url "spirit:profile-detail" pk=user.pk slug=user.st.slug %}">{% trans "Profile" %}</a></li>
<li><a class="menu-link" href="{% url "spirit:topic-active" %}">{% trans "Topics" %}</a></li>
<li><a class="menu-link" href="{% url "spirit:topic-unread-list" %}">{% trans "Unread topics" %}</a></li>
<li><a class="menu-link" href="{% url "spirit:private-list" %}">{% trans "Private topics" %}</a></li>
{% if user.is_administrator %}
{% if user.st.is_administrator %}
<li><a class="menu-link" href="{% url "spirit:admin" %}">{% trans "Admin" %}</a></li>
{% endif %}

View File

@ -41,7 +41,7 @@
<img class="comment-avatar" src="{% get_gravatar_url user=flag.comment.user size=50 %}" />
<div class="comment-username">
<a href="{{ flag.comment.user.get_absolute_url }}">{{ flag.comment.user.username }}</a>
<a href="{{ flag.comment.user.st.get_absolute_url }}">{{ flag.comment.user.username }}</a>
</div>
</div>
@ -73,7 +73,7 @@
<img class="comment-avatar" src="{% get_gravatar_url user=f.user size=50 %}" />
<div class="comment-username">
<a href="{{ f.user.get_absolute_url }}">{{ f.user.username }}</a>
<a href="{{ f.user.st.get_absolute_url }}">{{ f.user.username }}</a>
</div>
</div>

View File

@ -10,6 +10,7 @@
<form action="." method="post">
{% csrf_token %}
{% include "spirit/_form.html" with form=uform %}
{% include "spirit/_form.html" %}
<input class="button" type="submit" name="post" value="{% trans "Save" %}" />

View File

@ -17,7 +17,7 @@
<div class="comment-info">
<div class="comment-username">
<a class="username{% if c.user.is_administrator %} is-admin{% elif c.user.is_moderator %} is-mod{% endif %}" href="{{ c.user.get_absolute_url }}">{{ c.user.username }}</a><span class="comment-realname">{{ c.user.get_full_name }}</span>
<a class="username{% if c.user.st.is_administrator %} is-admin{% elif c.user.st.is_moderator %} is-mod{% endif %}" href="{{ c.user.st.get_absolute_url }}">{{ c.user.username }}</a><span class="comment-realname">{{ c.user.get_full_name }}</span>
</div>
<ul class="comment-date">
@ -43,7 +43,7 @@
{% if not c.action %}
<ul class="comment-actions">
{% if user.is_authenticated %}
{% if user.is_moderator %}
{% if user.st.is_moderator %}
<li><a href="{% url "spirit:comment-delete" c.pk %}"><i class="fa fa-times"></i> {% trans "delete" %}</a></li>
{% endif %}
@ -63,7 +63,7 @@
{% endifnotequal %}
{% endif %}
{% if user.is_moderator or c.user.pk == user.pk %}
{% if user.st.is_moderator or c.user.pk == user.pk %}
<li><a href="{% url "spirit:comment-update" pk=c.pk %}" >{% trans "edit" %}</a></li>
{% endif %}
@ -97,14 +97,14 @@
<div class="comment-media">
<div class="comment-img">
<div class="comment-removed">
<a href="{{ c.user.get_absolute_url }}">{{ c.user.username }}</a>
<a href="{{ c.user.st.get_absolute_url }}">{{ c.user.username }}</a>
</div>
</div>
<div class="comment-body">
<div class="comment-text">
{% if user.is_moderator %}
{% if user.st.is_moderator %}
{{ c.comment_html|safe }}
{% else %}
{% trans "This comment was deleted" %}.
@ -113,7 +113,7 @@
</div>
</div>
{% if user.is_moderator %}
{% if user.st.is_moderator %}
<ul class="comment-actions">
<li><a href="{% url "spirit:comment-undelete" c.pk %}"><i class="fa fa-times"></i> {% trans "undelete" %}</a></li>
</ul>

View File

@ -24,7 +24,7 @@
<div class="comment-info">
<div class="comment-username">
<a href="{{ c.comment_fk.user.get_absolute_url }}">{{ c.comment_fk.user.username }}</a>
<a href="{{ c.comment_fk.user.st.get_absolute_url }}">{{ c.comment_fk.user.username }}</a>
</div>
<ul class="comment-date">

View File

@ -26,14 +26,14 @@
{{ topic.title }}
{% if user.is_moderator %}
{% if user.st.is_moderator %}
<a class="head-edit-link" href="{% url "spirit:topic-update" topic.pk %}"><i class="fa fa-pencil"></i> {% trans "edit" %}</a>
{% elif user.pk == topic.user.pk and not topic.is_closed %}
<a class="head-edit-link" href="{% url "spirit:topic-update" topic.pk %}"><i class="fa fa-pencil"></i> {% trans "edit" %}</a>
{% endif %}
</h1>
{% if user.is_moderator %}
{% if user.st.is_moderator %}
<div class="topic-moderation js-tabs-container">
<a class="dropdown-button js-tab" href="#" data-related=".js-mod-content"><i class="fa fa-cogs"></i></a>
@ -120,7 +120,7 @@
} );
{% if user.is_moderator %}
{% if user.st.is_moderator %}
$('.js-show-move-comments').move_comments( {
csrfToken: "{{ csrf_token }}",
target: "{% url "spirit:comment-move" topic.pk %}",

View File

@ -2,7 +2,7 @@
{% for n in notifications %}
<div class="row">
{% url "spirit:profile-detail" pk=n.comment.user.pk slug=n.comment.user.slug as url_profile %}
{% url "spirit:profile-detail" pk=n.comment.user.pk slug=n.comment.user.st.slug as url_profile %}
{% url "spirit:comment-find" pk=n.comment.pk as url_topic %}
{% if n.is_comment %}

View File

@ -14,13 +14,13 @@
</li><!--
--><li>
<div class="profile-title">{% trans "Seen" %}</div>
<div class="profile-date">{{ p_user.last_seen|shortnaturaltime }}</div>
<div class="profile-date">{{ p_user.st.last_seen|shortnaturaltime }}</div>
</li>
{% if user.is_administrator %}
{% if user.st.is_administrator %}
<li>
<div class="profile-title">{% trans "Last IP" %}</div>
<div class="profile-date">{{ p_user.last_ip }}</div>
<div class="profile-date">{{ p_user.st.last_ip }}</div>
</li>
{% endif %}
</ul>
@ -36,14 +36,14 @@
</div>
{% endifequal %}
{% if user.is_administrator %}
{% if user.st.is_administrator %}
<div class="profile-preferences">
<a class="button" href="{% url "spirit:admin-user-edit" user_id=p_user.pk %}"><i class="fa fa-cog"></i> {% trans "Edit user" %}</a>
</div>
{% endif %}
<ul class="tabs">
<li><a class="tab-link{% ifequal active_tab 0 %} is-selected{% endifequal %}" href="{% url "spirit:profile-detail" pk=p_user.pk slug=p_user.slug %}" >{% trans "Comments" %}</a></li><!--
--><li><a class="tab-link{% ifequal active_tab 1 %} is-selected{% endifequal %}" href="{% url "spirit:profile-topics" pk=p_user.pk slug=p_user.slug %}" >{% trans "Topics" %}</a></li><!--
--><li><a class="tab-link{% ifequal active_tab 2 %} is-selected{% endifequal %}" href="{% url "spirit:profile-likes" pk=p_user.pk slug=p_user.slug %}" >{% trans "Likes" %}</a></li>
<li><a class="tab-link{% ifequal active_tab 0 %} is-selected{% endifequal %}" href="{% url "spirit:profile-detail" pk=p_user.pk slug=p_user.st.slug %}" >{% trans "Comments" %}</a></li><!--
--><li><a class="tab-link{% ifequal active_tab 1 %} is-selected{% endifequal %}" href="{% url "spirit:profile-topics" pk=p_user.pk slug=p_user.st.slug %}" >{% trans "Topics" %}</a></li><!--
--><li><a class="tab-link{% ifequal active_tab 2 %} is-selected{% endifequal %}" href="{% url "spirit:profile-likes" pk=p_user.pk slug=p_user.st.slug %}" >{% trans "Likes" %}</a></li>
</ul>

View File

@ -15,7 +15,7 @@
<div class="comment-info">
<div class="comment-username">
<a href="{{ c.user.get_absolute_url }}">{{ c.user.username }}</a>
<a href="{{ c.user.st.get_absolute_url }}">{{ c.user.username }}</a>
</div>
<ul class="comment-date">

View File

@ -11,12 +11,12 @@
<h1 class="headline">{% trans "Menu" %}</h1>
<ul class="menu">
<li><a class="menu-link" href="{% url "spirit:profile-detail" pk=user.pk slug=user.slug %}">{% trans "Profile" %}</a></li>
<li><a class="menu-link" href="{% url "spirit:profile-detail" pk=user.pk slug=user.st.slug %}">{% trans "Profile" %}</a></li>
<li><a class="menu-link" href="{% url "spirit:topic-active" %}">{% trans "Topics" %}</a></li>
<li><a class="menu-link" href="{% url "spirit:topic-unread-list" %}">{% trans "Unread topics" %}</a></li>
<li><a class="menu-link" href="{% url "spirit:private-list" %}">{% trans "Private topics" %}</a></li>
{% if user.is_administrator %}
{% if user.st.is_administrator %}
<li><a class="menu-link" href="{% url "spirit:admin" %}">{% trans "Admin" %}</a></li>
{% endif %}

View File

@ -22,6 +22,7 @@
<form action="." method="post">
{% csrf_token %}
{% include "spirit/_form.html" with form=uform %}
{% include "spirit/_form.html" %}
<input class="button" type="submit" name="post" value="{% trans "Save" %}" />

View File

@ -11,4 +11,4 @@ from .. import register
@register.simple_tag()
def get_avatar_color(user):
# returns 0-215
return smart_text(int(215 * math.log10(user.id)))
return smart_text(int(215 * math.log10(user.pk)))

View File

@ -18,7 +18,7 @@ def moderator_required(view_func):
return redirect_to_login(next=request.get_full_path(),
login_url=settings.LOGIN_URL)
if not user.is_moderator:
if not user.st.is_moderator:
raise PermissionDenied
return view_func(request, *args, **kwargs)
@ -35,7 +35,7 @@ def administrator_required(view_func):
return redirect_to_login(next=request.get_full_path(),
login_url=settings.LOGIN_URL)
if not user.is_administrator:
if not user.st.is_administrator:
raise PermissionDenied
return view_func(request, *args, **kwargs)
@ -48,7 +48,7 @@ def guest_only(view_func):
@wraps(view_func)
def wrapper(request, *args, **kwargs):
if request.user.is_authenticated():
return redirect(request.GET.get('next', request.user.get_absolute_url()))
return redirect(request.GET.get('next', request.user.st.get_absolute_url()))
return view_func(request, *args, **kwargs)

View File

@ -71,7 +71,7 @@ class InlineLexer(mistune.InlineLexer):
# Already mentioned?
if username in self.mentions:
user = self.mentions[username]
return self.renderer.mention(username, user.get_absolute_url())
return self.renderer.mention(username, user.st.get_absolute_url())
# Mentions limiter
if self._mention_count >= settings.ST_MENTIONS_PER_COMMENT:
@ -87,4 +87,4 @@ class InlineLexer(mistune.InlineLexer):
return m.group(0)
self.mentions[username] = user
return self.renderer.mention(username, user.get_absolute_url())
return self.renderer.mention(username, user.st.get_absolute_url())

View File

@ -31,7 +31,11 @@ class AutoSlugField(SlugField):
if default or not add or not self.populate_from:
return default
value = getattr(instance, self.populate_from)
inst = instance
for attr in self.populate_from.split('.'):
value = getattr(inst, attr)
inst = value
if value is None:
return default

View File

@ -38,7 +38,7 @@ class TokenGenerator(object):
class UserActivationTokenGenerator(TokenGenerator):
def _uid(self, user):
return ";".join((smart_text(user.pk), smart_text(user.is_verified)))
return ";".join((smart_text(user.pk), smart_text(user.st.is_verified)))
class UserEmailChangeTokenGenerator(TokenGenerator):

View File

@ -12,7 +12,7 @@ from djconfig import config
from ...utils.paginator import yt_paginate
from spirit.utils.decorators import administrator_required
from spirit.forms.admin import UserEditForm
from spirit.forms.admin import UserForm, UserProfileForm
User = get_user_model()
@ -23,16 +23,22 @@ def user_edit(request, user_id):
user = get_object_or_404(User, pk=user_id)
if request.method == 'POST':
form = UserEditForm(data=request.POST, instance=user)
uform = UserForm(data=request.POST, instance=user)
form = UserProfileForm(data=request.POST, instance=user.st)
if form.is_valid():
if uform.is_valid() and form.is_valid():
uform.save()
form.save()
messages.info(request, _("This profile has been updated!"))
return redirect(request.GET.get("next", request.get_full_path()))
else:
form = UserEditForm(instance=user)
uform = UserForm(instance=user)
form = UserProfileForm(instance=user.st)
context = {'form': form, }
context = {
'form': form,
'uform': uform
}
return render(request, 'spirit/admin/user/user_edit.html', context)
@ -40,7 +46,7 @@ def user_edit(request, user_id):
@administrator_required
def user_list(request):
users = yt_paginate(
User.objects.all(),
User.objects.all().order_by('-date_joined', '-pk'),
per_page=config.topics_per_page,
page_number=request.GET.get('page', 1)
)
@ -51,7 +57,7 @@ def user_list(request):
@administrator_required
def user_admins(request):
users = yt_paginate(
User.objects.filter(is_administrator=True),
User.objects.filter(st__is_administrator=True).order_by('-date_joined', '-pk'),
per_page=config.topics_per_page,
page_number=request.GET.get('page', 1)
)
@ -62,7 +68,7 @@ def user_admins(request):
@administrator_required
def user_mods(request):
users = yt_paginate(
User.objects.filter(is_moderator=True, is_administrator=False),
User.objects.filter(st__is_moderator=True, st__is_administrator=False).order_by('-date_joined', '-pk'),
per_page=config.topics_per_page,
page_number=request.GET.get('page', 1)
)
@ -73,7 +79,7 @@ def user_mods(request):
@administrator_required
def user_unactive(request):
users = yt_paginate(
User.objects.filter(is_active=False),
User.objects.filter(is_active=False).order_by('-date_joined', '-pk'),
per_page=config.topics_per_page,
page_number=request.GET.get('page', 1)
)

View File

@ -23,7 +23,8 @@ from ..utils.paginator import yt_paginate
from ..models.topic import Topic
from ..models.comment import Comment
from ..forms.user import UserProfileForm, RegistrationForm, LoginForm, EmailChangeForm, ResendActivationForm
from ..forms.user import UserProfileForm, RegistrationForm, \
LoginForm, EmailChangeForm, ResendActivationForm, UserForm
User = get_user_model()
@ -34,7 +35,7 @@ User = get_user_model()
def custom_login(request, **kwargs):
# Current Django 1.5 login view does not redirect somewhere if the user is logged in
if request.user.is_authenticated():
return redirect(request.GET.get('next', request.user.get_absolute_url()))
return redirect(request.GET.get('next', request.user.st.get_absolute_url()))
if request.is_limited and request.method == "POST":
return redirect(request.get_full_path())
@ -95,7 +96,7 @@ def registration_activation(request, pk, token):
activation = UserActivationTokenGenerator()
if activation.is_valid(user, token):
user.is_verified = True
user.st.is_verified = True
user.is_active = True
user.save()
messages.info(request, _("Your account has been activated!"))
@ -131,16 +132,22 @@ def resend_activation_email(request):
@login_required
def profile_update(request):
if request.method == 'POST':
form = UserProfileForm(data=request.POST, instance=request.user)
uform = UserForm(data=request.POST, instance=request.user)
form = UserProfileForm(data=request.POST, instance=request.user.st)
if form.is_valid():
if uform.is_valid() and form.is_valid():
uform.save()
form.save()
messages.info(request, _("Your profile has been updated!"))
return redirect(reverse('spirit:profile-update'))
else:
form = UserProfileForm(instance=request.user)
uform = UserForm(instance=request.user)
form = UserProfileForm(instance=request.user.st)
context = {'form': form, }
context = {
'form': form,
'uform': uform
}
return render(request, 'spirit/user/profile_update.html', context)
@ -196,8 +203,8 @@ def email_change_confirm(request, token):
def profile_topics(request, pk, slug):
p_user = get_object_or_404(User, pk=pk)
if p_user.slug != slug:
url = reverse("spirit:profile-topics", kwargs={'pk': p_user.pk, 'slug': p_user.slug})
if p_user.st.slug != slug:
url = reverse("spirit:profile-topics", kwargs={'pk': p_user.pk, 'slug': p_user.st.slug})
return HttpResponsePermanentRedirect(url)
topics = Topic.objects\
@ -225,8 +232,8 @@ def profile_topics(request, pk, slug):
def profile_comments(request, pk, slug):
p_user = get_object_or_404(User, pk=pk)
if p_user.slug != slug:
url = reverse("spirit:profile-detail", kwargs={'pk': p_user.pk, 'slug': p_user.slug})
if p_user.st.slug != slug:
url = reverse("spirit:profile-detail", kwargs={'pk': p_user.pk, 'slug': p_user.st.slug})
return HttpResponsePermanentRedirect(url)
comments = Comment.objects\
@ -251,8 +258,8 @@ def profile_comments(request, pk, slug):
def profile_likes(request, pk, slug):
p_user = get_object_or_404(User, pk=pk)
if p_user.slug != slug:
url = reverse("spirit:profile-likes", kwargs={'pk': p_user.pk, 'slug': p_user.slug})
if p_user.st.slug != slug:
url = reverse("spirit:profile-likes", kwargs={'pk': p_user.pk, 'slug': p_user.st.slug})
return HttpResponsePermanentRedirect(url)
comments = Comment.objects\

View File

@ -6,7 +6,6 @@ from django.test import TestCase, RequestFactory
from django.core.urlresolvers import reverse
from django.core.cache import cache
from django.core.exceptions import PermissionDenied
from django.contrib.auth.models import User as UserModel
from django.contrib.auth import get_user_model
from djconfig.utils import override_djconfig
@ -16,7 +15,7 @@ from . import utils
from spirit.views.admin import user, category, comment_flag, config, index, topic
from spirit.models.category import Category
from spirit.models.comment_flag import CommentFlag, Flag
from spirit.forms.admin import UserEditForm, CategoryForm, BasicConfigForm, CommentFlagForm
from spirit.forms.admin import UserForm, CategoryForm, BasicConfigForm, CommentFlagForm, UserProfileForm
User = get_user_model()
@ -26,14 +25,16 @@ class AdminViewTest(TestCase):
def setUp(self):
cache.clear()
self.user = utils.create_user(is_administrator=True)
self.user = utils.create_user()
self.user.st.is_administrator = True
self.user.st.save()
self.category = utils.create_category()
self.topic = utils.create_topic(self.category, user=self.user)
def test_permission_denied_to_non_admin(self):
req = RequestFactory().get('/')
req.user = UserModel()
req.user.is_administrator = False
req.user = self.user
req.user.st.is_administrator = False
self.assertRaises(PermissionDenied, category.category_list, req)
self.assertRaises(PermissionDenied, category.category_create, req)
@ -104,7 +105,9 @@ class AdminViewTest(TestCase):
"""
List of admins paginated
"""
user2 = utils.create_user(is_administrator=True)
user2 = utils.create_user()
user2.st.is_administrator = True
user2.st.save()
utils.login(self)
response = self.client.get(reverse('spirit:admin-user-admins'))
@ -114,7 +117,10 @@ class AdminViewTest(TestCase):
"""
List of mods
"""
mod = utils.create_user(is_moderator=True)
mod = utils.create_user()
mod.st.is_moderator = True
mod.st.save()
utils.login(self)
response = self.client.get(reverse('spirit:admin-user-mods'))
self.assertQuerysetEqual(response.context['users'], map(repr, [mod, ]))
@ -124,12 +130,17 @@ class AdminViewTest(TestCase):
"""
List of mods paginated
"""
utils.create_user(is_moderator=True)
mod = utils.create_user(is_moderator=True)
mod = utils.create_user()
mod.st.is_moderator = True
mod.st.save()
mod2 = utils.create_user()
mod2.st.is_moderator = True
mod2.st.save()
utils.login(self)
response = self.client.get(reverse('spirit:admin-user-mods'))
self.assertQuerysetEqual(response.context['users'], map(repr, [mod, ]))
self.assertQuerysetEqual(response.context['users'], map(repr, [mod2, ]))
def test_user_unactive(self):
"""
@ -387,7 +398,10 @@ class AdminFormTest(TestCase):
"is_administrator": True,
"is_moderator": True,
"is_active": True}
form = UserEditForm(data=form_data)
form = UserForm(data=form_data)
self.assertEqual(form.is_valid(), True)
form = UserProfileForm(data=form_data)
self.assertEqual(form.is_valid(), True)
def test_category(self):

View File

@ -10,7 +10,6 @@ from django.core.cache import cache
from django.core.urlresolvers import reverse
from django.template import Template, Context
from django.core.exceptions import PermissionDenied
from django.contrib.auth.models import User as UserModel
from django.contrib.auth import get_user_model
from django.conf import settings
from django.core.files.uploadedfile import SimpleUploadedFile
@ -29,6 +28,7 @@ from spirit.utils import markdown
from spirit.views.comment import comment_delete
from spirit.models.topic import Topic
from spirit.models.category import Category
from spirit.models.user import UserProfile
User = get_user_model()
@ -221,7 +221,7 @@ class CommentViewTest(TestCase):
"""
moderators can update other people comments
"""
User.objects.filter(pk=self.user.pk).update(is_moderator=True)
UserProfile.objects.filter(user__pk=self.user.pk).update(is_moderator=True)
user = utils.create_user()
comment = utils.create_comment(user=user, topic=self.topic)
@ -237,7 +237,7 @@ class CommentViewTest(TestCase):
"""
moderators can not update comments in private topics they has no access
"""
User.objects.filter(pk=self.user.pk).update(is_moderator=True)
UserProfile.objects.filter(user__pk=self.user.pk).update(is_moderator=True)
user = utils.create_user()
topic_private = utils.create_private_topic()
comment = utils.create_comment(user=user, topic=topic_private.topic)
@ -270,15 +270,17 @@ class CommentViewTest(TestCase):
def test_comment_delete_permission_denied_to_non_moderator(self):
req = RequestFactory().get('/')
req.user = UserModel()
req.user.is_moderator = False
req.user = self.user
req.user.st.is_moderator = False
self.assertRaises(PermissionDenied, comment_delete, req)
def test_comment_delete(self):
"""
comment delete
"""
self.user = utils.create_user(is_moderator=True)
self.user = utils.create_user()
self.user.st.is_moderator = True
self.user.st.save()
comment = utils.create_comment(user=self.user, topic=self.topic)
utils.login(self)
@ -295,7 +297,9 @@ class CommentViewTest(TestCase):
"""
comment undelete
"""
self.user = utils.create_user(is_moderator=True)
self.user = utils.create_user()
self.user.st.is_moderator = True
self.user.st.save()
comment = utils.create_comment(user=self.user, topic=self.topic, is_removed=True)
utils.login(self)
@ -313,7 +317,7 @@ class CommentViewTest(TestCase):
comment move to another topic
"""
utils.login(self)
self.user.is_moderator = True
self.user.st.is_moderator = True
self.user.save()
comment = utils.create_comment(user=self.user, topic=self.topic)
comment2 = utils.create_comment(user=self.user, topic=self.topic)
@ -343,7 +347,7 @@ class CommentViewTest(TestCase):
comment_moved.connect(comment_moved_handler)
utils.login(self)
self.user.is_moderator = True
self.user.st.is_moderator = True
self.user.save()
comment = utils.create_comment(user=self.user, topic=self.topic)

View File

@ -178,7 +178,7 @@ class TopicViewTest(TestCase):
topic_post_moderate.connect(topic_post_moderate_handler)
utils.login(self)
self.user.is_moderator = True
self.user.st.is_moderator = True
self.user.save()
category = utils.create_category()

View File

@ -24,7 +24,7 @@ class TopicViewTest(TestCase):
delete topic
"""
utils.login(self)
self.user.is_moderator = True
self.user.st.is_moderator = True
self.user.save()
category = utils.create_category()
@ -41,7 +41,7 @@ class TopicViewTest(TestCase):
undelete topic
"""
utils.login(self)
self.user.is_moderator = True
self.user.st.is_moderator = True
self.user.save()
category = utils.create_category()
@ -62,7 +62,7 @@ class TopicViewTest(TestCase):
topic_post_moderate.connect(topic_post_moderate_handler)
utils.login(self)
self.user.is_moderator = True
self.user.st.is_moderator = True
self.user.save()
category = utils.create_category()
@ -84,7 +84,7 @@ class TopicViewTest(TestCase):
topic_post_moderate.connect(topic_post_moderate_handler)
utils.login(self)
self.user.is_moderator = True
self.user.st.is_moderator = True
self.user.save()
category = utils.create_category()
@ -106,7 +106,7 @@ class TopicViewTest(TestCase):
topic_post_moderate.connect(topic_post_moderate_handler)
utils.login(self)
self.user.is_moderator = True
self.user.st.is_moderator = True
self.user.save()
category = utils.create_category()
@ -128,7 +128,7 @@ class TopicViewTest(TestCase):
topic_post_moderate.connect(topic_post_moderate_handler)
utils.login(self)
self.user.is_moderator = True
self.user.st.is_moderator = True
self.user.save()
category = utils.create_category()
@ -150,7 +150,7 @@ class TopicViewTest(TestCase):
topic_post_moderate.connect(topic_post_moderate_handler)
utils.login(self)
self.user.is_moderator = True
self.user.st.is_moderator = True
self.user.save()
category = utils.create_category()
@ -172,7 +172,7 @@ class TopicViewTest(TestCase):
topic_post_moderate.connect(topic_post_moderate_handler)
utils.login(self)
self.user.is_moderator = True
self.user.st.is_moderator = True
self.user.save()
category = utils.create_category()

View File

@ -16,11 +16,11 @@ from djconfig.utils import override_djconfig
from . import utils
from spirit.forms.user import RegistrationForm, UserProfileForm, EmailChangeForm, ResendActivationForm
from spirit.forms.user import RegistrationForm, UserProfileForm, EmailChangeForm, ResendActivationForm, UserForm
from spirit.backends.user import EmailAuthBackend
from spirit.models.comment_like import CommentLike
from spirit.utils.user.tokens import UserActivationTokenGenerator, UserEmailChangeTokenGenerator
from spirit.models.user import User as UserModel
from spirit.models.user import UserProfile
from spirit.models.topic import Topic
from spirit.models.comment import Comment
from spirit.models.comment_bookmark import CommentBookmark
@ -60,7 +60,7 @@ class UserViewTest(TestCase):
"""
utils.login(self)
response = self.client.get(reverse('spirit:user-login'))
expected_url = self.user.get_absolute_url()
expected_url = self.user.st.get_absolute_url()
self.assertRedirects(response, expected_url, status_code=302)
# next
response = self.client.get(reverse('spirit:user-login') + '?next=/fakepath/')
@ -111,7 +111,7 @@ class UserViewTest(TestCase):
"""
utils.login(self)
response = self.client.get(reverse("spirit:profile-topics", kwargs={'pk': self.user2.pk,
'slug': self.user2.slug}))
'slug': self.user2.st.slug}))
self.assertEqual(response.status_code, 200)
self.assertQuerysetEqual(response.context['topics'], [repr(self.topic), ])
self.assertEqual(repr(response.context['p_user']), repr(self.user2))
@ -132,7 +132,7 @@ class UserViewTest(TestCase):
utils.login(self)
response = self.client.get(reverse("spirit:profile-topics", kwargs={'pk': self.user2.pk,
'slug': self.user2.slug}))
'slug': self.user2.st.slug}))
self.assertQuerysetEqual(response.context['topics'], map(repr, [topic_b, topic_c, topic_a]))
def test_profile_topics_bookmarks(self):
@ -143,7 +143,7 @@ class UserViewTest(TestCase):
utils.login(self)
response = self.client.get(reverse("spirit:profile-topics",
kwargs={'pk': self.user2.pk, 'slug': self.user2.slug}))
kwargs={'pk': self.user2.pk, 'slug': self.user2.st.slug}))
self.assertEqual(response.status_code, 200)
self.assertQuerysetEqual(response.context['topics'], [repr(self.topic), ])
self.assertEqual(response.context['topics'][0].bookmark, bookmark)
@ -157,7 +157,7 @@ class UserViewTest(TestCase):
utils.login(self)
response = self.client.get(reverse("spirit:profile-topics", kwargs={'pk': self.user2.pk,
'slug': self.user2.slug}))
'slug': self.user2.st.slug}))
self.assertEqual(response.status_code, 200)
self.assertQuerysetEqual(response.context['topics'], [repr(topic), ])
@ -179,7 +179,7 @@ class UserViewTest(TestCase):
utils.login(self)
response = self.client.get(reverse("spirit:profile-topics", kwargs={'pk': self.user2.pk,
'slug': self.user2.slug}))
'slug': self.user2.st.slug}))
self.assertQuerysetEqual(response.context['topics'], [])
def test_profile_topics_invalid_slug(self):
@ -190,7 +190,7 @@ class UserViewTest(TestCase):
response = self.client.get(reverse("spirit:profile-topics", kwargs={'pk': self.user2.pk,
'slug': "invalid"}))
expected_url = reverse("spirit:profile-topics", kwargs={'pk': self.user2.pk,
'slug': self.user2.slug})
'slug': self.user2.st.slug})
self.assertRedirects(response, expected_url, status_code=301)
def test_profile_comments(self):
@ -201,7 +201,7 @@ class UserViewTest(TestCase):
comment = utils.create_comment(user=self.user2, topic=self.topic)
utils.create_comment(user=self.user, topic=self.topic)
response = self.client.get(reverse("spirit:profile-detail", kwargs={'pk': self.user2.pk,
'slug': self.user2.slug}))
'slug': self.user2.st.slug}))
self.assertEqual(response.status_code, 200)
self.assertQuerysetEqual(response.context['comments'], [repr(comment), ])
self.assertEqual(repr(response.context['p_user']), repr(self.user2))
@ -219,7 +219,7 @@ class UserViewTest(TestCase):
utils.login(self)
response = self.client.get(reverse("spirit:profile-detail", kwargs={'pk': self.user2.pk,
'slug': self.user2.slug}))
'slug': self.user2.st.slug}))
self.assertQuerysetEqual(response.context['comments'], map(repr, [comment_b, comment_c, comment_a]))
@override_djconfig(comments_per_page=1)
@ -232,7 +232,7 @@ class UserViewTest(TestCase):
utils.login(self)
response = self.client.get(reverse("spirit:profile-detail", kwargs={'pk': self.user2.pk,
'slug': self.user2.slug}))
'slug': self.user2.st.slug}))
self.assertEqual(response.status_code, 200)
self.assertQuerysetEqual(response.context['comments'], [repr(comment), ])
@ -257,7 +257,7 @@ class UserViewTest(TestCase):
utils.login(self)
response = self.client.get(reverse("spirit:profile-detail", kwargs={'pk': self.user2.pk,
'slug': self.user2.slug}))
'slug': self.user2.st.slug}))
self.assertQuerysetEqual(response.context['comments'], [])
def test_profile_comments_invalid_slug(self):
@ -268,7 +268,7 @@ class UserViewTest(TestCase):
response = self.client.get(reverse("spirit:profile-detail", kwargs={'pk': self.user2.pk,
'slug': "invalid"}))
expected_url = reverse("spirit:profile-detail", kwargs={'pk': self.user2.pk,
'slug': self.user2.slug})
'slug': self.user2.st.slug})
self.assertRedirects(response, expected_url, status_code=301)
def test_profile_likes(self):
@ -281,7 +281,7 @@ class UserViewTest(TestCase):
like = CommentLike.objects.create(user=self.user2, comment=comment)
CommentLike.objects.create(user=self.user, comment=comment2)
response = self.client.get(reverse("spirit:profile-likes", kwargs={'pk': self.user2.pk,
'slug': self.user2.slug}))
'slug': self.user2.st.slug}))
self.assertEqual(response.status_code, 200)
self.assertQuerysetEqual(response.context['comments'], [repr(like.comment), ])
self.assertEqual(repr(response.context['p_user']), repr(self.user2))
@ -302,7 +302,7 @@ class UserViewTest(TestCase):
utils.login(self)
response = self.client.get(reverse("spirit:profile-likes", kwargs={'pk': self.user2.pk,
'slug': self.user2.slug}))
'slug': self.user2.st.slug}))
self.assertQuerysetEqual(response.context['comments'], map(repr, [comment_b, comment_c, comment_a]))
def test_profile_likes_dont_show_removed_or_private(self):
@ -331,7 +331,7 @@ class UserViewTest(TestCase):
utils.login(self)
response = self.client.get(reverse("spirit:profile-likes", kwargs={'pk': self.user2.pk,
'slug': self.user2.slug}))
'slug': self.user2.st.slug}))
self.assertQuerysetEqual(response.context['comments'], [])
def test_profile_likes_invalid_slug(self):
@ -342,7 +342,7 @@ class UserViewTest(TestCase):
response = self.client.get(reverse("spirit:profile-likes", kwargs={'pk': self.user2.pk,
'slug': "invalid"}))
expected_url = reverse("spirit:profile-likes", kwargs={'pk': self.user2.pk,
'slug': self.user2.slug})
'slug': self.user2.st.slug})
self.assertRedirects(response, expected_url, status_code=301)
@override_djconfig(comments_per_page=1)
@ -357,7 +357,7 @@ class UserViewTest(TestCase):
utils.login(self)
response = self.client.get(reverse("spirit:profile-likes", kwargs={'pk': self.user2.pk,
'slug': self.user2.slug}))
'slug': self.user2.st.slug}))
self.assertEqual(response.status_code, 200)
self.assertQuerysetEqual(response.context['comments'], [repr(like.comment), ])
@ -372,7 +372,7 @@ class UserViewTest(TestCase):
# post
form_data = {'first_name': 'foo', 'last_name': 'bar',
'location': 'spirit', 'timezone': self.user.timezone}
'location': 'spirit', 'timezone': self.user.st.timezone}
response = self.client.post(reverse('spirit:profile-update'),
form_data)
expected_url = reverse('spirit:profile-update')
@ -449,7 +449,7 @@ class UserViewTest(TestCase):
"""
registration activation
"""
self.user.is_verified = False
self.user.st.is_verified = False
self.user.is_active = False
self.user.save()
token = UserActivationTokenGenerator().generate(self.user)
@ -464,11 +464,12 @@ class UserViewTest(TestCase):
Activation token should not work if user is verified
ActiveUserMiddleware required
"""
self.user.is_verified = False
self.user.st.is_verified = False
token = UserActivationTokenGenerator().generate(self.user)
utils.login(self)
User.objects.filter(pk=self.user.pk).update(is_active=False, is_verified=True)
User.objects.filter(pk=self.user.pk).update(is_active=False)
UserProfile.objects.filter(user__pk=self.user.pk).update(is_verified=True)
response = self.client.get(reverse('spirit:registration-activation', kwargs={'pk': self.user.pk,
'token': token}))
expected_url = reverse("spirit:user-login")
@ -543,7 +544,9 @@ class UserViewTest(TestCase):
"""
resend_activation_email invalid if is_verified was set
"""
user = utils.create_user(password="foo", is_verified=True)
user = utils.create_user(password="foo")
user.st.is_verified = True
user.st.save()
form_data = {'email': user.email,
'password': "foo"}
@ -654,8 +657,11 @@ class UserFormTest(TestCase):
edit user profile
"""
form_data = {'first_name': 'foo', 'last_name': 'bar',
'location': 'spirit', 'timezone': self.user.timezone}
form = UserProfileForm(data=form_data, instance=self.user)
'location': 'spirit', 'timezone': self.user.st.timezone}
form = UserProfileForm(data=form_data, instance=self.user.st)
self.assertEqual(form.is_valid(), True)
form = UserForm(data=form_data, instance=self.user)
self.assertEqual(form.is_valid(), True)
def test_email_change(self):
@ -718,15 +724,17 @@ class UserModelTest(TestCase):
is_superuser should always be is_administrator and is_moderator
test model
"""
user = UserModel(is_superuser=True)
user = User(is_superuser=True)
user.save()
self.assertTrue(user.is_administrator)
self.assertTrue(user.is_moderator)
self.assertTrue(user.st.is_administrator)
self.assertTrue(user.st.is_moderator)
def test_user_administrator(self):
"""
is_administrator should always be is_moderator
"""
user = UserModel(is_administrator=True)
user = User()
user.save()
self.assertTrue(user.is_moderator)
user.st.is_administrator = True
user.st.save()
self.assertTrue(user.st.is_moderator)

View File

@ -12,7 +12,7 @@ from django.test.utils import override_settings
from django.template import Template, Context
from django.utils import translation
from django.utils import timezone
from django.contrib.auth.models import AnonymousUser, User
from django.contrib.auth.models import AnonymousUser
from django.http import HttpResponseRedirect
from django.http import HttpResponse
from django.conf import settings
@ -22,6 +22,7 @@ from django.contrib import messages
from django.utils.translation import ugettext as _
from django.utils.timezone import utc
from django.utils.http import urlunquote
from django.contrib.auth import get_user_model
from spirit.models.category import Category
from spirit.utils.forms import NestedModelChoiceField
@ -38,6 +39,9 @@ from spirit.templatetags.tags.utils.messages import render_messages
from spirit.utils.markdown import Markdown, quotify
User = get_user_model()
class UtilsTests(TestCase):
def setUp(self):
@ -242,6 +246,10 @@ class UtilsTimezoneTests(TestCase):
class UtilsDecoratorsTests(TestCase):
def setUp(self):
cache.clear()
self.user = test_utils.create_user()
def test_moderator_required(self):
"""
Tests the user is logged in and is also a moderator
@ -255,11 +263,11 @@ class UtilsDecoratorsTests(TestCase):
req.user = AnonymousUser()
self.assertIsInstance(view(req), HttpResponseRedirect)
req.user = User()
req.user.is_moderator = False
req.user = self.user
req.user.st.is_moderator = False
self.assertRaises(PermissionDenied, view, req)
req.user.is_moderator = True
req.user.st.is_moderator = True
self.assertIsNone(view(req))
def test_administrator_required(self):
@ -275,11 +283,11 @@ class UtilsDecoratorsTests(TestCase):
req.user = AnonymousUser()
self.assertIsInstance(view(req), HttpResponseRedirect)
req.user = User()
req.user.is_administrator = False
req.user = self.user
req.user.st.is_administrator = False
self.assertRaises(PermissionDenied, view, req)
req.user.is_administrator = True
req.user.st.is_administrator = True
self.assertIsNone(view(req))
@ -287,7 +295,7 @@ class UtilsMarkdownTests(TestCase):
def setUp(self):
cache.clear()
self.user = test_utils.create_user(username="nitely", slug="nitely")
self.user = test_utils.create_user(username="nitely")
self.user2 = test_utils.create_user(username="esteban")
self.user3 = test_utils.create_user(username="áéíóú")
@ -302,9 +310,9 @@ class UtilsMarkdownTests(TestCase):
'<a class="comment-mention" href="%s">@esteban</a>,'
'<a class="comment-mention" href="%s">@\xe1\xe9\xed\xf3\xfa</a>, '
'@fakeone</p>' %
(self.user.get_absolute_url(),
self.user2.get_absolute_url(),
self.user3.get_absolute_url()))
(self.user.st.get_absolute_url(),
self.user2.st.get_absolute_url(),
self.user3.st.get_absolute_url()))
@override_settings(ST_MENTIONS_PER_COMMENT=2)
def test_markdown_mentions_limit(self):
@ -463,7 +471,7 @@ class UtilsUserTests(TestCase):
"""
Validate if user can be activated
"""
self.user.is_verified = False
self.user.st.is_verified = False
activation_token = UserActivationTokenGenerator()
token = activation_token.generate(self.user)
@ -471,7 +479,7 @@ class UtilsUserTests(TestCase):
self.assertFalse(activation_token.is_valid(self.user, "bad token"))
# Invalid after verification
self.user.is_verified = True
self.user.st.is_verified = True
self.assertFalse(activation_token.is_valid(self.user, token))
# Invalid for different user