diff --git a/humbug/__init__.py b/humbug/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/humbug/settings.py b/humbug/settings.py new file mode 100644 index 0000000000..0c034527ee --- /dev/null +++ b/humbug/settings.py @@ -0,0 +1,159 @@ +# Django settings for humbug project. + +DEBUG = True +TEMPLATE_DEBUG = DEBUG + +ADMINS = ( + ('Jessica McKellar', 'jessica.mckellar@gmail.com'), +) + +MANAGERS = ADMINS + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': 'zephyrdb', + 'USER': '', # Not used with sqlite3. + 'PASSWORD': '', # Not used with sqlite3. + 'HOST': '', # Set to empty string for localhost. Not used with sqlite3. + 'PORT': '', # Set to empty string for default. Not used with sqlite3. + } +} + +# Local time zone for this installation. Choices can be found here: +# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name +# although not all choices may be available on all operating systems. +# In a Windows environment this must be set to your system time zone. +TIME_ZONE = 'America/Chicago' + +# Language code for this installation. All choices can be found here: +# http://www.i18nguy.com/unicode/language-identifiers.html +LANGUAGE_CODE = 'en-us' + +SITE_ID = 1 + +# If you set this to False, Django will make some optimizations so as not +# to load the internationalization machinery. +USE_I18N = True + +# If you set this to False, Django will not format dates, numbers and +# calendars according to the current locale. +USE_L10N = True + +# If you set this to False, Django will not use timezone-aware datetimes. +USE_TZ = True + +# Absolute filesystem path to the directory that will hold user-uploaded files. +# Example: "/home/media/media.lawrence.com/media/" +MEDIA_ROOT = '' + +# URL that handles the media served from MEDIA_ROOT. Make sure to use a +# trailing slash. +# Examples: "http://media.lawrence.com/media/", "http://example.com/media/" +MEDIA_URL = '' + +# Absolute path to the directory static files should be collected to. +# Don't put anything in this directory yourself; store your static files +# in apps' "static/" subdirectories and in STATICFILES_DIRS. +# Example: "/home/media/media.lawrence.com/static/" +STATIC_ROOT = '' + +# URL prefix for static files. +# Example: "http://media.lawrence.com/static/" +STATIC_URL = '/static/' + +# Additional locations of static files +STATICFILES_DIRS = ( + # Put strings here, like "/home/html/static" or "C:/www/django/static". + # Always use forward slashes, even on Windows. + # Don't forget to use absolute paths, not relative paths. +) + +# List of finder classes that know how to find static files in +# various locations. +STATICFILES_FINDERS = ( + 'django.contrib.staticfiles.finders.FileSystemFinder', + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', +# 'django.contrib.staticfiles.finders.DefaultStorageFinder', +) + +# Make this unique, and don't share it with anybody. +SECRET_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' + +# List of callables that know how to import templates from various sources. +TEMPLATE_LOADERS = ( + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', +# 'django.template.loaders.eggs.Loader', +) + +MIDDLEWARE_CLASSES = ( + 'django.middleware.common.CommonMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + # Uncomment the next line for simple clickjacking protection: + # 'django.middleware.clickjacking.XFrameOptionsMiddleware', +) + +ROOT_URLCONF = 'humbug.urls' + +# Python dotted path to the WSGI application used by Django's runserver. +WSGI_APPLICATION = 'humbug.wsgi.application' + +TEMPLATE_DIRS = ( + # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". + # Always use forward slashes, even on Windows. + # Don't forget to use absolute paths, not relative paths. + '/Users/jesstess/dev/humbug/templates', +) + +INSTALLED_APPS = ( + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.sites', + 'django.contrib.messages', + 'django.contrib.staticfiles', + # Uncomment the next line to enable the admin: + # 'django.contrib.admin', + # Uncomment the next line to enable admin documentation: + # 'django.contrib.admindocs', + 'zephyr', +) + +# A sample logging configuration. The only tangible logging +# performed by this configuration is to send an email to +# the site admins on every HTTP 500 error when DEBUG=False. +# See http://docs.djangoproject.com/en/dev/topics/logging for +# more details on how to customize your logging configuration. +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'filters': { + 'require_debug_false': { + '()': 'django.utils.log.RequireDebugFalse' + } + }, + 'handlers': { + 'mail_admins': { + 'level': 'ERROR', + 'filters': ['require_debug_false'], + 'class': 'django.utils.log.AdminEmailHandler' + } + }, + 'loggers': { + 'django.request': { + 'handlers': ['mail_admins'], + 'level': 'ERROR', + 'propagate': True, + }, + } +} + +ACCOUNT_ACTIVATION_DAYS=7 +EMAIL_HOST='localhost' +EMAIL_PORT=9991 +EMAIL_HOST_USER='username' +EMAIL_HOST_PASSWORD='password' diff --git a/humbug/urls.py b/humbug/urls.py new file mode 100644 index 0000000000..1bfdae27f7 --- /dev/null +++ b/humbug/urls.py @@ -0,0 +1,22 @@ +from django.conf.urls import patterns, include, url + +# Uncomment the next two lines to enable the admin: +# from django.contrib import admin +# admin.autodiscover() + +urlpatterns = patterns('', + url(r'^$', 'zephyr.views.home', name='home'), + url(r'^update$', 'zephyr.views.update', name='update'), + url(r'^get_updates$', 'zephyr.views.get_updates', name='get_updates'), + url(r'^zephyr/', 'zephyr.views.zephyr', name='zephyr'), + url(r'^accounts/home/', 'zephyr.views.accounts_home', name='accounts_home'), + url(r'^accounts/login/', 'django.contrib.auth.views.login', {'template_name': 'zephyr/login.html'}), + url(r'^accounts/logout/', 'django.contrib.auth.views.logout', {'template_name': 'zephyr/index.html'}), + url(r'^accounts/register/', 'zephyr.views.register', name='register'), + + # Uncomment the admin/doc line below to enable admin documentation: + # url(r'^admin/doc/', include('django.contrib.admindocs.urls')), + + # Uncomment the next line to enable the admin: + # url(r'^admin/', include(admin.site.urls)), +) diff --git a/humbug/wsgi.py b/humbug/wsgi.py new file mode 100644 index 0000000000..bd9cc296d6 --- /dev/null +++ b/humbug/wsgi.py @@ -0,0 +1,28 @@ +""" +WSGI config for humbug project. + +This module contains the WSGI application used by Django's development server +and any production WSGI deployments. It should expose a module-level variable +named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover +this application via the ``WSGI_APPLICATION`` setting. + +Usually you will have the standard Django WSGI application here, but it also +might make sense to replace the whole Django WSGI application with a custom one +that later delegates to the Django one. For example, you could introduce WSGI +middleware here, or combine a Django application with an application of another +framework. + +""" +import os + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "humbug.settings") + +# This application object is used by any WSGI server configured to use this +# file. This includes Django's development server, if the WSGI_APPLICATION +# setting points here. +from django.core.wsgi import get_wsgi_application +application = get_wsgi_application() + +# Apply WSGI middleware here. +# from helloworld.wsgi import HelloWorldApplication +# application = HelloWorldApplication(application) diff --git a/templates/zephyr/accounts_home.html b/templates/zephyr/accounts_home.html new file mode 100644 index 0000000000..0815b6706e --- /dev/null +++ b/templates/zephyr/accounts_home.html @@ -0,0 +1 @@ +login | register diff --git a/templates/zephyr/base.html b/templates/zephyr/base.html new file mode 100644 index 0000000000..ee3d7cf763 --- /dev/null +++ b/templates/zephyr/base.html @@ -0,0 +1,9 @@ +{% autoescape off %} +{% if not user.is_authenticated %}login | register{% endif %} + +{% if user.is_authenticated %}logout{% endif %} + +{% block content %} +{% endblock %} +{% endautoescape %} diff --git a/templates/zephyr/index.html b/templates/zephyr/index.html new file mode 100644 index 0000000000..8d5c4b96a3 --- /dev/null +++ b/templates/zephyr/index.html @@ -0,0 +1,123 @@ +{% extends "zephyr/base.html" %} + +{% block content %} +

Hello {{ user_profile.user.username }}!

+ + + + + +
+{% csrf_token %} +Class: +Instance:
+Content: + +
+ +Unhide + +
+ +{% for zephyr in zephyrs %} + + + + +{% endfor %} +
{% if user_profile.pointer == zephyr.id %}

->{% else %}

{% endif %}

+

{{ zephyr.zephyr_class.name }} / {{ zephyr.instance }} / {{ zephyr.sender.user.username }}
+{{ zephyr.content }} +

+
+ +{% endblock %} diff --git a/templates/zephyr/login.html b/templates/zephyr/login.html new file mode 100644 index 0000000000..057a2d4330 --- /dev/null +++ b/templates/zephyr/login.html @@ -0,0 +1,20 @@ +{% if form.errors %} +

Your username and password didn't match. Please try again.

+{% endif %} + +
+{% csrf_token %} + + + + + + + + + +
{{ form.username.label_tag }}{{ form.username }}
{{ form.password.label_tag }}{{ form.password }}
+ + + +
diff --git a/templates/zephyr/register.html b/templates/zephyr/register.html new file mode 100644 index 0000000000..039a17aa18 --- /dev/null +++ b/templates/zephyr/register.html @@ -0,0 +1,15 @@ +
{% csrf_token %} + + + + + + + + + +
{{ form.username.label_tag }}{{ form.username }}
{{ form.password.label_tag }}{{ form.password }}
+ + + +
diff --git a/zephyr/__init__.py b/zephyr/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/zephyr/forms.py b/zephyr/forms.py new file mode 100644 index 0000000000..0d19883d73 --- /dev/null +++ b/zephyr/forms.py @@ -0,0 +1,5 @@ +from django import forms + +class RegistrationForm(forms.Form): + username = forms.CharField(max_length=100) + password = forms.CharField(max_length=100) diff --git a/zephyr/models.py b/zephyr/models.py new file mode 100644 index 0000000000..26f9cc7567 --- /dev/null +++ b/zephyr/models.py @@ -0,0 +1,24 @@ +from django.db import models +from django.contrib.auth.models import User +from django.db.models.signals import post_save + +class UserProfile(models.Model): + user = models.OneToOneField(User) + pointer = models.IntegerField() + +class ZephyrClass(models.Model): + name = models.CharField(max_length=30) + +class Zephyr(models.Model): + sender = models.ForeignKey(UserProfile) + zephyr_class = models.ForeignKey(ZephyrClass) + instance = models.CharField(max_length=30) + content = models.CharField(max_length=200) + pub_date = models.DateTimeField('date published') + +def create_user_profile(sender, **kwargs): + """When creating a new user, make a profile for him or her.""" + u = kwargs["instance"] + if not UserProfile.objects.filter(user=u): + UserProfile(user=u, pointer=-1).save() +post_save.connect(create_user_profile, sender=User) diff --git a/zephyr/tests.py b/zephyr/tests.py new file mode 100644 index 0000000000..501deb776c --- /dev/null +++ b/zephyr/tests.py @@ -0,0 +1,16 @@ +""" +This file demonstrates writing tests using the unittest module. These will pass +when you run "manage.py test". + +Replace this with more appropriate tests for your application. +""" + +from django.test import TestCase + + +class SimpleTest(TestCase): + def test_basic_addition(self): + """ + Tests that 1 + 1 always equals 2. + """ + self.assertEqual(1 + 1, 2) diff --git a/zephyr/views.py b/zephyr/views.py new file mode 100644 index 0000000000..c1aa82d725 --- /dev/null +++ b/zephyr/views.py @@ -0,0 +1,97 @@ +from django.contrib.auth import authenticate, login +from django.contrib.auth.decorators import login_required +from django.core.urlresolvers import reverse +from django.http import HttpResponse, HttpResponseRedirect +from django.shortcuts import render_to_response +from django.template import RequestContext +from django.shortcuts import render + +from django.contrib.auth.models import User +from zephyr.models import Zephyr, UserProfile, ZephyrClass +from zephyr.forms import RegistrationForm + +import datetime +import simplejson + +def register(request): + if request.method == 'POST': + form = RegistrationForm(request.POST) + if form.is_valid(): + username = request.POST['username'] + password = request.POST['password'] + u = User.objects.create_user(username=username, password=password) + u.save() + user = authenticate(username=username, password=password) + login(request, user) + return HttpResponseRedirect(reverse('zephyr.views.home')) + else: + form = RegistrationForm() + + return render(request, 'zephyr/register.html', { + 'form': form, + }) + +def accounts_home(request): + return render_to_response('zephyr/accounts_home.html', + context_instance=RequestContext(request)) + +def home(request): + if not request.user.is_authenticated(): + return HttpResponseRedirect('accounts/home/') + + zephyrs = Zephyr.objects.all() + user = request.user + user_profile = UserProfile.objects.get(user=user) + if user_profile.pointer == -1: + user_profile.pointer = min([zephyr.id for zephyr in zephyrs]) + user_profile.save() + return render_to_response('zephyr/index.html', {'zephyrs': zephyrs, 'user_profile': user_profile}, + context_instance=RequestContext(request)) + +def update(request): + if not request.POST: + # Do something + pass + user = request.user + user_profile = UserProfile.objects.get(user=user) + if request.POST.get('pointer'): + user_profile.pointer = request.POST.get("pointer") + user_profile.save() + return HttpResponse(simplejson.dumps({}), mimetype='application/javascript') + +def get_updates(request): + if not request.POST: + # Do something + pass + pointer = request.POST.get('pointer') + new_zephyrs = Zephyr.objects.filter(id__gt=pointer) + new_zephyr_list = [] + for zephyr in new_zephyrs: + new_zephyr_list.append({"id": zephyr.id, + "sender": zephyr.sender.user.username, + "zephyr_class": zephyr.zephyr_class.name, + "instance": zephyr.instance, + "content": zephyr.content + }) + + return HttpResponse(simplejson.dumps(new_zephyr_list), + mimetype='application/javascript') + +@login_required +def zephyr(request): + class_name = request.POST['class'] + if ZephyrClass.objects.filter(name=class_name): + my_class = ZephyrClass.objects.get(name=class_name) + else: + my_class = ZephyrClass() + my_class.name = class_name + my_class.save() + + new_zephyr = Zephyr() + new_zephyr.sender = UserProfile.objects.get(user=request.user) + new_zephyr.content = request.POST['new_zephyr'] + new_zephyr.zephyr_class = my_class + new_zephyr.instance = request.POST['instance'] + new_zephyr.pub_date = datetime.datetime.utcnow() + new_zephyr.save() + return HttpResponseRedirect(reverse('zephyr.views.home'))