class AnonymousRequiredMixin(object):

    '''
    Make any view be accessible by unauthenticated users only
    '''

    def dispatch(self, request, *args, **kwargs):
        if request.user.is_authenticated():
            return redirect(settings.LOGIN_REDIRECT_URL)
        return super(AnonymousRequiredMixin, self).dispatch(
            request, *args, **kwargs) class LoginRequiredMixin(object):

    '''
    Bind login requirement to any view
    '''

    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super(LoginRequiredMixin, self).dispatch(*args, **kwargs) class UserAddress(models.Model):

    user = models.OneToOneField('User', related_name='address', editable=False)
    zipcode = models.CharField(max_length=90)
    address_line1 = models.CharField(max_length=120)
    address_line2 = models.CharField(max_length=80, blank=True)
    state = models.ForeignKey('cities_light.Region')
    city = models.ForeignKey('cities_light.City')

    # Verbose names
    zipcode.verbose_name = 'CEP'
    address_line1.verbose_name = 'endereço'
    address_line2.verbose_name = 'complemento'
    state.verbose_name = 'estado'
    city.verbose_name = 'cidade' class DeleteUser(LoginRequiredMixin, FormView):

    form_class = DeleteUserForm
    template_name = 'accounts/delete-user.html'

    def get_form_kwargs(self):
        kwargs = super(DeleteUser, self).get_form_kwargs()
        kwargs['user'] = self.request.user
        return kwargs

    def form_valid(self, form):
        email = self.request.user.email

        # Delete user and logout (clean session)
        self.request.user.delete()
        logout_user(self.request)

        # Put deleted_email into session for feedback form consumption
        self.request.session['deleted_email'] = email
        self.request.session['feedback_success_message'] = (
            'Sua conta foi excluída. Até logo! :(')
        return HttpResponseRedirect('{}?next={}'.format(
            reverse('feedback:create'), reverse('accounts:login'))) class EditNotifications(BaseEditUser, UpdateView):

    form_class = EditNotificationsForm
    title = 'Notificações'
    url_pattern = 'accounts:edit_notifications' class EditPersonalInfo(BaseEditUser, UpdateView):

    fields = ('full_name', 'username', 'email', 'picture',)
    title = 'Informações Pessoais'
    url_pattern = 'accounts:edit_personal_info' class EditProfessionalInfo(BaseEditUser, UpdateView):

    fields = ('job_title', 'bio',)
    title = 'Informações Profissionais'
    url_pattern = 'accounts:edit_professional_info' class EditSecuritySettings(BaseEditUser, UpdateView):

    form_class = PasswordChangeForm
    success_message = 'Configurações de segurança atualizadas com sucesso!'
    template_name = 'accounts/edit_security_settings.html'
    title = 'Segurança'
    url_pattern = 'accounts:edit_security_settings'

    def get_form_kwargs(self):
        kwargs = super(EditSecuritySettings, self).get_form_kwargs()
        kwargs['user'] = kwargs.pop('instance')
        return kwargs class EditUserAddress(BaseEditUser, UpdateView):

    form_class = UserAddressForm
    title = 'Editar Endereço'
    url_pattern = 'accounts:edit_user_address'

    def get_object(self):
        # If the user already has an address, make it the edition target
        return getattr(self.request.user, 'address', None)

    def form_valid(self, form):
        address = form.save(commit=False)
        address.user = self.request.user
        address.save()
        return super(EditUserAddress, self).form_valid(form) class Signup(AnonymousRequiredMixin, CreateView):
    '''
    User Signup
    '''

    form_class = SignupForm
    success_url = reverse_lazy('accounts:edit_dashboard')
    template_name = 'accounts/signup.html'

    def form_valid(self, form):
        response = super(Signup, self).form_valid(form)

        # log user in
        user = authenticate(email=form.cleaned_data['email'],
                            password=form.cleaned_data['password'])
        login_user(self.request, user)

        # Send welcome email upon signup
        user.send_welcome_email()

        # Display a welcome message
        messages.info(
            self.request,
            'Parabéns! Você agora está cadastrado e já pode buscar projetos '
            'para participar. Bem vindo e mãos à obra!')

        return response
from django.contrib.auth import get_user_model
from django.core import mail
from django.core.urlresolvers import reverse
from django.test import TestCase
from brasilcomvc.common.views import AnonymousRequiredMixin, LoginRequiredMixin
from cities_light.models import City
from ..models import UserAddress
from ..views import (
    DeleteUser,
    EditNotifications,
    EditPersonalInfo,
    EditProfessionalInfo,
    EditSecuritySettings,
    EditUserAddress,
    Signup,
)
        self.assertEqual(resp.status_code, 200)
        self.assertTemplateUsed('accounts/password_reset.html')

    def test_inexistent_email_submit_should_fail_silently(self):
        resp = self.client.post(self.url, {'email': 'nil@example.com'})
        self.assertRedirects(resp, reverse('accounts:password_reset_sent'))
        self.assertEqual(len(mail.outbox), 0)

    def test_existent_email_submit_should_proceed(self):
        self._setup_user()
        resp = self.client.post(self.url, {'email': self.user.email})
        self.assertRedirects(resp, reverse('accounts:password_reset_sent'))
        self.assertEqual(len(mail.outbox), 1)
        self.assertEqual(mail.outbox[0].subject, 'Redefinição de senha')

    def test_reset_email_should_have_secret_link(self):
        self._setup_user()
        resp = self.client.post(self.url, {'email': self.user.email})
        reset_url = reverse('accounts:password_reset_confirm', kwargs={
            'uidb64': resp.context['uid'],
            'token': resp.context['token']})
        self.assertIn('http://testserver' + reset_url, mail.outbox[0].body)


class ResetPasswordConfirmTestCase(TestCase):

    def setUp(self):
        self.user = User.objects.create(email='wat@example.com')
        self.user.set_password('forgot-it')
        self.user.save()
        resp = self.client.post(
            reverse('accounts:password_reset'), {'email': self.user.email})
        self.url = reverse('accounts:password_reset_confirm', kwargs={
            'uidb64': resp.context['uid'],
            'token': resp.context['token']})

    def test_secret_link_should_open_final_password_reset_page(self):
        resp = self.client.get(self.url)
        self.assertTemplateUsed(resp, 'accounts/password_reset_confirm.html')

    def test_password_reset_confirm_post_should_update_user_password(self):
        new_pwd = '123'
        resp = self.client.post(
            self.url, {'new_password1': new_pwd, 'new_password2': new_pwd})
        self.assertRedirects(resp, reverse('accounts:login'))
        user = User.objects.get(id=self.user.id)
        self.assertTrue(user.check_password(new_pwd))


class EditPersonalInfoTestCase(TestCase):

    url = reverse('accounts:edit_personal_info')

    def setUp(self):
        data = {'email': 'user@example.com', 'password': '123'}
        user = User.objects.create_user(**data)
        self.client.login(username=data['email'], password=data['password'])
        self.user_id = user.pk

    def test_inherits_login_required_mixin(self):
        self.assertTrue(issubclass(EditPersonalInfo, LoginRequiredMixin))

    def test_form_should_have_right_fields_only(self):
        self.assertEqual(
            EditPersonalInfo.fields,
            ('full_name', 'username', 'email', 'picture',))

    def test_correct_form_submit_should_update_data(self):
        data = {
            'full_name': 'Test User',
            'email': 'new@example.com',
            'username': 'new_username',
        }
        resp = self.client.post(self.url, data)
        self.assertRedirects(resp, self.url)
        user = User.objects.get(pk=self.user_id)
        for key, value in data.items():
            self.assertEqual(getattr(user, key), value)


class EditProfessionalInfoTestCase(TestCase):

    url = reverse('accounts:edit_professional_info')

    def setUp(self):
        data = {'email': 'user@example.com', 'password': '123'}
        user = User.objects.create_user(**data)
        self.client.login(username=data['email'], password=data['password'])
        self.user_id = user.pk

    def test_inherits_login_required_mixin(self):
        self.assertTrue(issubclass(EditProfessionalInfo, LoginRequiredMixin))

    def test_form_should_have_right_fields_only(self):
        self.assertEqual(
            EditProfessionalInfo.fields, ('job_title', 'bio',))

    def test_correct_form_submit_should_update_data(self):
        data = {
            'job_title': 'Python Programmer',
            'bio': 'I am an unusual person who does not like to write bios',
        }
        resp = self.client.post(self.url, data)
        self.assertRedirects(resp, self.url)
        user = User.objects.get(pk=self.user_id)
        for key, value in data.items():
            self.assertEqual(getattr(user, key), value)


class EditNotificationsTestCase(TestCase):

    url = reverse('accounts:edit_notifications')

    def setUp(self):
        data = {'email': 'user@example.com', 'password': '123'}
        user = User.objects.create_user(**data)
        self.client.login(username=data['email'], password=data['password'])
        self.user_id = user.pk

    def test_inherits_login_required_mixin(self):

        self.assertTrue(issubclass(EditNotifications, LoginRequiredMixin))