Started migrating to python3

This commit is contained in:
Sebastian 2023-07-12 19:44:08 +02:00
parent 6439a0d974
commit 58e4dbc484
12 changed files with 428 additions and 415 deletions

3
.style.yapf Normal file
View File

@ -0,0 +1,3 @@
[style]
based_on_style = pep8
column_limit=100

View File

@ -1,7 +1,8 @@
# Django settings for past3d project. # Django settings for past3d project.
from django.core.urlresolvers import reverse_lazy from django.urls import reverse_lazy
import os import os
BASE_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), '../') BASE_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), '../')
DEBUG = True DEBUG = True
@ -15,13 +16,15 @@ MANAGERS = ADMINS
DATABASES = { DATABASES = {
'default': { 'default': {
'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. 'ENGINE':
'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
'NAME': os.path.join(BASE_DIR, "data.sqlite"), # Or path to database file if using sqlite3. 'NAME': os.path.join(BASE_DIR, "data.sqlite"), # Or path to database file if using sqlite3.
# The following settings are not used with sqlite3: # The following settings are not used with sqlite3:
'USER': '', 'USER': '',
'PASSWORD': '', 'PASSWORD': '',
'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. 'HOST':
'PORT': '', # Set to empty string for default. '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP.
'PORT': '', # Set to empty string for default.
} }
} }
@ -54,7 +57,7 @@ USE_TZ = True
# Absolute filesystem path to the directory that will hold user-uploaded files. # Absolute filesystem path to the directory that will hold user-uploaded files.
# Example: "/var/www/example.com/media/" # Example: "/var/www/example.com/media/"
MEDIA_ROOT = os.path.join(BASE_DIR,"media") MEDIA_ROOT = os.path.join(BASE_DIR, "media")
# URL that handles the media served from MEDIA_ROOT. Make sure to use a # URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash. # trailing slash.
@ -65,7 +68,7 @@ MEDIA_URL = '/media/'
# Don't put anything in this directory yourself; store your static files # Don't put anything in this directory yourself; store your static files
# in apps' "static/" subdirectories and in STATICFILES_DIRS. # in apps' "static/" subdirectories and in STATICFILES_DIRS.
# Example: "/var/www/example.com/static/" # Example: "/var/www/example.com/static/"
STATIC_ROOT = os.path.join(BASE_DIR,"static") STATIC_ROOT = os.path.join(BASE_DIR, "static")
# URL prefix for static files. # URL prefix for static files.
# Example: "http://example.com/static/", "http://static.example.com/" # Example: "http://example.com/static/", "http://static.example.com/"
@ -73,7 +76,7 @@ STATIC_URL = '/static/'
# Additional locations of static files # Additional locations of static files
STATICFILES_DIRS = ( STATICFILES_DIRS = (
os.path.join(BASE_DIR,"static_common"), os.path.join(BASE_DIR, "static_common"),
# Put strings here, like "/home/html/static" or "C:/www/django/static". # Put strings here, like "/home/html/static" or "C:/www/django/static".
# Always use forward slashes, even on Windows. # Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths. # Don't forget to use absolute paths, not relative paths.
@ -84,7 +87,7 @@ STATICFILES_DIRS = (
STATICFILES_FINDERS = ( STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder', 'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder', 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
# 'django.contrib.staticfiles.finders.DefaultStorageFinder', # 'django.contrib.staticfiles.finders.DefaultStorageFinder',
) )
# Make this unique, and don't share it with anybody. # Make this unique, and don't share it with anybody.
@ -94,7 +97,7 @@ SECRET_KEY = 'InsertSomethingSecretHereBeforeDoingProduktion'
TEMPLATE_LOADERS = ( TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader', 'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader', 'django.template.loaders.app_directories.Loader',
# 'django.template.loaders.eggs.Loader', # 'django.template.loaders.eggs.Loader',
) )
MIDDLEWARE_CLASSES = ( MIDDLEWARE_CLASSES = (
@ -113,7 +116,7 @@ ROOT_URLCONF = 'past3d.urls'
WSGI_APPLICATION = 'past3d.wsgi.application' WSGI_APPLICATION = 'past3d.wsgi.application'
TEMPLATE_DIRS = ( TEMPLATE_DIRS = (
os.path.join(BASE_DIR,'templates'), os.path.join(BASE_DIR, 'templates'),
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows. # Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths. # Don't forget to use absolute paths, not relative paths.
@ -140,7 +143,7 @@ SESSION_SERIALIZER = 'django.contrib.sessions.serializers.JSONSerializer'
LOGIN_REDIRECT_URL = reverse_lazy('geometry_create') LOGIN_REDIRECT_URL = reverse_lazy('geometry_create')
EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend' EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend'
EMAIL_FILE_PATH = '/tmp/django' EMAIL_FILE_PATH = '/tmp/django'
# A sample logging configuration. The only tangible logging # A sample logging configuration. The only tangible logging
# performed by this configuration is to send an email to # performed by this configuration is to send an email to

View File

@ -1,31 +1,19 @@
from django.conf.urls import patterns, include, url from django.urls import include, re_path, path
from django.conf import settings from django.conf import settings
from django.conf.urls.static import static from django.conf.urls.static import static
# Uncomment the next two lines to enable the admin: # Uncomment the next two lines to enable the admin:
from django.contrib import admin from django.contrib import admin
admin.autodiscover() admin.autodiscover()
from views import HomeView from past3d.views import HomeView
urlpatterns = patterns('', urlpatterns = [
# Examples: re_path(r'^$', HomeView.as_view(), name='home'),
# url(r'^$', 'past3d.views.home', name='home'), path('users/', include('users.urls')),
# url(r'^past3d/', include('past3d.foo.urls')), path('3d/', include('pastebin.urls')),
path('admin/', admin.site.urls),
url(r'^$', HomeView.as_view(), name='home'), ]
url(r'^users/', include('users.urls')),
url(r'^3d/', include('pastebin.urls')),
# 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)),
)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

View File

@ -2,9 +2,11 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from django.contrib import admin from django.contrib import admin
from models import Geometry from pastebin.models import Geometry
class GeometryAdmin(admin.ModelAdmin): class GeometryAdmin(admin.ModelAdmin):
list_display = ['name', 'description', 'date', 'file', 'sourcefile'] list_display = ['name', 'description', 'date', 'file', 'sourcefile']
admin.site.register(Geometry, GeometryAdmin) admin.site.register(Geometry, GeometryAdmin)

View File

@ -5,7 +5,7 @@ import struct
from django.forms import ModelForm from django.forms import ModelForm
from django import forms from django import forms
from models import Geometry from pastebin.models import Geometry
facet_pattern = re.compile(r'facet normal\s+[0-9.e+-]+\s+[0-9.e+-]+\s+[0-9.e+-]+') facet_pattern = re.compile(r'facet normal\s+[0-9.e+-]+\s+[0-9.e+-]+\s+[0-9.e+-]+')
loop_pattern = re.compile(r'outer\s+loop') loop_pattern = re.compile(r'outer\s+loop')
@ -14,74 +14,77 @@ endloop_pattern = re.compile(r'endloop')
endfacet_pattern = re.compile(r'endfacet') endfacet_pattern = re.compile(r'endfacet')
endsolid_pattern = re.compile(r'endsolid .*') endsolid_pattern = re.compile(r'endsolid .*')
class STLUploadForm(ModelForm): class STLUploadForm(ModelForm):
def clean_file(self):
stlfile = self.cleaned_data.get("file") def clean_file(self):
stlfile.open()
if stlfile.read(5) != "solid": stlfile = self.cleaned_data.get("file")
#print "binary" stlfile.open()
#Skip header
stlfile.seek(80)
count = struct.unpack("i",stlfile.read(4))[0]
if stlfile.size - 84 != count * 50:
raise forms.ValidationError("Not a valid binary STL file.")
else: if stlfile.read(5) != "solid":
#print "ascii" #print "binary"
next_patterns = [facet_pattern] #Skip header
stlfile.readline() stlfile.seek(80)
line = stlfile.readline().strip() count = struct.unpack("i", stlfile.read(4))[0]
if stlfile.size - 84 != count * 50:
matched_pattern = None raise forms.ValidationError("Not a valid binary STL file.")
vertex_count = 0
while line != "": else:
#print "ascii"
next_patterns = [facet_pattern]
stlfile.readline()
line = stlfile.readline().strip()
corret = False matched_pattern = None
for pattern in next_patterns: vertex_count = 0
if pattern.match(line) != None:
corret = True
matched_pattern = pattern
if not corret:
raise forms.ValidationError("Not a valid ascii STL file.")
if matched_pattern == facet_pattern: while line != "":
next_patterns = [loop_pattern]
if matched_pattern == loop_pattern:
vertex_count = 0
next_patterns = [vertex_pattern]
if matched_pattern == vertex_pattern:
vertex_count += 1
if vertex_count < 3:
next_patterns = [vertex_pattern, endloop_pattern]
else :
next_patterns = [endloop_pattern]
if matched_pattern == endloop_pattern:
next_patterns = [endfacet_pattern]
if matched_pattern == endfacet_pattern:
next_patterns = [facet_pattern, endsolid_pattern]
line = stlfile.readline().strip() corret = False
for pattern in next_patterns:
if pattern.match(line) != None:
corret = True
matched_pattern = pattern
if not corret:
raise forms.ValidationError("Not a valid ascii STL file.")
if matched_pattern != endsolid_pattern: if matched_pattern == facet_pattern:
raise forms.ValidationError("Not a valid ascii STL file.") next_patterns = [loop_pattern]
if matched_pattern == loop_pattern:
vertex_count = 0
next_patterns = [vertex_pattern]
if matched_pattern == vertex_pattern:
vertex_count += 1
if vertex_count < 3:
next_patterns = [vertex_pattern, endloop_pattern]
else:
next_patterns = [endloop_pattern]
if matched_pattern == endloop_pattern:
next_patterns = [endfacet_pattern]
if matched_pattern == endfacet_pattern:
next_patterns = [facet_pattern, endsolid_pattern]
# see https://code.djangoproject.com/ticket/20020 line = stlfile.readline().strip()
# stlfile.close()
return stlfile if matched_pattern != endsolid_pattern:
raise forms.ValidationError("Not a valid ascii STL file.")
# see https://code.djangoproject.com/ticket/20020
# stlfile.close()
return stlfile
class GeometryForm(STLUploadForm): class GeometryForm(STLUploadForm):
class Meta:
model = Geometry class Meta:
fields = ['name', 'description', 'public', 'expiration', 'file', 'sourcefile'] model = Geometry
fields = ['name', 'description', 'public', 'expiration', 'file', 'sourcefile']
class AnonymousGeometryForm(STLUploadForm): class AnonymousGeometryForm(STLUploadForm):
expiration = forms.ChoiceField(choices=Geometry.EXPIRATION_CHOICES[:-1]) expiration = forms.ChoiceField(choices=Geometry.EXPIRATION_CHOICES[:-1])
class Meta:
model = Geometry
fields = ['name', 'description', 'public', 'expiration', 'file']
class Meta:
model = Geometry
fields = ['name', 'description', 'public', 'expiration', 'file']

View File

@ -5,164 +5,160 @@ import re
from hashlib import md5 from hashlib import md5
from datetime import datetime, timedelta from datetime import datetime, timedelta
from django.core.urlresolvers import reverse from django.urls import reverse
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.db import models from django.db import models
vertex_pattern = re.compile(r'vertex\s+([0-9.e+-]+)\s+([0-9.e+-]+)\s+([0-9.e+-]+)') vertex_pattern = re.compile(r'vertex\s+([0-9.e+-]+)\s+([0-9.e+-]+)\s+([0-9.e+-]+)')
def safe_upload_path(base_dir): def safe_upload_path(base_dir):
def generate_path(instance, filename): def generate_path(instance, filename):
ext = os.path.splitext(filename)[1] ext = os.path.splitext(filename)[1]
md5sum = md5() md5sum = md5()
md5sum.update(instance.name md5sum.update(instance.name + str(datetime.now()) + filename)
+ str(datetime.now()) randomname = md5sum.hexdigest()
+ filename)
randomname = md5sum.hexdigest()
return os.path.join(base_dir,'%s%s' % (randomname, ext)) return os.path.join(base_dir, '%s%s' % (randomname, ext))
return generate_path
return generate_path
class Geometry(models.Model): class Geometry(models.Model):
HOUR = 0 HOUR = 0
DAY = 1 DAY = 1
WEEK = 2 WEEK = 2
MONTH = 3 MONTH = 3
FORERVER = 4 FORERVER = 4
EXPIRATION_CHOICES = ((HOUR, 'one hour'), EXPIRATION_CHOICES = ((HOUR, 'one hour'), (DAY, 'one day'), (WEEK, 'one week'),
(DAY, 'one day'), (MONTH, 'one month'), (FORERVER, 'forever'))
(WEEK, 'one week'),
(MONTH, 'one month'),
(FORERVER, 'forever'))
DELTAS = { HOUR : timedelta(hours = 1), DELTAS = {
DAY : timedelta(days = 1), HOUR: timedelta(hours=1),
WEEK : timedelta(weeks = 1), DAY: timedelta(days=1),
MONTH : timedelta(weeks = 4)} WEEK: timedelta(weeks=1),
MONTH: timedelta(weeks=4)
}
name = models.CharField(max_length = 128) name = models.CharField(max_length=128)
description = models.TextField(blank=True) description = models.TextField(blank=True)
user = models.ForeignKey(User, blank=True, null=True) user = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE)
date = models.DateTimeField(auto_now_add=True) date = models.DateTimeField(auto_now_add=True)
expiration = models.IntegerField(default = 0, choices = EXPIRATION_CHOICES) expiration = models.IntegerField(default=0, choices=EXPIRATION_CHOICES)
public = models.BooleanField(default=True) public = models.BooleanField(default=True)
polycount = models.IntegerField(blank=True, default=0) polycount = models.IntegerField(blank=True, default=0)
width = models.FloatField(blank=True, default=0) width = models.FloatField(blank=True, default=0)
depth = models.FloatField(blank=True, default=0) depth = models.FloatField(blank=True, default=0)
height = models.FloatField(blank=True, default=0) height = models.FloatField(blank=True, default=0)
file = models.FileField(upload_to=safe_upload_path('models')) file = models.FileField(upload_to=safe_upload_path('models'))
sourcefile = models.FileField(upload_to=safe_upload_path('sources'), blank=True) sourcefile = models.FileField(upload_to=safe_upload_path('sources'), blank=True)
def get_absolute_url(self): def get_absolute_url(self):
return reverse('geometry_details', kwargs={'id' : self.pk}) return reverse('geometry_details', kwargs={'id': self.pk})
@classmethod @classmethod
def get_latest(cls): def get_latest(cls):
return cls.objects.all().filter(public = True).order_by('-date')[:10] return cls.objects.all().filter(public=True).order_by('-date')[:10]
def get_expiration_date(self): def get_expiration_date(self):
for expiration in [self.HOUR, self.DAY, self.WEEK, self.MONTH]: for expiration in [self.HOUR, self.DAY, self.WEEK, self.MONTH]:
if self.expiration == expiration: if self.expiration == expiration:
return self.date + self.DELTAS[expiration] return self.date + self.DELTAS[expiration]
return None return None
def _generate_meta_infos(self):
print("Generating metainfos %s" % self.name)
def _generate_meta_infos(self): self.file.open()
print "Generating metainfos %s" % self.name
self.file.open() count = 0
min_coord = [None, None, None]
max_coord = [None, None, None]
count = 0 if self.file.read(5) != "solid":
min_coord = [None,None,None] print("binary")
max_coord = [None,None,None] # Skip header
self.file.seek(80)
count = struct.unpack("i", self.file.read(4))[0]
if self.file.read(5) != "solid": done = False
print "binary" for pos in range(0, count):
#Skip header # Skip normal (3 * 32bit)
self.file.seek(80) self.file.seek(self.file.tell() + 3 * 4)
count = struct.unpack("i",self.file.read(4))[0] # Loop over each coordinate
for vert in range(0, 3):
# Loop over each coordinate
for i in range(0, 3):
x = struct.unpack("<f", self.file.read(4))[0]
done = False if min_coord[i] is not None:
for pos in range(0,count): min_coord[i] = min(min_coord[i], x)
#Skip normal (3 * 32bit) else:
self.file.seek(self.file.tell()+3*4) min_coord[i] = x
#Loop over each coordinate
for vert in range(0,3):
# Loop over each coordinate
for i in range(0,3):
x = struct.unpack("<f",self.file.read(4))[0]
if min_coord[i] != None : if max_coord[i] is not None:
min_coord[i] = min(min_coord[i], x) max_coord[i] = max(max_coord[i], x)
else: else:
min_coord[i] = x max_coord[i] = x
# Skip attributes (16bit)
self.file.seek(self.file.tell() + 2)
if max_coord[i] != None : else:
max_coord[i] = max(max_coord[i], x) print("ascii")
else:
max_coord[i] = x
#Skip attributes (16bit)
self.file.seek(self.file.tell()+2)
else: line = self.file.readline()
print "ascii" while line != "":
line = line.strip()
if line.startswith("facet"):
count = count + 1
if line.startswith("vertex"):
coords = vertex_pattern.match(line).groups()
for i in range(0, 3):
x = float(coords[i])
line = self.file.readline() if min_coord[i] is not None:
while line != "": min_coord[i] = min(min_coord[i], x)
line = line.strip() else:
if line.startswith("facet"): min_coord[i] = x
count = count + 1
if line.startswith("vertex"):
coords = vertex_pattern.match(line).groups();
for i in range(0,3):
x = float(coords[i])
if min_coord[i] != None : if max_coord[i] is not None:
min_coord[i] = min(min_coord[i], x) max_coord[i] = max(max_coord[i], x)
else: else:
min_coord[i] = x max_coord[i] = x
if max_coord[i] != None : line = self.file.readline()
max_coord[i] = max(max_coord[i], x)
else:
max_coord[i] = x
line = self.file.readline() self.file.close()
self.file.close() self.width = max_coord[0] - min_coord[0]
self.depth = max_coord[1] - min_coord[1]
self.height = max_coord[2] - min_coord[2]
self.polycount = count
self.width = max_coord[0] - min_coord[0] self.save()
self.depth = max_coord[1] - min_coord[1]
self.height = max_coord[2] - min_coord[2]
self.polycount = count
self.save() def get_polycount(self):
if self.polycount == 0:
self._generate_meta_infos()
return self.polycount
def get_polycount(self): def get_width(self):
if self.polycount == 0: if self.polycount == 0:
self._generate_meta_infos() self._generate_meta_infos()
return self.polycount return self.width
def get_width(self): def get_depth(self):
if self.polycount == 0: if self.polycount == 0:
self._generate_meta_infos() self._generate_meta_infos()
return self.width return self.depth
def get_depth(self): def get_height(self):
if self.polycount == 0: if self.polycount == 0:
self._generate_meta_infos() self._generate_meta_infos()
return self.depth return self.height
def get_height(self):
if self.polycount == 0:
self._generate_meta_infos()
return self.height

View File

@ -1,11 +1,11 @@
from django.conf.urls import patterns, include, url from django.urls import re_path
from views import GeometryView, GeometryListView, GeometryCreate, GeometryDelete from pastebin.views import GeometryView, GeometryListView, GeometryCreate, GeometryDelete
urlpatterns = patterns('', urlpatterns = [
url(r'^new/$', GeometryCreate.as_view(), name='geometry_create'), re_path(r'^new/$', GeometryCreate.as_view(), name='geometry_create'),
url(r'^list/$', GeometryListView.as_view(), name='geometry_list'), re_path(r'^list/$', GeometryListView.as_view(), name='geometry_list'),
url(r'^list/page/(?P<page>[0-9]+)/$', GeometryListView.as_view(), name='geometry_list'), re_path(r'^list/page/(?P<page>[0-9]+)/$', GeometryListView.as_view(), name='geometry_list'),
url(r'^delete/(?P<id>\d+)/$', GeometryDelete.as_view(), name='geometry_delete'), re_path(r'^delete/(?P<id>\d+)/$', GeometryDelete.as_view(), name='geometry_delete'),
url(r'^(?P<id>\d+)/$', GeometryView.as_view(), name='geometry_details')) re_path(r'^(?P<id>\d+)/$', GeometryView.as_view(), name='geometry_details')
]

View File

@ -1,23 +1,25 @@
from django.views.generic.edit import CreateView, DeleteView from django.views.generic.edit import CreateView, DeleteView
from django.views.generic.detail import DetailView from django.views.generic.detail import DetailView
from django.core.urlresolvers import reverse from django.urls import reverse
from django.views.generic.base import ContextMixin from django.views.generic.base import ContextMixin
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
from django.views.generic.list import ListView from django.views.generic.list import ListView
from forms import GeometryForm, AnonymousGeometryForm from pastebin.forms import GeometryForm, AnonymousGeometryForm
from models import Geometry from pastebin.models import Geometry
class LastesGeometriesMixin(ContextMixin): class LastesGeometriesMixin(ContextMixin):
def get_context_data(self, **kwargs):
context = super(LastesGeometriesMixin, self).get_context_data(**kwargs) def get_context_data(self, **kwargs):
context['latest_geometries'] = Geometry.get_latest() context = super(LastesGeometriesMixin, self).get_context_data(**kwargs)
return context context['latest_geometries'] = Geometry.get_latest()
return context
class GeometryListView(ListView, LastesGeometriesMixin): class GeometryListView(ListView, LastesGeometriesMixin):
queryset = Geometry.objects.all().filter(public = True).order_by('date') queryset = Geometry.objects.all().filter(public=True).order_by('date')
paginate_by = 50 paginate_by = 50
paginate_orphans = 25 paginate_orphans = 25
page_kwarg = 'page' page_kwarg = 'page'
@ -26,10 +28,10 @@ class GeometryListView(ListView, LastesGeometriesMixin):
class GeometryView(DetailView): class GeometryView(DetailView):
model = Geometry model = Geometry
pk_url_kwarg = 'id' pk_url_kwarg = 'id'
context_object_name = 'geometry' context_object_name = 'geometry'
template_name = 'pastebin/geometry.html' template_name = 'pastebin/geometry.html'
class GeometryCreate(CreateView, LastesGeometriesMixin): class GeometryCreate(CreateView, LastesGeometriesMixin):
@ -37,28 +39,29 @@ class GeometryCreate(CreateView, LastesGeometriesMixin):
template_name = 'pastebin/geometry_create.html' template_name = 'pastebin/geometry_create.html'
def get_success_url(self): def get_success_url(self):
return reverse('geometry_details', kwargs={'id' :self.object.id}) return reverse('geometry_details', kwargs={'id': self.object.id})
def get_form_class(self): def get_form_class(self):
if self.request.user.is_authenticated() : if self.request.user.is_authenticated():
return GeometryForm return GeometryForm
else: else:
return AnonymousGeometryForm return AnonymousGeometryForm
def form_valid(self, form): def form_valid(self, form):
res = super(GeometryCreate, self).form_valid(form) res = super(GeometryCreate, self).form_valid(form)
if self.request.user.is_authenticated() : if self.request.user.is_authenticated():
self.object.user = self.request.user self.object.user = self.request.user
self.object.save() self.object.save()
return res
return res
class GeometryDelete(DeleteView, LastesGeometriesMixin): class GeometryDelete(DeleteView, LastesGeometriesMixin):
model = Geometry model = Geometry
pk_url_kwarg = 'id' pk_url_kwarg = 'id'
template_name = 'pastebin/geometry_delete.html' template_name = 'pastebin/geometry_delete.html'
success_url ='/' success_url = '/'
def check_user(self, request): def check_user(self, request):
obj = self.get_object() obj = self.get_object()
@ -67,8 +70,8 @@ class GeometryDelete(DeleteView, LastesGeometriesMixin):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
self.check_user(request) self.check_user(request)
return super(GeometryDelete,self).get(self, request, *args, **kwargs) return super(GeometryDelete, self).get(self, request, *args, **kwargs)
def delete(self, request, *args, **kwargs): def delete(self, request, *args, **kwargs):
self.check_user(request) self.check_user(request)
return super(GeometryDelete,self).delete(self, request, *args, **kwargs) return super(GeometryDelete, self).delete(self, request, *args, **kwargs)

View File

@ -1,5 +1,6 @@
Django==1.5.4 asgiref==3.7.2
Werkzeug==0.9.4 Django==4.2.3
django-extensions==1.2.2 django-extensions==3.2.3
six==1.4.1 MarkupSafe==2.1.3
wsgiref==0.1.2 sqlparse==0.4.4
Werkzeug==2.3.6

View File

@ -2,93 +2,86 @@ from django import forms
from django.forms import ModelForm from django.forms import ModelForm
from django.contrib.auth.models import User from django.contrib.auth.models import User
class UserCreateForm(ModelForm): class UserCreateForm(ModelForm):
password1 = forms.CharField(label='Password', widget=forms.PasswordInput) password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput) password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
class Meta:
model = User
fields = ['username', 'email']
class Meta:
model = User
fields = ['username', 'email']
def clean_password2(self): def clean_password2(self):
password1 = self.cleaned_data.get("password1") password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2") password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password1
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
def clean_email(self): return password1
#Make sure Email is unique
email = self.cleaned_data.get("email")
if User.objects.filter(email = email):
raise forms.ValidationError("Email already in use.")
return email def clean_email(self):
# Make sure Email is unique
email = self.cleaned_data.get("email")
if User.objects.filter(email=email):
raise forms.ValidationError("Email already in use.")
return email
def save(self, commit=True): def save(self, commit=True):
user = super(UserCreateForm, self).save(commit=False) user = super(UserCreateForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"]) user.set_password(self.cleaned_data["password1"])
user.is_active = False user.is_active = False
if commit: if commit:
user.save() user.save()
return user return user
class UserUpdateForm(ModelForm): class UserUpdateForm(ModelForm):
new_password1 = forms.CharField(label='New Password', new_password1 = forms.CharField(label='New Password',
widget=forms.PasswordInput, widget=forms.PasswordInput,
required=False) required=False)
new_password2 = forms.CharField(label='New Password confirmation', new_password2 = forms.CharField(label='New Password confirmation',
widget=forms.PasswordInput, widget=forms.PasswordInput,
required=False) required=False)
current_password = forms.CharField(label='Current Password', widget=forms.PasswordInput) current_password = forms.CharField(label='Current Password', widget=forms.PasswordInput)
class Meta: class Meta:
model = User model = User
fields = ['email'] fields = ['email']
def clean_current_password(self):
current_password = self.cleaned_data.get("current_password")
def clean_current_password(self): if not self.instance.check_password(current_password):
current_password = self.cleaned_data.get("current_password") raise forms.ValidationError("Password incorrect")
if not self.instance.check_password(current_password):
raise forms.ValidationError("Password incorrect")
return current_password return current_password
def clean_new_password2(self):
password1 = self.cleaned_data.get("new_password1")
password2 = self.cleaned_data.get("new_password2")
def clean_new_password2(self): if password1 and password2 and password1 != password2:
password1 = self.cleaned_data.get("new_password1") raise forms.ValidationError("Passwords don't match")
password2 = self.cleaned_data.get("new_password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password1
return password1
def clean_email(self): def clean_email(self):
#Make sure Email is still unique # Make sure Email is still unique
email = self.cleaned_data.get("email") email = self.cleaned_data.get("email")
if User.objects.filter(email = email).exclude(id=self.instance.id): if User.objects.filter(email=email).exclude(id=self.instance.id):
raise forms.ValidationError("Email already in use.") raise forms.ValidationError("Email already in use.")
return email return email
def save(self, commit=True):
user = super(UserUpdateForm, self).save(commit=False)
def save(self, commit=True): password = self.cleaned_data.get("new_password1")
user = super(UserUpdateForm, self).save(commit=False) if password:
user.set_password(password)
password = self.cleaned_data.get("new_password1")
if password: if commit:
user.set_password(password) user.save()
return user
if commit:
user.save()
return user

View File

@ -1,37 +1,57 @@
from django.conf.urls import patterns, include, url from django.urls import re_path, path, reverse_lazy
from django.core.urlresolvers import reverse_lazy from django.contrib.auth import views as auth_views
from pastebin.models import Geometry from pastebin.models import Geometry
from views import * from users.views import *
urlpatterns = patterns('', urlpatterns = [
url(r'^signup/$', UserCreateView.as_view(), name='signup'), re_path(r'^signup/$', UserCreateView.as_view(), name='signup'),
url(r'^confirm/(?P<user_id>\d+)/$', SendConfirmationView.as_view(), name='send_confirmation'), re_path(r'^confirm/(?P<user_id>\d+)/$', SendConfirmationView.as_view(), name='send_confirmation'),
url(r'^confirm/(?P<user_id>\d+)/(?P<token>.+)/$', CheckConfirmationView.as_view(), name='check_confirmation'), re_path(r'^confirm/(?P<user_id>\d+)/(?P<token>.+)/$',
CheckConfirmationView.as_view(),
url(r'^update/(?P<user_id>\d+)/$', UserUpdateView.as_view(), name='user_update'), name='check_confirmation'),
re_path(r'^update/(?P<user_id>\d+)/$', UserUpdateView.as_view(), name='user_update'),
url(r'^password/reset/$', 'django.contrib.auth.views.password_reset', {'extra_context' : {'latest_geometries' : Geometry.get_latest()}, path('password/reset/',
'template_name' : 'users/password_reset.html', auth_views.PasswordResetView.as_view(), {
'post_reset_redirect' : reverse_lazy('password_reset_sent')}, 'extra_context': {
name='password_reset'), 'latest_geometries': Geometry.get_latest()
},
url(r'^password/reset/(?P<uidb36>[0-9A-Za-z]+)/(?P<token>.+)/$', 'django.contrib.auth.views.password_reset_confirm', {'extra_context' : {'latest_geometries' : Geometry.get_latest()}, 'template_name': 'users/password_reset.html',
'template_name' : 'users/password_reset_confirm.html', 'post_reset_redirect': reverse_lazy('password_reset_sent')
'post_reset_redirect' : reverse_lazy('login')}, },
name='password_reset_confirm'), name='password_reset'),
path('password/reset/confirm/',
url(r'^password/reset/sent/$', 'django.contrib.auth.views.password_reset_done', {'extra_context' : {'latest_geometries' : Geometry.get_latest()}, auth_views.PasswordResetConfirmView.as_view(), {
'template_name' : 'users/password_reset_sent.html',}, 'extra_context': {
name='password_reset_sent'), 'latest_geometries': Geometry.get_latest()
},
'template_name': 'users/password_reset_confirm.html',
url(r'^login/$', 'django.contrib.auth.views.login', {'extra_context' : {'latest_geometries' : Geometry.get_latest()}, 'post_reset_redirect': reverse_lazy('login')
'template_name' : 'users/login.html'}, },
name='login'), name='password_reset_confirm'),
path('password/reset/sent/',
url(r'^logout/$', 'django.contrib.auth.views.logout',{'extra_context' : {'latest_geometries' : Geometry.get_latest()}, auth_views.PasswordResetDoneView.as_view(), {
'next_page' : reverse_lazy('login')}, 'extra_context': {
name='logout'), 'latest_geometries': Geometry.get_latest()
) },
'template_name': 'users/password_reset_sent.html',
},
name='password_reset_sent'),
path('login/',
auth_views.LoginView.as_view(), {
'extra_context': {
'latest_geometries': Geometry.get_latest()
},
'template_name': 'users/login.html'
},
name='login'),
path('logout/',
auth_views.LogoutView.as_view(), {
'extra_context': {
'latest_geometries': Geometry.get_latest()
},
'next_page': reverse_lazy('login')
},
name='logout'),
]

View File

@ -1,104 +1,105 @@
from django.views.generic.edit import CreateView, UpdateView from django.views.generic.edit import CreateView, UpdateView
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.urlresolvers import reverse from django.urls import reverse
from django.contrib.sites.models import get_current_site from django.contrib.sites.shortcuts import get_current_site
from django.contrib.auth.tokens import default_token_generator from django.contrib.auth.tokens import default_token_generator
from django.template import loader from django.template import loader
from django.utils.http import int_to_base36 from django.utils.http import int_to_base36
from django.http import Http404 from django.http import Http404
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from pastebin.views import LastesGeometriesMixin from pastebin.views import LastesGeometriesMixin
from forms import UserCreateForm, UserUpdateForm from users.forms import UserCreateForm, UserUpdateForm
class UserCreateView(CreateView, LastesGeometriesMixin): class UserCreateView(CreateView, LastesGeometriesMixin):
model = User model = User
form_class = UserCreateForm form_class = UserCreateForm
template_name = 'users/signup.html' template_name = 'users/signup.html'
def get_success_url(self):
def get_success_url(self): return reverse('send_confirmation', kwargs={'user_id': self.object.pk})
return reverse('send_confirmation', kwargs={'user_id' : self.object.pk})
class UserUpdateView(UpdateView, LastesGeometriesMixin): class UserUpdateView(UpdateView, LastesGeometriesMixin):
model = User model = User
form_class = UserUpdateForm form_class = UserUpdateForm
template_name = 'users/user_update.html' template_name = 'users/user_update.html'
pk_url_kwarg = 'user_id' pk_url_kwarg = 'user_id'
def get_queryset(self): def get_queryset(self):
return self.model.objects.filter(id=self.request.user.id) return self.model.objects.filter(id=self.request.user.id)
def get_success_url(self):
return reverse('geometry_create')
def get_success_url(self):
return reverse('geometry_create')
class SendConfirmationView(TemplateView, LastesGeometriesMixin): class SendConfirmationView(TemplateView, LastesGeometriesMixin):
template_name = 'users/send_confirmation.html' template_name = 'users/send_confirmation.html'
email_template_name = 'users/confirmation_email.txt' email_template_name = 'users/confirmation_email.txt'
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(SendConfirmationView, self).get_context_data(**kwargs) context = super(SendConfirmationView, self).get_context_data(**kwargs)
context['confirm_user'] = User.objects.get(id=kwargs['user_id']) context['confirm_user'] = User.objects.get(id=kwargs['user_id'])
return context return context
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
try: try:
user = User.objects.get(id=kwargs['user_id']) user = User.objects.get(id=kwargs['user_id'])
except User.DoesNotExist: except User.DoesNotExist:
raise Http404 raise Http404
if user.is_active: if user.is_active:
raise Http404 raise Http404
site_name = get_current_site(self.request).name
uid = int_to_base36(user.pk)
token = default_token_generator.make_token(user)
link = request.build_absolute_uri(reverse('check_confirmation', kwargs={'user_id' : user.pk, 'token' : token}))
context = { site_name = get_current_site(self.request).name
'email': user.email, uid = int_to_base36(user.pk)
'site_name': site_name, token = default_token_generator.make_token(user)
'validation_link': link, link = request.build_absolute_uri(
'user': user reverse('check_confirmation', kwargs={
} 'user_id': user.pk,
'token': token
}))
subject = "Validate your registration at %s" % site_name context = {
email = loader.render_to_string(self.email_template_name, context) 'email': user.email,
user.email_user(subject,email) 'site_name': site_name,
'validation_link': link,
'user': user
}
subject = "Validate your registration at %s" % site_name
email = loader.render_to_string(self.email_template_name, context)
user.email_user(subject, email)
return super(SendConfirmationView,self).get(self, request, *args, **kwargs) return super(SendConfirmationView, self).get(self, request, *args, **kwargs)
class CheckConfirmationView(TemplateView, LastesGeometriesMixin): class CheckConfirmationView(TemplateView, LastesGeometriesMixin):
template_name = 'users/check_confirmation.html' template_name = 'users/check_confirmation.html'
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(CheckConfirmationView, self).get_context_data(**kwargs) context = super(CheckConfirmationView, self).get_context_data(**kwargs)
context['confirm_user'] = User.objects.get(id=kwargs['user_id']) context['confirm_user'] = User.objects.get(id=kwargs['user_id'])
return context return context
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
try: try:
user = User.objects.get(id=kwargs['user_id']) user = User.objects.get(id=kwargs['user_id'])
except User.DoesNotExist: except User.DoesNotExist:
raise Http404 raise Http404
if user.is_active: if user.is_active:
raise Http404 raise Http404
if not default_token_generator.check_token(user,kwargs['token']): if not default_token_generator.check_token(user, kwargs['token']):
raise Http404 raise Http404
user.is_active = True user.is_active = True
user.save() user.save()
print "Acitvating %s" % user.username print("Acitvating %s" % user.username)
return super(CheckConfirmationView,self).get(self, request, *args, **kwargs) return super(CheckConfirmationView, self).get(self, request, *args, **kwargs)