aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.coveragerc3
-rw-r--r--.gitignore8
-rw-r--r--README.md35
-rw-r--r--apps/accounts/__init__.py0
-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.py12
-rw-r--r--apps/accounts/tests/test_views.py0
-rw-r--r--config/__init__.py0
-rw-r--r--config/base_urls.py21
-rwxr-xr-xconfig/djadmin.sh10
-rw-r--r--config/requirements.txt30
-rw-r--r--config/settings.py135
-rw-r--r--config/wsgi.py16
-rwxr-xr-xmanage.py17
18 files changed, 374 insertions, 0 deletions
diff --git a/.coveragerc b/.coveragerc
new file mode 100644
index 0000000..ea53d98
--- /dev/null
+++ b/.coveragerc
@@ -0,0 +1,3 @@
+[run]
+omit=
+ venv/*
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6e506cd
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+*.log
+Vagrantfile
+.vagrant
+.env
+venv/
+__pycache__
+.coverage
+htmlcov/
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..108d74c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,35 @@
+# Project purpose
+
+## Internal Apps
+### Accounts
+* adds profile to default Django user
+ * profile photo
+ * website
+ * bio
+ * location
+
+
+## Rational for external dependencies
+### Coverage
+[https://github.com/nedbat/coveragepy](https://github.com/nedbat/coveragepy)
+#### Why
+* gotta test
+* I hate keeping track of what needs tests
+### Python Decouple
+[https://pypi.org/project/python-decouple/](https://pypi.org/project/python-decouple/)
+####Why
+* Decouple helps you to organize your settings so that you can change parameters without having to redeploy your app.
+* Allows committing settings.py by keeping not-committed settings in one place (.env)
+
+### Django Taggit
+[https://github.com/alex/django-taggit](https://github.com/alex/django-taggit)
+####Why
+* Simplest way to get robust tagging capabilities
+* When I wrote my own, this is what I wrote
+
+
+### Django Storages
+[https://github.com/jschneier/django-storages](https://github.com/jschneier/django-storages)
+####Why
+* Simplest way to make all static assets go to Amazon S3
+* Simplifies migrating server setups by keep static assets off the server
diff --git a/apps/accounts/__init__.py b/apps/accounts/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apps/accounts/__init__.py
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..5aac623
--- /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(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..48cc976
--- /dev/null
+++ b/apps/accounts/tests/test_models.py
@@ -0,0 +1,12 @@
+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')
+ profile = UserProfile(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..e69de29
--- /dev/null
+++ b/apps/accounts/tests/test_views.py
diff --git a/config/__init__.py b/config/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/config/__init__.py
diff --git a/config/base_urls.py b/config/base_urls.py
new file mode 100644
index 0000000..5779be7
--- /dev/null
+++ b/config/base_urls.py
@@ -0,0 +1,21 @@
+"""myproj URL Configuration
+
+The `urlpatterns` list routes URLs to views. For more information please see:
+ https://docs.djangoproject.com/en/2.1/topics/http/urls/
+Examples:
+Function views
+ 1. Add an import: from my_app import views
+ 2. Add a URL to urlpatterns: path('', views.home, name='home')
+Class-based views
+ 1. Add an import: from other_app.views import Home
+ 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
+Including another URLconf
+ 1. Import the include() function: from django.urls import include, path
+ 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
+"""
+from django.contrib import admin
+from django.urls import path
+
+urlpatterns = [
+ path('admin/', admin.site.urls),
+]
diff --git a/config/djadmin.sh b/config/djadmin.sh
new file mode 100755
index 0000000..24081d4
--- /dev/null
+++ b/config/djadmin.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+DIR="$( cd "$( dirname $( dirname "${BASH_SOURCE[0]}" ) )" && pwd )"
+PYTHONPATH=$PYTHONPATH:$DIR
+PYTHONPATH=$PYTHONPATH:"${DIR}/apps"
+PYTHONPATH=$PYTHONPATH:"${DIR}/apps/lib"
+PYTHONPATH=$PYTHONPATH:"${DIR}/venv/lib/python3.6/"
+export PYTHONPATH
+export DJANGO_SETTINGS_MODULE=config.settings
+ADMIN="${DIR}/venv/bin/django-admin.py"
+$ADMIN $@
diff --git a/config/requirements.txt b/config/requirements.txt
new file mode 100644
index 0000000..d89255f
--- /dev/null
+++ b/config/requirements.txt
@@ -0,0 +1,30 @@
+backcall==0.1.0
+confusable-homoglyphs==3.2.0
+coverage==4.5.1
+decorator==4.3.0
+Django==2.1.2
+django-extensions==2.1.3
+django-registration==3.0
+django-storages==1.7.1
+django-taggit==0.23.0
+Faker==0.9.1
+ipython==7.1.1
+ipython-genutils==0.2.0
+jedi==0.13.1
+mixer==6.1.3
+parso==0.3.1
+pexpect==4.6.0
+pickleshare==0.7.5
+Pillow==5.3.0
+pkg-resources==0.0.0
+prompt-toolkit==2.0.7
+psycopg2==2.7.5
+ptyprocess==0.6.0
+Pygments==2.2.0
+python-dateutil==2.7.5
+python-decouple==3.1
+pytz==2018.7
+six==1.11.0
+text-unidecode==1.2
+traitlets==4.3.2
+wcwidth==0.1.7
diff --git a/config/settings.py b/config/settings.py
new file mode 100644
index 0000000..abe86dd
--- /dev/null
+++ b/config/settings.py
@@ -0,0 +1,135 @@
+"""
+Django settings for project.
+
+Generated by 'django-admin startproject' using Django 2.1.2.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/2.1/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/2.1/ref/settings/
+"""
+
+import os
+from decouple import config, Csv
+
+# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+
+SECRET_KEY = config('SECRET_KEY')
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = config('DEBUG', cast=bool)
+
+AUTH_PROFILE_MODULE = "accounts.UserProfile"
+AUTH_USER_MODEL = "accounts.User"
+
+DEFAULT_FILE_STORAGE = config('DEFAULT_FILE_STORAGE')
+
+AWS_S3_OBJECT_PARAMETERS = {
+ 'CacheControl': 'max-age=86400',
+}
+
+ALLOWED_HOSTS = config('ALLOWED_HOSTS', cast=Csv())
+
+
+# APPS
+# https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
+DJANGO_APPS = [
+ 'django.contrib.admin',
+ 'django.contrib.auth',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ 'django.contrib.messages',
+ 'django.contrib.staticfiles',
+]
+THIRD_PARTY_APPS = [
+ 'taggit',
+ 'django_extensions'
+]
+LOCAL_APPS = [
+ 'accounts',
+]
+INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS
+
+
+# https://docs.djangoproject.com/en/dev/ref/settings/#middleware
+MIDDLEWARE = [
+ 'django.middleware.security.SecurityMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.middleware.common.CommonMiddleware',
+ 'django.middleware.csrf.CsrfViewMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ 'django.contrib.messages.middleware.MessageMiddleware',
+ 'django.middleware.clickjacking.XFrameOptionsMiddleware',
+]
+
+ROOT_URLCONF = 'config.base_urls'
+
+TEMPLATES = [
+ {
+ 'BACKEND': 'django.template.backends.django.DjangoTemplates',
+ 'DIRS': [],
+ 'APP_DIRS': True,
+ 'OPTIONS': {
+ 'context_processors': [
+ 'django.template.context_processors.debug',
+ 'django.template.context_processors.request',
+ 'django.contrib.auth.context_processors.auth',
+ 'django.contrib.messages.context_processors.messages',
+ ],
+ },
+ },
+]
+
+WSGI_APPLICATION = 'config.wsgi.application'
+
+DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.contrib.gis.db.backends.postgis',
+ 'NAME': config('DB_NAME'),
+ 'USER': config('DB_USER'),
+ 'PASSWORD': config('DB_PASSWORD'),
+ 'HOST': config('DB_HOST'),
+ 'PORT': '',
+ }
+}
+
+
+# Password validation
+# https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators
+
+AUTH_PASSWORD_VALIDATORS = [
+ {
+ 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
+ },
+]
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/2.1/topics/i18n/
+
+LANGUAGE_CODE = 'en-us'
+
+TIME_ZONE = 'UTC'
+
+USE_I18N = True
+
+USE_L10N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/2.1/howto/static-files/
+
+STATIC_URL = '/static/'
diff --git a/config/wsgi.py b/config/wsgi.py
new file mode 100644
index 0000000..0c727f0
--- /dev/null
+++ b/config/wsgi.py
@@ -0,0 +1,16 @@
+"""
+WSGI config for myproj project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproj.settings')
+
+application = get_wsgi_application()
diff --git a/manage.py b/manage.py
new file mode 100755
index 0000000..e9c4109
--- /dev/null
+++ b/manage.py
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+import os
+import sys
+d = os.path.dirname(os.path.abspath(__file__))
+sys.path.append(d+"/apps")
+sys.path.append(d+"/config")
+if __name__ == '__main__':
+ os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
+ try:
+ from django.core.management import execute_from_command_line
+ except ImportError as exc:
+ raise ImportError(
+ "Couldn't import Django. Are you sure it's installed and "
+ "available on your PYTHONPATH environment variable? Did you "
+ "forget to activate a virtual environment?"
+ ) from exc
+ execute_from_command_line(sys.argv)