aboutsummaryrefslogtreecommitdiff
path: root/apps/accounts
diff options
context:
space:
mode:
Diffstat (limited to 'apps/accounts')
-rw-r--r--apps/accounts/__init__.py1
-rw-r--r--apps/accounts/admin.py13
-rw-r--r--apps/accounts/apps.py8
-rw-r--r--apps/accounts/forms.py19
-rw-r--r--apps/accounts/migrations/0001_initial.py55
-rw-r--r--apps/accounts/migrations/__init__.py0
-rw-r--r--apps/accounts/models.py20
-rw-r--r--apps/accounts/signals.py12
-rw-r--r--apps/accounts/tests/__init__.py0
-rw-r--r--apps/accounts/tests/test_models.py13
-rw-r--r--apps/accounts/tests/test_views.py23
-rw-r--r--apps/accounts/urls.py12
-rw-r--r--apps/accounts/views.py32
13 files changed, 208 insertions, 0 deletions
diff --git a/apps/accounts/__init__.py b/apps/accounts/__init__.py
new file mode 100644
index 0000000..9332741
--- /dev/null
+++ b/apps/accounts/__init__.py
@@ -0,0 +1 @@
+default_app_config = 'accounts.apps.AccountAppConfig'
diff --git a/apps/accounts/admin.py b/apps/accounts/admin.py
new file mode 100644
index 0000000..25f873b
--- /dev/null
+++ b/apps/accounts/admin.py
@@ -0,0 +1,13 @@
+from django.contrib import admin
+
+from .models import User, UserProfile
+
+
+@admin.register(User)
+class UserAdmin(admin.ModelAdmin):
+ pass
+
+
+@admin.register(UserProfile)
+class UserProfileAdmin(admin.ModelAdmin):
+ pass
diff --git a/apps/accounts/apps.py b/apps/accounts/apps.py
new file mode 100644
index 0000000..9a7d5ba
--- /dev/null
+++ b/apps/accounts/apps.py
@@ -0,0 +1,8 @@
+from django.apps import AppConfig
+
+
+class AccountAppConfig(AppConfig):
+ name = 'accounts'
+
+ def ready(self):
+ import accounts.signals
diff --git a/apps/accounts/forms.py b/apps/accounts/forms.py
new file mode 100644
index 0000000..d53e754
--- /dev/null
+++ b/apps/accounts/forms.py
@@ -0,0 +1,19 @@
+from django import forms
+from django_registration.forms import RegistrationForm
+
+from .models import User, UserProfile
+
+
+class UserForm(RegistrationForm):
+ class Meta(RegistrationForm.Meta):
+ model = User
+
+
+class ProfileForm(forms.ModelForm):
+ class Meta:
+ model = UserProfile
+ fields = '__all__'
+
+ def __init__(self, *args, **kwargs):
+ self.user = kwargs.pop("user", None)
+ super(ProfileForm, self).__init__(*args, **kwargs)
diff --git a/apps/accounts/migrations/0001_initial.py b/apps/accounts/migrations/0001_initial.py
new file mode 100644
index 0000000..0e2775e
--- /dev/null
+++ b/apps/accounts/migrations/0001_initial.py
@@ -0,0 +1,55 @@
+# Generated by Django 2.1.2 on 2018-11-02 19:01
+
+from django.conf import settings
+import django.contrib.auth.models
+import django.contrib.auth.validators
+from django.db import migrations, models
+import django.db.models.deletion
+import django.utils.timezone
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ('auth', '0009_alter_user_last_name_max_length'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='User',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('password', models.CharField(max_length=128, verbose_name='password')),
+ ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
+ ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
+ ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
+ ('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')),
+ ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
+ ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
+ ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
+ ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
+ ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
+ ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')),
+ ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')),
+ ],
+ options={
+ 'ordering': ['-date_joined'],
+ },
+ managers=[
+ ('objects', django.contrib.auth.models.UserManager()),
+ ],
+ ),
+ migrations.CreateModel(
+ name='UserProfile',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('photo', models.ImageField(blank=True, null=True, upload_to='profile')),
+ ('website', models.CharField(blank=True, default='', max_length=300, null=True)),
+ ('location', models.CharField(blank=True, default='', max_length=300, null=True)),
+ ('bio', models.TextField(blank=True, default='', null=True)),
+ ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
+ ],
+ ),
+ ]
diff --git a/apps/accounts/migrations/__init__.py b/apps/accounts/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apps/accounts/migrations/__init__.py
diff --git a/apps/accounts/models.py b/apps/accounts/models.py
new file mode 100644
index 0000000..a930081
--- /dev/null
+++ b/apps/accounts/models.py
@@ -0,0 +1,20 @@
+from django.db import models
+from django.contrib.auth.models import AbstractUser
+
+
+class User(AbstractUser):
+ pass
+
+ class Meta:
+ ordering = ['-date_joined']
+
+
+class UserProfile(models.Model):
+ user = models.OneToOneField(User, on_delete=models.CASCADE)
+ photo = models.ImageField(upload_to='profile', null=True, blank=True)
+ website = models.CharField(max_length=300, null=True, blank=True, default='')
+ location = models.CharField(max_length=300, null=True, blank=True, default='')
+ bio = models.TextField(null=True, blank=True, default='')
+
+ def __str__(self):
+ return self.user.username
diff --git a/apps/accounts/signals.py b/apps/accounts/signals.py
new file mode 100644
index 0000000..837a7ed
--- /dev/null
+++ b/apps/accounts/signals.py
@@ -0,0 +1,12 @@
+from django.db.models.signals import post_save
+from django.dispatch import receiver
+
+from .models import User, UserProfile
+
+
+@receiver(post_save, sender=User)
+def create_profile(sender, update_fields, created, instance, **kwargs):
+ """ creates a blank profile when a new user signs up """
+ if created:
+ user_profile = UserProfile.objects.create(user=instance)
+ user_profile.save()
diff --git a/apps/accounts/tests/__init__.py b/apps/accounts/tests/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apps/accounts/tests/__init__.py
diff --git a/apps/accounts/tests/test_models.py b/apps/accounts/tests/test_models.py
new file mode 100644
index 0000000..f9b33f6
--- /dev/null
+++ b/apps/accounts/tests/test_models.py
@@ -0,0 +1,13 @@
+from django.test import TestCase
+from mixer.backend.django import mixer
+
+from accounts.models import User, UserProfile
+
+
+class UserProfileModelTest(TestCase):
+
+ def test_string_representation(self):
+ user = mixer.blend(User, username='test')
+ user.save()
+ profile = UserProfile.objects.get(user=user)
+ self.assertEqual(str(profile), str(user.username))
diff --git a/apps/accounts/tests/test_views.py b/apps/accounts/tests/test_views.py
new file mode 100644
index 0000000..39dcb31
--- /dev/null
+++ b/apps/accounts/tests/test_views.py
@@ -0,0 +1,23 @@
+from django.test import Client
+from django.test import RequestFactory, TestCase
+from mixer.backend.django import mixer
+
+from accounts.models import User
+from accounts.views import ProfileView
+
+
+class ProfileViewTest(TestCase):
+ def setUp(self):
+ # Every test needs access to the request factory.
+ self.factory = RequestFactory()
+ self.user = mixer.blend(User, username='tpynchon', password="gravity")
+
+ def test_profile_view(self):
+ request = self.factory.get('/settings/')
+ request.user = self.user
+ response = ProfileView.as_view()(request)
+ self.assertEqual(response.status_code, 200)
+ response.render()
+ html = response.content.decode('utf8')
+ self.assertTrue(html.startswith('<!DOCTYPE html>'))
+ self.assertIn('<h1>Account Settings</h1>', html)
diff --git a/apps/accounts/urls.py b/apps/accounts/urls.py
new file mode 100644
index 0000000..d9ee327
--- /dev/null
+++ b/apps/accounts/urls.py
@@ -0,0 +1,12 @@
+from django.urls import path
+
+from . import views
+
+
+urlpatterns = [
+ path(
+ r'',
+ views.SettingsListView.as_view(),
+ name="settings"
+ ),
+]
diff --git a/apps/accounts/views.py b/apps/accounts/views.py
new file mode 100644
index 0000000..e51c60e
--- /dev/null
+++ b/apps/accounts/views.py
@@ -0,0 +1,32 @@
+from django.views.generic import UpdateView, DetailView
+from django.utils.decorators import method_decorator
+from django.contrib.auth.decorators import login_required
+
+from .models import UserProfile
+from .forms import ProfileForm
+
+
+@method_decorator(login_required, name='dispatch')
+class UpdateViewWithUser(UpdateView):
+
+ def get_form_kwargs(self, **kwargs):
+ kwargs = super().get_form_kwargs(**kwargs)
+ kwargs.update({'user': self.request.user})
+ return kwargs
+
+
+class ProfileView(UpdateViewWithUser):
+ model = UserProfile
+ form_class = ProfileForm
+ template_name = "accounts/profile.html"
+
+ def get_object(self):
+ return self.request.user.userprofile
+
+
+class SettingsListView(DetailView):
+ model = UserProfile
+ template_name = "accounts/profile.html"
+
+ def get_object(self):
+ return self.request.user.userprofile