diff --git a/accounts/__init__.py b/accounts/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/accounts/admin.py b/accounts/admin.py
new file mode 100644
index 0000000..8c38f3f
--- /dev/null
+++ b/accounts/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/accounts/apps.py b/accounts/apps.py
new file mode 100644
index 0000000..3e3c765
--- /dev/null
+++ b/accounts/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class AccountsConfig(AppConfig):
+ default_auto_field = 'django.db.models.BigAutoField'
+ name = 'accounts'
diff --git a/accounts/migrations/0001_initial.py b/accounts/migrations/0001_initial.py
new file mode 100644
index 0000000..32c2885
--- /dev/null
+++ b/accounts/migrations/0001_initial.py
@@ -0,0 +1,39 @@
+# Generated by Django 3.2 on 2022-09-25 23:10
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ('auth', '0012_alter_user_first_name_max_length'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='UserAccount',
+ fields=[
+ ('id', models.BigAutoField(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(max_length=2555, null=True, unique=True)),
+ ('email', models.EmailField(max_length=255, unique=True)),
+ ('first_name', models.CharField(max_length=255)),
+ ('last_name', models.CharField(max_length=255)),
+ ('avatar', models.ImageField(blank=True, null=True, upload_to='avatar/')),
+ ('is_active', models.BooleanField(default=True)),
+ ('is_staff', models.BooleanField(default=False)),
+ ('get_newsletter', models.BooleanField(db_index=True, default=True)),
+ ('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={
+ 'verbose_name': 'User',
+ 'verbose_name_plural': 'Users',
+ 'ordering': ['-id'],
+ },
+ ),
+ ]
diff --git a/accounts/migrations/__init__.py b/accounts/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/accounts/models.py b/accounts/models.py
new file mode 100644
index 0000000..4d92152
--- /dev/null
+++ b/accounts/models.py
@@ -0,0 +1,74 @@
+import datetime
+
+from django.conf import settings
+from django.contrib.auth.models import (AbstractBaseUser, BaseUserManager,
+ PermissionsMixin)
+from django.db import models
+
+# Create your models here.
+
+class UserAccountManager(BaseUserManager):
+ """ Manages the functions needed to create a user """
+ def create_user(self, email, password=None, **extra_fields):
+ """ Creates and saves a new user """
+ if not email:
+ raise ValueError("Users must have an email address")
+
+ email = self.normalize_email(email)
+ user = self.model(email=email, **extra_fields)
+
+ user.set_password(password)
+ user.save(using=self._db)
+
+ return user
+
+ def create_superuser(self, email, password, **extra_fields):
+ user = self.create_user(email, password, **extra_fields)
+
+ user.is_superuser = True
+ user.is_staff = True
+ user.save(using=self._db)
+
+ return user
+
+
+class UserAccount(AbstractBaseUser, PermissionsMixin):
+ """ General user account fields """
+
+ username = models.CharField(max_length=2555, null=True, unique=True)
+ email = models.EmailField(max_length=255, unique=True)
+ first_name = models.CharField(max_length=255)
+ last_name = models.CharField(max_length=255)
+ avatar = models.ImageField(upload_to='avatar/', null=True, blank=True)
+ is_active = models.BooleanField(default=True)
+ is_staff = models.BooleanField(default=False)
+ get_newsletter = models.BooleanField(default=True, db_index=True)
+
+ objects = UserAccountManager()
+
+ USERNAME_FIELD = "email"
+ REQUIRED_FIELDS = ["first_name", "last_name"]
+
+ class Meta:
+ ordering = ['-id']
+ verbose_name = "User"
+ verbose_name_plural = "Users"
+
+
+ def get_short_name(self):
+ return self.first_name
+
+ def __str__(self):
+ return self.email
+
+ def get_or_create_userprofile(self):
+ from profiles.models import UserProfile
+ profile, _ = UserProfile.objects.get_or_create(user=self)
+ return profile
+
+ def get_avatar(self):
+ profile = self.get_or_create_userprofile()
+ return profile.avatar
+
+
+
\ No newline at end of file
diff --git a/accounts/tests.py b/accounts/tests.py
new file mode 100644
index 0000000..7ce503c
--- /dev/null
+++ b/accounts/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/accounts/urls.py b/accounts/urls.py
new file mode 100644
index 0000000..84c07f9
--- /dev/null
+++ b/accounts/urls.py
@@ -0,0 +1,8 @@
+from django.contrib import admin
+from django.urls import include, path
+
+app_name = 'accounts'
+
+urlpatterns = [
+
+]
diff --git a/accounts/views.py b/accounts/views.py
new file mode 100644
index 0000000..91ea44a
--- /dev/null
+++ b/accounts/views.py
@@ -0,0 +1,3 @@
+from django.shortcuts import render
+
+# Create your views here.
diff --git a/album/__init__.py b/album/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/album/admin.py b/album/admin.py
new file mode 100644
index 0000000..8c38f3f
--- /dev/null
+++ b/album/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/album/apps.py b/album/apps.py
new file mode 100644
index 0000000..83b2048
--- /dev/null
+++ b/album/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class AlbumConfig(AppConfig):
+ default_auto_field = 'django.db.models.BigAutoField'
+ name = 'album'
diff --git a/album/migrations/__init__.py b/album/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/album/models.py b/album/models.py
new file mode 100644
index 0000000..71a8362
--- /dev/null
+++ b/album/models.py
@@ -0,0 +1,3 @@
+from django.db import models
+
+# Create your models here.
diff --git a/album/serializers.py b/album/serializers.py
new file mode 100644
index 0000000..e69de29
diff --git a/album/static/album/css/album.css b/album/static/album/css/album.css
new file mode 100644
index 0000000..e3bdccc
--- /dev/null
+++ b/album/static/album/css/album.css
@@ -0,0 +1,39 @@
+:root {
+ --jumbotron-padding-y: 3rem;
+ }
+
+ .jumbotron {
+ padding-top: var(--jumbotron-padding-y);
+ padding-bottom: var(--jumbotron-padding-y);
+ margin-bottom: 0;
+ background-color: #fff;
+ }
+ @media (min-width: 768px) {
+ .jumbotron {
+ padding-top: calc(var(--jumbotron-padding-y) * 2);
+ padding-bottom: calc(var(--jumbotron-padding-y) * 2);
+ }
+ }
+
+ .jumbotron p:last-child {
+ margin-bottom: 0;
+ }
+
+ .jumbotron-heading {
+ font-weight: 300;
+ }
+
+ .jumbotron .container {
+ max-width: 40rem;
+ }
+
+ footer {
+ padding-top: 3rem;
+ padding-bottom: 3rem;
+ }
+
+ footer p {
+ margin-bottom: .25rem;
+ }
+
+ .box-shadow { box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05); }
\ No newline at end of file
diff --git a/album/templates/album/base.html b/album/templates/album/base.html
new file mode 100644
index 0000000..f101c3b
--- /dev/null
+++ b/album/templates/album/base.html
@@ -0,0 +1,389 @@
+{% extends 'base.html' %}
+
+{% block content %}
+
+
+
+
+
+
+
About
+
+ Add some information about the album below, the author, or any other
+ background context. Make it a few sentences long so folks can pick
+ up some informative tidbits. Then, link them off to some social
+ networking sites or contact information.
+
+ Something short and leading about the collection below—its contents, the
+ creator, etc. Make it short and sweet, but not too short so folks don't
+ simply skip over it entirely.
+
+ Add some information about the album below, the author, or any other
+ background context. Make it a few sentences long so folks can pick
+ up some informative tidbits. Then, link them off to some social
+ networking sites or contact information.
+
+ Something short and leading about the collection below—its contents, the
+ creator, etc. Make it short and sweet, but not too short so folks don't
+ simply skip over it entirely.
+