diff --git a/imager/settings.py b/imager/settings.py
index 281ae2d..623a90d 100644
--- a/imager/settings.py
+++ b/imager/settings.py
@@ -29,6 +29,11 @@
SITE_ID = 1
+# IPs
+INTERNAL_IPS = ('127.0.0.1',
+ '::1'
+ )
+
# Application definition
INSTALLED_APPS = (
@@ -43,7 +48,8 @@
'imager_user',
'imager_images',
'sorl.thumbnail',
- 'registration'
+ 'registration',
+ 'debug_toolbar',
)
MIDDLEWARE_CLASSES = (
@@ -54,6 +60,7 @@
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
+ 'debug_toolbar.middleware.DebugToolbarMiddleware',
)
ROOT_URLCONF = 'imager.urls'
@@ -116,3 +123,20 @@
REGISTRATION_OPEN = True
LOGIN_URL = '/accounts/login/'
LOGIN_REDIRECT_URL = '/profile/'
+
+# Debug toolbar settings
+DEBUG_TOOLBAR_PATCH_SETTINGS = False
+DEBUG_TOOLBAR_PANELS = (
+ 'debug_toolbar.panels.versions.VersionsPanel',
+ 'debug_toolbar.panels.timer.TimerPanel',
+ 'debug_toolbar.panels.settings.SettingsPanel',
+ 'debug_toolbar.panels.headers.HeadersPanel',
+ 'debug_toolbar.panels.request.RequestPanel',
+ 'debug_toolbar.panels.sql.SQLPanel',
+ 'debug_toolbar.panels.staticfiles.StaticFilesPanel',
+ 'debug_toolbar.panels.templates.TemplatesPanel',
+ 'debug_toolbar.panels.cache.CachePanel',
+ 'debug_toolbar.panels.signals.SignalsPanel',
+ 'debug_toolbar.panels.logging.LoggingPanel',
+ 'debug_toolbar.panels.redirects.RedirectsPanel',
+)
diff --git a/imager/templates/home.html b/imager/templates/home.html
index bbd7725..f906791 100644
--- a/imager/templates/home.html
+++ b/imager/templates/home.html
@@ -19,8 +19,8 @@
Login
Join
{% else %}
- Stream
- Library
+ Stream
+ Library
Logout
{% endif %}
diff --git a/imager/urls.py b/imager/urls.py
index 13698c5..baa685e 100644
--- a/imager/urls.py
+++ b/imager/urls.py
@@ -7,15 +7,20 @@
urlpatterns = patterns('',
# Examples:
url(r'^$', 'imager.views.home', name='home'),
- url(r'^grappelli/', include('grappelli.urls')),
- url(r'^admin/', include(admin.site.urls)),
- url(r'^accounts/', include(
- 'registration.backends.default.urls')),
- url(r'^profile/', include(
- 'imager_user.urls', namespace='profile')),
- url(r'^content/', include(
- 'imager_images.urls', namespace='content'))
+ url(r'^grappelli/',
+ include('grappelli.urls')),
+ url(r'^admin/',
+ include(admin.site.urls)),
+ url(r'^accounts/',
+ include('registration.backends.default.urls')),
+ url(r'^profile/',
+ include('imager_user.urls', namespace='profile')),
+ url(r'^',
+ include('imager_images.urls', namespace='images')),
)
if settings.DEBUG:
+ import debug_toolbar
urlpatterns += static(dcs.MEDIA_URL, document_root=dcs.MEDIA_ROOT)
+ urlpatterns += patterns('',
+ url(r'^__debug__/', include(debug_toolbar.urls)),)
diff --git a/imager_images/forms.py b/imager_images/forms.py
index 5ce76cf..582c7fa 100644
--- a/imager_images/forms.py
+++ b/imager_images/forms.py
@@ -1,5 +1,6 @@
from django.forms.models import ModelForm
from imager_images.models import Album, Photo
+# from django.forms.models import inlineformset_factory
class NewAlbumForm(ModelForm):
@@ -27,9 +28,14 @@ class Meta:
# super(PhotoAlbumForm, self).__init__(*args, **kwargs)
# # # self.fields['photo'].queryset.filter(user=self.instance.album.user)
-# # import pdb; pdb.set_trace()
-# self.fields['photo'].queryset = self.fields['photo'].queryset.filter(
-# user=self.instance.album.user)
+# import pdb; pdb.set_trace()
+# try:
+# self.instance.album
+# except:
+# pass
+# else:
+# self.fields['photo'].queryset = self.fields['photo'].queryset.filter(
+# user=self.instance.album.user)
# class Meta:
# model = Photo.albums.through
@@ -49,3 +55,38 @@ def __init__(self, *args, **kwargs):
class Meta:
model = Photo
exclude = []
+
+
+# class AlbumUpdateViewForm(ModelForm):
+# def __init__(self, *args, **kwargs):
+# super(AlbumUpdateViewForm, self).__init__(*args, **kwargs)
+# # import ipdb; ipdb.set_trace()
+# self.fields['photos'].queryset = self.instance.user.photos.all()
+
+# class Meta:
+# model = Album
+
+# fields = ('title',
+# 'description',
+# 'photos',
+# 'published'
+# )
+
+# PhotoFormSet = inlineformset_factory(Album, Photo)
+
+
+class PhotoUpdateViewForm(ModelForm):
+ def __init__(self, *args, **kwargs):
+ super(PhotoUpdateViewForm, self).__init__(*args, **kwargs)
+ # import ipdb; ipdb.set_trace()
+ self.fields['albums'].queryset = self.instance.user.albums.all()
+
+ class Meta:
+ model = Photo
+
+ fields = ('albums',
+ 'title',
+ 'description',
+ 'date_published',
+ 'published',
+ )
diff --git a/imager_images/models.py b/imager_images/models.py
index 13a88d4..db68d8e 100644
--- a/imager_images/models.py
+++ b/imager_images/models.py
@@ -1,6 +1,7 @@
from django.db import models
from django.contrib.auth.models import User
from sorl.thumbnail import ImageField
+from django.core.urlresolvers import reverse
PRIVATE = 'pvt'
SHARED = 'shd'
@@ -60,3 +61,6 @@ def __str__(self):
def album_photos(self):
self.photos.all()
+
+ def get_absolute_url(self):
+ return reverse('album', kwargs={'pk': self.pk})
diff --git a/imager_images/static/imager_images/css/screen.css b/imager_images/static/imager_images/css/screen.css
deleted file mode 100644
index 4af5642..0000000
--- a/imager_images/static/imager_images/css/screen.css
+++ /dev/null
@@ -1 +0,0 @@
-article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden]{display:none}html{background:#fff;color:#000;font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{font-size:2em;margin:0.67em 0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}mark{background:#ff0;color:#000}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:"\201C" "\201D" "\2018" "\2019"}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{border:1px solid silver;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}button,input{line-height:normal}button,select{text-transform:none}button,html input[type='button'],input[type='reset'],input[type='submit']{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}input[type='checkbox'],input[type='radio']{box-sizing:border-box;padding:0}input[type='search']{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type='search']::-webkit-search-cancel-button,input[type='search']::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}html{font:100%/1.5 "Karla","lucida grande",sans-serif,sans-serif;font-weight:400}@media (min-width: 40rem){html{font-size:106%}}@media (min-width: 64rem){html{font-size:112%}}body{color:#777;background-color:#fff}h1,h2,h3,h4,h5{color:#222;line-height:1.2em;font-family:"Montserrat","Helvetica",sans-serif;font-weight:600}h1{font-size:3.5rem;margin:0 0 0.2em 0}@media (min-width: 40rem){h1{font-size:4.5rem}}@media (min-width: 64rem){h1{font-size:5rem}}h2{color:#e67e39;margin-bottom:1.5rem;font-size:1.5rem;text-transform:uppercase}@media (min-width: 40rem){h2{font-size:2rem}}h3{font-size:1.2rem;margin-bottom:0.5rem}blockquote{margin:0}blockquote p{color:#bbb;font-style:italic;margin-bottom:1.5rem}cite{color:#bbb}p{margin:0 auto 2em auto;text-align:left}.lead{max-width:45rem;font-size:1.25rem}ol{list-style-type:decimal}ul,ol{margin:0 0 1.25em 0}li{margin-bottom:2em}li.last-list-item{border-bottom:none}dt{font-weight:bold}dd{margin-bottom:1.625em}strong{font-weight:bold}i{font-style:italic}em{font-style:normal}a{color:#4ae;text-decoration:none}a:hover{text-decoration:underline}::-moz-selection,::selection{background:#e67e39;color:#fff}.sub-point{display:block;font-size:0.75rem}*,*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}body{margin:0;padding:0;background:#fff}section{border-top:2px solid #f2f2f2;text-align:center;padding:2rem 0}section:first-of-type{border-top:none}@media (min-width: 40rem){section{padding:4rem 0}}.container{margin:0 auto;max-width:40rem;width:90%}.row{*zoom:1}.row:after{content:"";display:table;clear:both}header{padding:2rem 0;background-color:#f7f7f7;text-align:center}header p{text-align:center}.example-image-link{display:inline-block;padding:4px;margin:0 0.5rem 1rem 0.5rem;background-color:#fff;line-height:0;-webkit-transition:background-color 0.1s ease-out;-moz-transition:background-color 0.1s ease-out;-o-transition:background-color 0.1s ease-out;transition:background-color 0.1s ease-out;-webkit-border-radius:6px;-moz-border-radius:6px;-ms-border-radius:6px;-o-border-radius:6px;border-radius:6px}.example-image-link:hover{background-color:#4ae}.example-image{width:7rem;-webkit-border-radius:5px;-moz-border-radius:5px;-ms-border-radius:5px;-o-border-radius:5px;border-radius:5px}.how-to-use-section p,.how-to-use-section ol,.how-to-use-section ul,.how-to-use-section pre{text-align:left}fieldset{border:none}.donate-button{width:100%}@media (min-width: 40rem){.donate-button{width:auto}}footer{padding:2rem 0;background-color:#f7f7f7;text-align:center}footer p{text-align:center}footer .button{margin-top:0.5rem}.sharing-section{position:fixed;z-index:10;top:20px;right:0}code{color:#777;background-color:#f2f2f2;-webkit-border-radius:6px;-moz-border-radius:6px;-ms-border-radius:6px;-o-border-radius:6px;border-radius:6px;font-family:Consolas,Courier,monospace;font-size:0.9rem;padding:0.1rem 0.3rem;position:relative;top:-1px}pre{background-color:#f2f2f2;-webkit-border-radius:6px;-moz-border-radius:6px;-ms-border-radius:6px;-o-border-radius:6px;border-radius:6px;padding:0 0.5rem 0.1rem 0.5rem}pre code{padding:0;font-size:0.7rem;border:none}.column{margin-bottom:1.5rem}@media (min-width: 40rem){.column{float:left;margin:0;padding-left:1rem;padding-right:1rem}.column.full{width:100%}.column.two-thirds{width:66.7%}.column.half{width:50%}.column.third{width:33.3%}.column.fourth{width:24.95%}.column.flow-opposite{float:right}}ul{margin:0;text-align:left}@media (min-width: 40rem){ul{display:inline-block}}.button{display:block;padding:0.7rem 2rem;margin-bottom:0.5rem;border:none;color:#fff;background-color:#4ae;font-size:1.2rem;font-weight:bold;text-transform:uppercase;-webkit-border-radius:6px;-moz-border-radius:6px;-ms-border-radius:6px;-o-border-radius:6px;border-radius:6px;vertical-align:middle;white-space:nowrap}.button:hover{background:#1595ea;text-decoration:none}@media (min-width: 40rem){.button{display:inline-block;margin:0 0.25rem}}.button-minor{padding:0.35rem 1rem;border:2px solid #4ae;color:#4ae;background-color:transparent;font-size:0.8rem}.button-minor:hover{color:#fff}hr{border:0;border-top:2px solid #f2f2f2;margin:2rem auto;width:3rem}@media (min-width: 40rem){hr{margin:2.5rem auto}}
diff --git a/imager_images/templates/album_form.html b/imager_images/templates/album_form.html
new file mode 100644
index 0000000..c8d46e7
--- /dev/null
+++ b/imager_images/templates/album_form.html
@@ -0,0 +1,12 @@
+{% extends "../../imager/templates/home.html" %}
+{% block title %}Album: {{user}}{% endblock %}
+
+{% block body %}
+
+
+{% endblock %}
diff --git a/imager_images/templates/library.html b/imager_images/templates/library.html
index 16e64a8..1db3665 100644
--- a/imager_images/templates/library.html
+++ b/imager_images/templates/library.html
@@ -5,7 +5,6 @@
{% block stylesheets %}
-
{% endblock %}
@@ -21,7 +20,7 @@
{% empty %}
-
+
{% endthumbnail %}
{{album.title}}
diff --git a/imager_images/templates/new_album_form.html b/imager_images/templates/new_album_form.html
new file mode 100644
index 0000000..4678a00
--- /dev/null
+++ b/imager_images/templates/new_album_form.html
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/imager_images/templates/photo_confirm_delete.html b/imager_images/templates/photo_confirm_delete.html
new file mode 100644
index 0000000..e6f59be
--- /dev/null
+++ b/imager_images/templates/photo_confirm_delete.html
@@ -0,0 +1,10 @@
+{% extends "../../imager/templates/home.html" %}
+{% block title %}Photo: {{user}}{% endblock %}
+
+{% block body %}
+
+{% endblock %}
+
diff --git a/imager_images/templates/photo_form.html b/imager_images/templates/photo_form.html
new file mode 100644
index 0000000..1aa2cf5
--- /dev/null
+++ b/imager_images/templates/photo_form.html
@@ -0,0 +1,12 @@
+{% extends "../../imager/templates/home.html" %}
+{% block title %}Photo: {{user}}{% endblock %}
+
+{% block body %}
+
+
+{% endblock %}
diff --git a/imager_images/templates/photoadd_form.html b/imager_images/templates/photoadd_form.html
new file mode 100644
index 0000000..38c786d
--- /dev/null
+++ b/imager_images/templates/photoadd_form.html
@@ -0,0 +1 @@
+{{forms.as_p}}
diff --git a/imager_images/urls.py b/imager_images/urls.py
index 16574dd..3eb0a25 100644
--- a/imager_images/urls.py
+++ b/imager_images/urls.py
@@ -1,8 +1,31 @@
from django.conf.urls import patterns, url
+from imager_images.views import AlbumCreate, AlbumUpdate, AlbumDelete
+from imager_images.views import PhotoAddView, PhotoUpdateView, PhotoDeleteView
+from django.contrib.auth.decorators import login_required
urlpatterns = patterns('',
# Examples:
url(r'library/',
- 'imager_images.views.library', name='library'),
- url(r'stream/', 'imager_images.views.stream', name='stream')
+ 'imager_images.views.library',
+ name='library'),
+ url(r'stream/', 'imager_images.views.stream',
+ name='stream'),
+ url(r'album/add/$',
+ login_required(AlbumCreate.as_view()),
+ name='album_add'),
+ url(r'album/update/(?P\d+)/$',
+ AlbumUpdate.as_view(),
+ name='album_update'),
+ url(r'album/delete/(?P\d+)/$',
+ AlbumDelete.as_view(),
+ name='album_delete'),
+ url(r'^photo/add/$',
+ login_required(PhotoAddView.as_view()),
+ name='photo_add'),
+ url(r'^photo/update/(?P\d+)/$',
+ login_required(PhotoUpdateView.as_view()),
+ name='photo_update'),
+ url(r'^photo/delete/(?P\d+)/$',
+ login_required(PhotoDeleteView.as_view()),
+ name='photo_delete')
)
diff --git a/imager_images/views.py b/imager_images/views.py
index c8abf42..43b7ce2 100644
--- a/imager_images/views.py
+++ b/imager_images/views.py
@@ -1,10 +1,14 @@
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
-from imager_images.models import Photo
+from django.views.generic import CreateView, UpdateView, DeleteView
+from imager_images.models import Photo, Album
+from django.core.urlresolvers import reverse_lazy
+from django.contrib.auth.views import redirect_to_login
+from imager_images.forms import PhotoUpdateViewForm
+
@login_required
def library(request):
- # import pdb; pdb.set_trace();
context = {'albums': request.user.albums.all()}
return render(request, 'library.html', context)
@@ -17,3 +21,88 @@ def stream(request):
user__in=stream_users).filter(
published__in=['pub', 'shd']).order_by('date_published')}
return render(request, 'stream.html', context)
+
+
+class AlbumCreate(CreateView):
+ template_name = "new_album_form.html"
+ model = Album
+ fields = ['title', 'description', 'photos', 'published']
+
+
+class AlbumUpdate(UpdateView):
+ def user_passes_test(self, request):
+ if request.user.is_authenticated():
+ self.object = self.get_object()
+ return self.object.user == request.user
+ return False
+
+ def dispatch(self, request, *args, **kwargs):
+ if not self.user_passes_test(request):
+ return redirect_to_login(request.get_full_path())
+ return super(PhotoUpdateView, self).dispatch(
+ request, *args, **kwargs)
+
+ model = Album
+ field = ['title', 'description', 'published']
+
+
+class AlbumDelete(DeleteView):
+ def user_passes_test(self, request):
+ if request.user.is_authenticated():
+ self.object = self.get_object()
+ return self.object.user == request.user
+ return False
+
+ def dispatch(self, request, *args, **kwargs):
+ if not self.user_passes_test(request):
+ return redirect_to_login(request.get_full_path())
+ return super(PhotoUpdateView, self).dispatch(
+ request, *args, **kwargs)
+
+ model = Album
+
+
+class PhotoAddView(CreateView):
+ template_name = 'photo_form.html'
+ model = Photo
+ fields = ('image',
+ 'title',
+ 'description',
+ 'published',
+ )
+
+
+class PhotoUpdateView(UpdateView):
+ def user_passes_test(self, request):
+ if request.user.is_authenticated():
+ self.object = self.get_object()
+ return self.object.user == request.user
+ return False
+
+ def dispatch(self, request, *args, **kwargs):
+ if not self.user_passes_test(request):
+ return redirect_to_login(request.get_full_path())
+ return super(PhotoUpdateView, self).dispatch(
+ request, *args, **kwargs)
+
+ form_class = PhotoUpdateViewForm
+ model = Photo
+ template_name = 'photo_form.html'
+
+
+class PhotoDeleteView(DeleteView):
+ def user_passes_test(self, request):
+ if request.user.is_authenticated():
+ self.object = self.get_object()
+ return self.object.user == request.user
+ return False
+
+ def dispatch(self, request, *args, **kwargs):
+ if not self.user_passes_test(request):
+ return redirect_to_login(request.get_full_path())
+ return super(PhotoUpdateView, self).dispatch(
+ request, *args, **kwargs)
+
+ template_name = 'photo_confirm_delete.html'
+ model = Photo
+ success_url = reverse_lazy('images:library')
diff --git a/requirements.txt b/requirements.txt
index 52d55cc..5ba0e18 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,5 @@
Django==1.7.5
+django-debug-toolbar==1.3.0
django-grappelli==2.6.3
django-phonenumber-field==0.7.1
django-registration-redux==1.1
@@ -8,3 +9,4 @@ Pillow==2.7.0
postgres==2.1.2
psycopg2==2.6
sorl-thumbnail==12.2
+sqlparse==0.1.14