lots of stuff to get authentication up
diff --git a/AppMgr/admin.py b/AppMgr/admin.py
index 8c38f3f..4917232 100644
--- a/AppMgr/admin.py
+++ b/AppMgr/admin.py
@@ -1,3 +1,37 @@
from django.contrib import admin
+from django.contrib.contenttypes.admin import GenericTabularInline
+
+from custom_user.models import EmailUser
+from custom_user.admin import EmailUserAdmin as BaseUserAdmin
+
+from AppMgr.models import UserProfile, Organization, Application, AppVersion
+
# Register your models here.
+
+class UserProfileInline(admin.StackedInline):
+ model = UserProfile
+
+class UserAdmin(BaseUserAdmin):
+ inlines = (UserProfileInline, )
+
+class OrganizationAdmin(admin.ModelAdmin):
+ search_fields = ['name']
+ list_display = ['name']
+
+class ApplicationInline(GenericTabularInline):
+ model = Application
+ ct_field = 'content_type'
+ ct_fk_field = 'object_id'
+
+class ApplicationAdmin(admin.ModelAdmin):
+ inlines = [ApplicationInline]
+ search_fields = ['name']
+ list_display = ['name']
+
+admin.site.unregister(EmailUser)
+admin.site.register(EmailUser, UserAdmin)
+
+admin.site.register(Organization, OrganizationAdmin)
+
+admin.site.register(Application, ApplicationAdmin)
diff --git a/AppMgr/models.py b/AppMgr/models.py
index 218b378..b44e9c5 100644
--- a/AppMgr/models.py
+++ b/AppMgr/models.py
@@ -1,23 +1,70 @@
from django.db import models
from django.conf import settings
+from django.contrib.postgres.fields import JSONField
+
+from django.contrib.contenttypes.models import ContentType
+from django.contrib.contenttypes.fields import GenericForeignKey
# Create your models here.
class UserProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL)
- # additional user parameters
-
def __unicode__(self):
return self.user.email
class Organization(models.Model):
name = models.CharField(max_length=255)
+ members = models.ManyToManyField(UserProfile)
+
+ class Meta:
+ permissions = (
+ ("admin", "All organizational privileges"),
+ ("change_apps", "Create/Modify/Delete Org's Applications"),
+ ("change_members", "Add/Remove Users"),
+ )
+
def __unicode__(self):
return self.name
class Application(models.Model):
name = models.CharField(max_length=255)
+ isPublic = models.BooleanField(default=True)
+
+ #Application owner can be either a UserProfile or an Organization
+ limit = models.Q(app_label='AppMgr', model='UserProfile') | \
+ models.Q(app_label='AppMgr', model='Organization')
+ content_type = models.ForeignKey(
+ ContentType,
+ verbose_name='application owner',
+ limit_choices_to=limit,
+ null=True,
+ blank=True,
+ )
+ object_id = models.PositiveIntegerField(
+ verbose_name='app owner id',
+ null=True,
+ )
+ content_object = GenericForeignKey('content_type', 'object_id')
+
+ class Meta:
+ permissions = (
+ ("admin", "All application privileges"),
+ ("edit", "add/modify application attributes"),
+ ("view", "read access to the application"),
+ )
+
+ def __unicode__(self):
+ return self.name
+
+class AppVersion(models.Model):
+ name = models.CharField(max_length=255)
+
+ app = models.ForeignKey(Application, null=True, blank=False)
+
+ aliases = JSONField()
+ domain = models.URLField(max_length=255)
+
def __unicode__(self):
return self.name
diff --git a/AppMgr/views.py b/AppMgr/views.py
index 91ea44a..29e3bc4 100644
--- a/AppMgr/views.py
+++ b/AppMgr/views.py
@@ -1,3 +1,147 @@
-from django.shortcuts import render
+from django.shortcuts import render, redirect, render_to_response
+from django.http import HttpResponseRedirect, HttpResponse
+from django.contrib.auth.decorators import login_required
+from django.contrib.auth import authenticate, login, logout, get_user_model
+from django.contrib.auth.views import password_reset, password_reset_confirm
+from django.contrib.sites.shortcuts import get_current_site
+from django.core.urlresolvers import reverse
+from django.template import RequestContext
+from django.conf import settings
+from django.db import IntegrityError
+
+from axes.decorators import watch_login
+
+from AppMgr.models import UserProfile, Organization, Application, AppVersion
# Create your views here.
+
+# creates a new user
+def register(request):
+ # TODO : add logging back in. Good practice!!
+ # Like before, get the request's context.
+ context = RequestContext(request)
+
+ # A boolean value for telling the template whether the registration was successful.
+ # Set to False initially. Code changes value to True when registration succeeds.
+ registrationSuccessful = False
+ userExists = False
+ error = False
+
+ # If it's a HTTP POST, we're interested in processing form data.
+ if request.method == 'POST':
+
+ # Now we hash the password with the set_password method.
+ # Once hashed, we can update the user object.
+ user = get_user_model()(email=request.POST['email'])
+ user.set_password(request.POST['password'])
+ user.last_login = '1970-01-01 00:00'
+
+ if not user.email or not request.POST['password']:
+ error = True
+ return render_to_response('registration/register.html', {'registrationSuccessful': registrationSuccessful, 'userExists': userExists, 'error': error}, context)
+
+ try:
+ user.save()
+ except IntegrityError:
+ userExists = True
+ return render_to_response('registration/register.html', {'registrationSuccessful': registrationSuccessful, 'userExists': userExists, 'error': error}, context)
+
+ # Now sort out the UserProfile instance.
+ # Since we need to set the user attribute ourselves, we set commit=False.
+ # This delays saving the model until we're ready to avoid integrity problems.
+ userprofile = UserProfile()
+ userprofile.user = user
+
+ # Now we save the UserProfile model instance.
+ userprofile.save()
+
+ # Update our variable to tell the template registration was successful.
+ registrationSuccessful = True
+ # add some logic to log events, log in users directly
+ print "successful registration of " + request.POST['email'] +" "+ datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+ request.POST['email_to'] = user.email
+ request.POST['email_subject'] = 'Welcome to TAP'
+ request.POST['email_message'] = 'Your registration was successful!\n\nIn case you forget your password, please go to the following page and reset your password:\n\nhttps://' + get_current_site(request).domain + '/AppMgr/reset/\n\nYour username, in case you\'ve forgotten, is the email address this message was sent to.\n\nThanks for using our site!\n\nThe ' + get_current_site(request).name + ' team'
+
+ # Update this if TAP wants email on registration
+ #exp_portal.email.send_email(request)
+
+ #return render_to_response('abcd.html', context)
+ return render_to_response('registration/register.html', {'registrationSuccessful': registrationSuccessful, 'userExists': userExists, 'error': error}, context)
+
+
+def logout_user(request):
+ """
+ Log users out and re-direct them to the main page.
+ """
+ logout(request)
+ return HttpResponseRedirect('/')
+
+@watch_login
+def login_user(request):
+ # Like before, obtain the context for the user's request.
+ context = RequestContext(request)
+
+ # If the request is a HTTP POST, try to pull out the relevant information.
+ if request.method == 'POST':
+ # Gather the username (email) and password provided by the user.
+ # This information is obtained from the login form.
+ email = request.POST['email']
+ password = request.POST['password']
+ # print "Login attempt by " + username + " at " + datetime
+
+ # Use Django's machinery to attempt to see if the username/password
+ # combination is valid - a User object is returned if it is.
+ user = authenticate(email=email, password=password)
+
+ # If we have a User object, the details are correct.
+ # If None (Python's way of representing the absence of a value), no user
+ # with matching credentials was found.
+ if user:
+ # Is the account active? It could have been disabled.
+ if user.is_active:
+ # If the account is valid and active, we can log the user in.
+ # We'll send the user back to the homepage.
+ login(request, user)
+ return HttpResponseRedirect('/AppMgr/user_profile')
+ else:
+ # An inactive account was used - no logging in!
+ return HttpResponse("Your TAP account is disabled.")
+ else:
+ # Bad login details were provided. So we can't log the user in.
+ print "Invalid login details: {0}, {1}".format(email, password)
+ return HttpResponse("Invalid login details supplied.")
+
+ # The request is not a HTTP POST, so display the login form.
+ # This scenario would most likely be a HTTP GET.
+ else:
+ # No context variables to pass to the template system, hence the
+ # blank dictionary object...
+ # experiment_title = title
+ return render(request, 'registration/login.html')
+ # return render(request, 'registration/login.html', {'experiment_title': experiment_title})
+
+ # return login_view(request, authentication_form=MyAuthForm)
+
+def reset_confirm(request, uidb64=None, token=None):
+ return password_reset_confirm(request, template_name='registration/reset_password_confirm.html',
+ uidb64=uidb64, token=token,
+ post_reset_redirect=reverse('AppMgr:login'))
+
+
+def reset(request):
+ return password_reset(request, template_name='registration/reset_password_form.html',
+ email_template_name='registration/reset_password_email.html',
+ post_reset_redirect=reverse('AppMgr:reset_sent'),
+ from_email=settings.EMAIL_FROM_NOMINAL_ADDRESS)
+
+def reset_sent(request):
+ return render(request, 'registration/reset_password_done.html')
+
+@login_required(login_url='/AppMgr/login')
+def view_profile(request):
+ user = request.user
+ return render(request, 'user_profile.html',
+ {'user': request.user,
+ }
+ )
diff --git a/tap/settings/base.py b/tap/settings/base.py
index 8c6a8b2..01a2567 100644
--- a/tap/settings/base.py
+++ b/tap/settings/base.py
@@ -26,7 +26,25 @@
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
-ALLOWED_HOSTS = []
+ALLOWED_HOSTS = ['*']
+
+SITE_ROOT = os.path.realpath(os.path.dirname(os.path.dirname(__file__)))
+
+SITE_ID = 1
+
+# Email integration setup
+EMAIL_USE_TLS = True
+EMAIL_HOST = 'email-smtp.us-east-1.amazonaws.com'
+EMAIL_PORT = 587
+EMAIL_HOST_USER = 'AKIAJJDM2ZC67STGF4IA'
+EMAIL_HOST_PASSWORD = MY_EMAIL_PASSWORD
+
+# Configurable email addresses
+# These are addresses where mail is sent from...
+EMAIL_FROM_NOMINAL_ADDRESS = "onlinetesting@xdataonline.com"
+EMAIL_FROM_ERROR_ADDRESS = "no-reply@xdataonline.com"
+# These are addresses used to send mail to...
+EMAIL_TO_ERROR_ADDRESS = "errors@xdataonline.com"
# Application definition
@@ -37,9 +55,11 @@
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
+ 'django.contrib.sites',
'django.contrib.staticfiles',
'custom_user',
'AppMgr',
+ 'axes',
)
MIDDLEWARE_CLASSES = (
@@ -55,12 +75,16 @@
ROOT_URLCONF = 'tap.urls'
+AUTHENTICATION_BACKENDS = (
+ 'django.contrib.auth.backends.ModelBackend',
+ )
+
AUTH_USER_MODEL = 'custom_user.EmailUser'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
- 'DIRS': [],
+ 'DIRS': [os.path.join(SITE_ROOT, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
@@ -77,7 +101,7 @@
# Database
-# https://docs.djangoproject.com/en/1.8/ref/settings/#databases
+# https://docs.djangoproject.com/en/1.9/ref/settings/#databases
DATABASES = {
'default': {
@@ -96,7 +120,7 @@
LANGUAGE_CODE = 'en-us'
-TIME_ZONE = 'UTC'
+TIME_ZONE = 'America/New_York'
USE_I18N = True
@@ -109,3 +133,31 @@
# https://docs.djangoproject.com/en/1.8/howto/static-files/
STATIC_URL = '/static/'
+
+LOGGING = {
+ 'version': 1,
+ 'disable_existing_loggers': True,
+ 'formatters': {
+ 'verbose': {
+ 'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
+ },
+ },
+ 'handlers': {
+ 'console': {
+ 'level': 'NOTSET',
+ 'class': 'logging.StreamHandler',
+ 'formatter': 'verbose'
+ }
+ },
+ 'loggers': {
+ '': {
+ 'handlers': ['console'],
+ 'level': 'NOTSET',
+ },
+ 'django.request': {
+ 'handlers': ['console'],
+ 'propagate': False,
+ 'level': 'ERROR'
+ }
+ }
+}
diff --git a/tap/settings/dev.py b/tap/settings/dev.py
index 32726e3..b594469 100644
--- a/tap/settings/dev.py
+++ b/tap/settings/dev.py
@@ -18,10 +18,7 @@
DEBUG = True
-TEMPLATES = [
- {
- 'OPTIONS': {
- 'debug': DEBUG,
- },
- },
-]
+for T in TEMPLATES:
+ T['OPTIONS']['debug'] = DEBUG
+
+
diff --git a/tap/settings/production.py b/tap/settings/production.py
index aba9e05..dd9aadc 100644
--- a/tap/settings/production.py
+++ b/tap/settings/production.py
@@ -18,11 +18,6 @@
DEBUG = False
-TEMPLATES = [
- {
- 'OPTIONS': {
- 'debug': DEBUG,
- },
- },
-]
+for T in TEMPLATES:
+ T['OPTIONS']['debug'] = DEBUG
diff --git a/tap/urls.py b/tap/urls.py
index ef54922..2f0ce05 100644
--- a/tap/urls.py
+++ b/tap/urls.py
@@ -17,4 +17,5 @@
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
+ url(r'^AppMgr/', include('AppMgr.urls', namespace='AppMgr')),
]
diff --git a/tap/wsgi.py b/tap/wsgi.py
index 41f366d..e862716 100644
--- a/tap/wsgi.py
+++ b/tap/wsgi.py
@@ -8,9 +8,12 @@
"""
import os, sys
+sys.path.append('/var/www/AppMgr/tap')
+sys.path.append('/var/www/AppMgr')
sys.path.append('./tap/settings')
-os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tap.production")
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "production")
+
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()