From 60b30d7d6c68bf74f45fe8de64f20d3bdee25ab9 Mon Sep 17 00:00:00 2001 From: Nathan Chapman Date: Fri, 9 Jul 2021 21:25:42 -0600 Subject: [PATCH] Initial commit --- .gitignore | 125 +++++++++++++++++++ Pipfile | 12 ++ Pipfile.lock | 52 ++++++++ board/__init__.py | 0 board/admin.py | 11 ++ board/apps.py | 9 ++ board/migrations/0001_initial.py | 60 ++++++++++ board/migrations/0002_auto_20210709_0103.py | 27 +++++ board/migrations/__init__.py | 0 board/models.py | 53 ++++++++ board/signals.py | 23 ++++ board/tests.py | 3 + board/views.py | 3 + manage.py | 22 ++++ onboard/__init__.py | 0 onboard/asgi.py | 16 +++ onboard/settings.py | 126 ++++++++++++++++++++ onboard/urls.py | 21 ++++ onboard/wsgi.py | 16 +++ 19 files changed, 579 insertions(+) create mode 100644 .gitignore create mode 100644 Pipfile create mode 100644 Pipfile.lock create mode 100644 board/__init__.py create mode 100644 board/admin.py create mode 100644 board/apps.py create mode 100644 board/migrations/0001_initial.py create mode 100644 board/migrations/0002_auto_20210709_0103.py create mode 100644 board/migrations/__init__.py create mode 100644 board/models.py create mode 100644 board/signals.py create mode 100644 board/tests.py create mode 100644 board/views.py create mode 100755 manage.py create mode 100644 onboard/__init__.py create mode 100644 onboard/asgi.py create mode 100644 onboard/settings.py create mode 100644 onboard/urls.py create mode 100644 onboard/wsgi.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8267ccc --- /dev/null +++ b/.gitignore @@ -0,0 +1,125 @@ +# Django # +*.log +*.pot +*.pyc +__pycache__ +db.sqlite3 +media + +# Backup files # +*.bak + +# If you are using PyCharm # +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/dictionaries +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.xml +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/gradle.xml +.idea/**/libraries +*.iws /out/ + +# Python # +*.py[cod] +*$py.class + +# Distribution / packaging +.Python build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +.pytest_cache/ +nosetests.xml +coverage.xml +*.cover +.hypothesis/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# envrc +.envrc + +# celery +celerybeat-schedule.* + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + +# Sublime Text # +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache +*.sublime-workspace +*.sublime-project + +# Static CACHE +/static/CACHE/ + +# sftp configuration file +sftp-config.json + +# Package control specific files Package +Control.last-run +Control.ca-list +Control.ca-bundle +Control.system-ca-bundle +GitHub.sublime-settings + +# Visual Studio Code # +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history + +# IntelliJ +/.idea diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..36be345 --- /dev/null +++ b/Pipfile @@ -0,0 +1,12 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +django = "*" + +[dev-packages] + +[requires] +python_version = "3.9" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..4395777 --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,52 @@ +{ + "_meta": { + "hash": { + "sha256": "c36ae28fea7b9a4cc02145632e2f41469af2e7b38b801903abb8333d3306f36b" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.9" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "asgiref": { + "hashes": [ + "sha256:4ef1ab46b484e3c706329cedeff284a5d40824200638503f5768edb6de7d58e9", + "sha256:ffc141aa908e6f175673e7b1b3b7af4fdb0ecb738fc5c8b88f69f055c2415214" + ], + "markers": "python_version >= '3.6'", + "version": "==3.4.1" + }, + "django": { + "hashes": [ + "sha256:3da05fea54fdec2315b54a563d5b59f3b4e2b1e69c3a5841dda35019c01855cd", + "sha256:c58b5f19c5ae0afe6d75cbdd7df561e6eb929339985dbbda2565e1cabb19a62e" + ], + "index": "pypi", + "version": "==3.2.5" + }, + "pytz": { + "hashes": [ + "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da", + "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798" + ], + "version": "==2021.1" + }, + "sqlparse": { + "hashes": [ + "sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0", + "sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8" + ], + "markers": "python_version >= '3.5'", + "version": "==0.4.1" + } + }, + "develop": {} +} diff --git a/board/__init__.py b/board/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/board/admin.py b/board/admin.py new file mode 100644 index 0000000..fa58b84 --- /dev/null +++ b/board/admin.py @@ -0,0 +1,11 @@ +from django.contrib import admin + +from .models import ( + Employee, + LogEntry, + Todo, +) + +admin.site.register(Employee) +admin.site.register(LogEntry) +admin.site.register(Todo) diff --git a/board/apps.py b/board/apps.py new file mode 100644 index 0000000..a711ffd --- /dev/null +++ b/board/apps.py @@ -0,0 +1,9 @@ +from django.apps import AppConfig + + +class BoardConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'board' + + def ready(self): + from .signals import create_employee \ No newline at end of file diff --git a/board/migrations/0001_initial.py b/board/migrations/0001_initial.py new file mode 100644 index 0000000..d3fb79f --- /dev/null +++ b/board/migrations/0001_initial.py @@ -0,0 +1,60 @@ +# Generated by Django 3.2.5 on 2021-07-09 00:52 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Checklist', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ], + ), + migrations.CreateModel( + name='Employee', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('first_name', models.CharField(max_length=50)), + ('last_name', models.CharField(max_length=50)), + ('hire_date', models.DateField()), + ('title', models.CharField(blank=True, max_length=50, null=True)), + ('department', models.CharField(blank=True, max_length=50, null=True)), + ('manager', models.CharField(blank=True, max_length=50, null=True)), + ('initial_comments', models.TextField(blank=True, null=True)), + ('archived', models.BooleanField(default=False)), + ], + ), + migrations.CreateModel( + name='Todo', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('description', models.CharField(max_length=50)), + ('completed', models.BooleanField(default=False)), + ('completed_at', models.DateTimeField(blank=True, null=True)), + ('checklist', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='board.checklist')), + ], + ), + migrations.CreateModel( + name='LogEntry', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('notes', models.CharField(max_length=50)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('employee', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='board.employee')), + ], + ), + migrations.AddField( + model_name='checklist', + name='employee', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='board.employee'), + ), + ] diff --git a/board/migrations/0002_auto_20210709_0103.py b/board/migrations/0002_auto_20210709_0103.py new file mode 100644 index 0000000..dabf13c --- /dev/null +++ b/board/migrations/0002_auto_20210709_0103.py @@ -0,0 +1,27 @@ +# Generated by Django 3.2.5 on 2021-07-09 01:03 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('board', '0001_initial'), + ] + + operations = [ + migrations.RemoveField( + model_name='todo', + name='checklist', + ), + migrations.AddField( + model_name='todo', + name='employee', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='board.employee'), + preserve_default=False, + ), + migrations.DeleteModel( + name='Checklist', + ), + ] diff --git a/board/migrations/__init__.py b/board/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/board/models.py b/board/models.py new file mode 100644 index 0000000..17bf0ae --- /dev/null +++ b/board/models.py @@ -0,0 +1,53 @@ +from django.db import models +from django.utils import timezone + + +class Employee(models.Model): + first_name = models.CharField(max_length=64) + last_name = models.CharField(max_length=64) + hire_date = models.DateField() + title = models.CharField(max_length=64, blank=True, null=True) + department = models.CharField(max_length=64, blank=True, null=True) + manager = models.CharField(max_length=64, blank=True, null=True) + initial_comments = models.TextField(blank=True, null=True) + archived = models.BooleanField(default=False) + + @property + def full_name(self): + return f"{self.first_name} {self.last_name}" + + + def __str__(self): + return self.full_name + + +class LogEntry(models.Model): + employee = models.ForeignKey(Employee, on_delete=models.CASCADE) + notes = models.CharField(max_length=500) + + + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + def __str__(self): + return f"{self.employee}: {self.notes}" + + +class Todo(models.Model): + employee = models.ForeignKey(Employee, on_delete=models.CASCADE) + description = models.CharField(max_length=64) + + completed = models.BooleanField(default=False) + completed_at = models.DateTimeField(blank=True, null=True) + + def complete(self): + LogEntry.objects.create( + employee=self.checklist.employee, + notes=f'Completed To-do: "{self.description}"' + ) + self.object.completed = True + self.object.completed_at = timezone.now() + self.object.save() + + def __str__(self): + return f"{self.employee}: {self.description}" diff --git a/board/signals.py b/board/signals.py new file mode 100644 index 0000000..6cbef55 --- /dev/null +++ b/board/signals.py @@ -0,0 +1,23 @@ +from django.db.models.signals import post_save +from django.dispatch import receiver +from .models import ( + Employee, + LogEntry, + Todo, +) + +@receiver(post_save, sender=Employee, dispatch_uid="employee_created_signal") +def create_employee(sender, instance, created, **kwargs): + if created: + Todo.objects.bulk_create([ + Todo(employee=instance, description="Active Directory"), + Todo(employee=instance, description="Office 365 Account"), + Todo(employee=instance, description="Office 365 Licence"), + Todo(employee=instance, description="Zendesk Account"), + Todo(employee=instance, description="inContact Account"), + Todo(employee=instance, description="IT Glue Entry"), + ]) + LogEntry.objects.create( + employee=instance, + notes=f"Created {instance.full_name}" + ) diff --git a/board/tests.py b/board/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/board/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/board/views.py b/board/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/board/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/manage.py b/manage.py new file mode 100755 index 0000000..6d109c6 --- /dev/null +++ b/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'onboard.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) + + +if __name__ == '__main__': + main() diff --git a/onboard/__init__.py b/onboard/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/onboard/asgi.py b/onboard/asgi.py new file mode 100644 index 0000000..0fd2f35 --- /dev/null +++ b/onboard/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for onboard project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'onboard.settings') + +application = get_asgi_application() diff --git a/onboard/settings.py b/onboard/settings.py new file mode 100644 index 0000000..fe945bb --- /dev/null +++ b/onboard/settings.py @@ -0,0 +1,126 @@ +""" +Django settings for onboard project. + +Generated by 'django-admin startproject' using Django 3.2.5. + +For more information on this file, see +https://docs.djangoproject.com/en/3.2/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/3.2/ref/settings/ +""" + +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'django-insecure-fdq1(f%l*__obb*zvb3gqnlki!ryr@_1_5om(_2ju3mu70mi4%' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'board.apps.BoardConfig', +] + +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 = 'onboard.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 = 'onboard.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/3.2/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', + } +} + + +# Password validation +# https://docs.djangoproject.com/en/3.2/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/3.2/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/3.2/howto/static-files/ + +STATIC_URL = '/static/' + +# Default primary key field type +# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' diff --git a/onboard/urls.py b/onboard/urls.py new file mode 100644 index 0000000..fc45c44 --- /dev/null +++ b/onboard/urls.py @@ -0,0 +1,21 @@ +"""onboard URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/3.2/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/onboard/wsgi.py b/onboard/wsgi.py new file mode 100644 index 0000000..bb75d03 --- /dev/null +++ b/onboard/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for onboard 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/3.2/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'onboard.settings') + +application = get_wsgi_application()