2
0
mirror of https://expo.survex.com/repositories/troggle/.git synced 2024-11-22 07:11:52 +00:00

Upload form for Photos

This commit is contained in:
Philip Sargent 2022-03-13 01:01:00 +00:00
parent f99ebf84e9
commit b65639df05
6 changed files with 236 additions and 8 deletions

View File

@ -153,7 +153,7 @@ class PageTests(TestCase):
def test_expoweb_via_areaid(self): def test_expoweb_via_areaid(self):
# the dispatcher takes a detour via the cave renering procedure for this # the dispatcher takes a detour via the cave renering procedure for this
response = self.client.get('/1623/others/t/via201.jpg') response = self.client.get('/guidebook/t/via201.jpg')
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.content), 6057) self.assertEqual(len(response.content), 6057)
@ -175,7 +175,6 @@ class PageTests(TestCase):
phmatch = re.search(ph, content) phmatch = re.search(ph, content)
self.assertIsNotNone(phmatch, "Failed to find expected text: '" + ph +"'") self.assertIsNotNone(phmatch, "Failed to find expected text: '" + ph +"'")
def test_page_admin(self): def test_page_admin(self):
# see the login page # see the login page
response = self.client.get('/admin/login/') response = self.client.get('/admin/login/')

View File

@ -12,6 +12,7 @@ from django.shortcuts import render
from django.template import Context, loader from django.template import Context, loader
from django.core.files.storage import FileSystemStorage, default_storage from django.core.files.storage import FileSystemStorage, default_storage
#from troggle import settings
from troggle.parsers.imports import import_caves, import_people, import_surveyscans from troggle.parsers.imports import import_caves, import_people, import_surveyscans
from troggle.parsers.imports import import_logbooks, import_QMs, import_drawingsfiles, import_survex from troggle.parsers.imports import import_logbooks, import_QMs, import_drawingsfiles, import_survex
# from databaseReset import reinit_db # don't do this. databaseRest runs code *at import time* # from databaseReset import reinit_db # don't do this. databaseRest runs code *at import time*
@ -19,6 +20,7 @@ from troggle.core.models.troggle import Expedition, Person, PersonExpedition
from troggle.core.models.caves import LogbookEntry, QM, Cave, PersonTrip from troggle.core.models.caves import LogbookEntry, QM, Cave, PersonTrip
from troggle.core.models.survex import DrawingFile from troggle.core.models.survex import DrawingFile
from .auth import login_required_if_public from .auth import login_required_if_public
#from django.views.decorators.csrf import ensure_csrf_cookie, csrf_exempt
'''File upload 'views' '''File upload 'views'
''' '''
@ -42,6 +44,9 @@ todo = '''
class FilesForm(forms.Form): # not a model-form, just a form-form class FilesForm(forms.Form): # not a model-form, just a form-form
uploadfiles = forms.FileField() uploadfiles = forms.FileField()
class TextForm(forms.Form): # not a model-form, just a form-form
photographer = forms.CharField(strip=True)
@login_required_if_public @login_required_if_public
def scanupload(request, wallet=None): def scanupload(request, wallet=None):
'''Upload scanned image files into a wallet on /expofiles '''Upload scanned image files into a wallet on /expofiles
@ -77,9 +82,11 @@ def scanupload(request, wallet=None):
dirpath = Path(settings.SURVEY_SCANS, year, wallet) dirpath = Path(settings.SURVEY_SCANS, year, wallet)
form = FilesForm() form = FilesForm()
if request.method == 'POST': if request.method == 'POST':
form = FilesForm(request.POST,request.FILES) form = FilesForm(request.POST,request.FILES)
print(f'! - FilesForm POSTED')
if form.is_valid(): if form.is_valid():
f = request.FILES["uploadfiles"] f = request.FILES["uploadfiles"]
multiple = request.FILES.getlist('uploadfiles') multiple = request.FILES.getlist('uploadfiles')
@ -115,6 +122,80 @@ def scanupload(request, wallet=None):
return render(request, 'scanuploadform.html', return render(request, 'scanuploadform.html',
{'form': form, 'wallet': wallet, **context, 'files': files, 'dirs': dirs, 'filesaved': filesaved, 'actual_saved': actual_saved}) {'form': form, 'wallet': wallet, **context, 'files': files, 'dirs': dirs, 'filesaved': filesaved, 'actual_saved': actual_saved})
@login_required_if_public
def photoupload(request, folder=None):
'''Upload photo image files into /expofiles/photos/<year>/<photographer>/
This does NOT use a Django model linked to a Django form. Just a simple Django form.
You will find the Django documentation on forms very confusing, This is simpler.
'''
year = settings.PHOTOS_YEAR
filesaved = False
actual_saved = []
context = {'year': year, 'placeholder': "AnathemaDevice"}
yearpath = Path(settings.PHOTOS_ROOT, year)
if folder == str(year) or folder == str(year) +"/":
folder = None
if folder is None:
folder = "" # improve this later
dirpath = Path(settings.PHOTOS_ROOT, year)
urlfile = f'/expofiles/photos/{year}'
urldir = f'/photoupload/{year}'
else: # it will contain the year as well as the photographer
dirpath = Path(settings.PHOTOS_ROOT, folder)
if dirpath.is_dir():
urlfile = f'/expofiles/photos/{folder}'
urldir = Path('/photoupload') / folder
else:
folder = "" # improve this later
dirpath = Path(settings.PHOTOS_ROOT, year)
urlfile = f'/expofiles/photos/{year}'
urldir = f'/photoupload/{year}'
form = FilesForm()
formd = TextForm()
if request.method == 'POST':
if "photographer" in request.POST:
formd = TextForm(request.POST)
if formd.is_valid():
newphotographer = request.POST["photographer"]
(yearpath / newphotographer).mkdir(exist_ok=True)
else:
form = FilesForm(request.POST,request.FILES)
if form.is_valid():
f = request.FILES["uploadfiles"]
multiple = request.FILES.getlist('uploadfiles')
fs = FileSystemStorage(dirpath)
actual_saved = []
if multiple:
for f in multiple:
actual_saved.append( fs.save(f.name, content=f) )
filesaved = True
files = []
dirs = []
try:
for f in dirpath.iterdir():
if f.is_dir():
dirs.append(f.name)
if f.is_file():
files.append(f.name)
except FileNotFoundError:
files.append('(no folder yet - would be created)')
if len(files) >0 :
files = sorted(files)
if dirs:
dirs = sorted(dirs)
return render(request, 'photouploadform.html',
{'form': form, **context, 'urlfile': urlfile, 'urldir': urldir,'folder': folder, 'files': files, 'dirs': dirs, 'filesaved': filesaved, 'actual_saved': actual_saved})
@login_required_if_public @login_required_if_public
def dwgupload(request, folder=None, gitdisable='no'): def dwgupload(request, folder=None, gitdisable='no'):
'''Upload DRAWING files (tunnel or therion) into the upload folder in :drawings '''Upload DRAWING files (tunnel or therion) into the upload folder in :drawings

View File

@ -427,7 +427,7 @@ div#difflistajax
background-color: #dfffdf; background-color: #dfffdf;
border: thin green solid; border: thin green solid;
} }
/* Using in DrawingsUpload and ScanUpload*/
.fancybutton { .fancybutton {
color: #ffffff; color: #ffffff;
font: 18px Georgia, "Times New Roman", Times, serif; font: 18px Georgia, "Times New Roman", Times, serif;
@ -479,6 +479,58 @@ div#difflistajax
background: linear-gradient(bottom, #39b2e5, #6083BF); background: linear-gradient(bottom, #39b2e5, #6083BF);
} }
/* Used in PhotoUpload and GPSlog upload */
.fancybutton2 {
color: #ffffff;
font: 18px Georgia, "Times New Roman", Times, serif;
letter-spacing: 1px;
text-shadow: 0 1px 1px #000000;
#display: block;
/* margin: auto; */
font-size: 1.2em;
line-height: 1.25em;
padding: 7px 25px;
cursor: pointer;
position: static;
background: #9ff;
border: 1px solid #60AABF;
/* -moz-border-radius: 20px;
-webkit-border-radius: 20px;
-khtml-border-radius: 20px;*/
border-radius: 20px;
/*
-webkit-box-shadow: rgba(0, 0, 0, .25) 0 1px 1px;
-moz-box-shadow: rgba(0, 0, 0, .25) 0 1px 1px;
-o-box-shadow: rgba(0, 0, 0, .25) 0 1px 1px;*/
box-shadow: rgba(0, 0, 0, .25) 0 1px 1px;
background: #9ff;
background: -webkit-gradient(linear, left top, left bottom, from(#9ff), to(#6083fF));
background: -moz-linear-gradient(top, #9ff, #6083fF);
background: -o-linear-gradient(top, #9ff, #6083fF);
background: linear-gradient(top, #9ff, #6083fF);
}
.fancybutton2:hover,
.fancybutton2:focus {
cursor: pointer;
border-color: blue;
/* -webkit-box-shadow: aqua 0 0 8px;
-moz-box-shadow: aqua 0 0 8px;
-o-box-shadow: aqua 0 0 8px; */
box-shadow: aqua 0 0 8px;
}
.fancybutton2:active {
background: #39e5b2;
/* background: -webkit-gradient(linear, left bottom, left top, from(#39e5b2), to(#6083BF));
background: -moz-linear-gradient(bottom, #39e5b2, #6083BF);
background: -o-linear-gradient(bottom, #39e5b2, #6083BF); */
background: linear-gradient(bottom, #9ff, #6083BF);
}
/* For the Scan upload form - to be used with a phone */ /* For the Scan upload form - to be used with a phone */
::-webkit-file-upload-button { ::-webkit-file-upload-button {
padding: 0.3em; padding: 0.3em;

View File

@ -35,6 +35,7 @@
<a href="{% url "scanupload" '2021:01' %}">Upload Scans</a> | <a href="{% url "scanupload" '2021:01' %}">Upload Scans</a> |
<a href="{% url "dwgallfiles" %}">Drawings</a> | <a href="{% url "dwgallfiles" %}">Drawings</a> |
<a href="{% url "dwgupload" %}">Upload Drawings</a> | <a href="{% url "dwgupload" %}">Upload Drawings</a> |
<a href="{% url "photoupload" %}">Upload Photos</a> |
<a href="/1623/290/290.html">290 (FGH)</a> | <a href="/1623/290/290.html">290 (FGH)</a> |
<a href="/1626/359/359.html">359 (Homecoming)</a> | <a href="/1626/359/359.html">359 (Homecoming)</a> |
<br> <br>

View File

@ -0,0 +1,93 @@
{% extends "base.html" %}
{% block title %}Simple Fileupload (Photos){% endblock %}
{% block content %}
{% if folder %}
<h2>Upload photos into /photos/{{folder}}/</h2>
{% else %}
<h2>Upload photos into /photos/{{year}}/</h2>
{% endif %}
<div style = "max-width:35%; margin-left:20%; text-align: center; " >
<form method ='post' enctype ="multipart/form-data">
{% csrf_token %}
<br>
<input class="fancybutton2" type = "file" multiple="multiple"
name = "uploadfiles" id="uploadfiles" />
<br><br><br>
<button class="fancybutton2" style="padding: 0.5em 25px; margin-left: 155px" type = "submit" value = "Upload" >
Upload
</button>
</form>
</div>
<div style = "max-width:29%; margin-left:20%; text-align: left" >
{% if filesaved %}
<p>
<b>File(s) saved as <br>
{% for f in actual_saved %}
<em>{{f}}</em> <br>
{% endfor %}
</p>
{% endif %}
<strong style="font-size: 110%;">Files:</strong><br>
{% for f in files %}
<a href="{{urlfile|urlencode}}/{{f|urlencode}}">{{f}}</a><br />
{% empty %}
<p>&lt;No files here&gt;
{% endfor %}
<p><strong style="font-size: 110%;">Photographer Directories:</strong><br>
{% if folder %}
<a href="{{urldir}}/..">[up]</a><br />
{% endif %}
{% for f in dirs %}
<a href="{{urldir}}/{{f}}">/{{f}}/</a><br />
{% empty %}
<p>&lt;No subdirectories&gt;
{% endfor %}
</div>
{% if folder %}
<p>You can upload your photographs here.
<p>You cannot create sub-folders here.
<p>Note that only photo image files are accepted: all other types of files are refused.
{% else %}
<p>You can upload your photographs to any of these folders, and you can create a new folder in your name for your photos.
<p>Note that only photo image files are accepted: all other types of files are refused.
<hr>
<h2>Create new Photographer folder in /photos/{{year}}/</h2>
<div style = "max-width:35%; margin-left:20%; text-align: center; " >
<form method ='post'>
{% csrf_token %}
<br>
<input class="fancybutton2" style="padding: 0.5em 25px; margin-left: 125px"
label = "Photographer" name = "photographer" id="photographer"
pattern="[A-Za-z]+"
placeholder="{{placeholder}}" required />
<label
style="padding: 0.5em 25px; margin-left: 110px"
for="photographer">Photographer's name<br></label>
<label
style="padding: 0.5em 25px; margin-left: 110px"
for="photographer">(no spaces, only letters)</label>
<br><br><br>
<button class="fancybutton2" style="padding: 0.5em 25px; margin-left: 155px" type = "submit" value = "Create" >
Create folder
</button>
</form>
</div>
<p>
{% endif %}
<hr />
{% endblock %}

10
urls.py
View File

@ -10,7 +10,7 @@ from django.urls import path, reverse, resolve
from troggle.core.views import caves, statistics, survex from troggle.core.views import caves, statistics, survex
from troggle.core.views.scans import scansingle, singlewallet, allwallets from troggle.core.views.scans import scansingle, singlewallet, allwallets
from troggle.core.views.drawings import dwgallfiles, dwgfilesingle from troggle.core.views.drawings import dwgallfiles, dwgfilesingle
from troggle.core.views.uploads import dwgupload, scanupload from troggle.core.views.uploads import dwgupload, scanupload, photoupload
from troggle.core.views.other import troggle404, frontpage, todos, controlpanel, frontpage from troggle.core.views.other import troggle404, frontpage, todos, controlpanel, frontpage
from troggle.core.views.other import exportlogbook from troggle.core.views.other import exportlogbook
from troggle.core.views.caves import ent, cavepage from troggle.core.views.caves import ent, cavepage
@ -86,9 +86,11 @@ trogglepatterns = [
re_path(r'^admin/', admin.site.urls), # includes admin login & logout urls re_path(r'^admin/', admin.site.urls), # includes admin login & logout urls
# Uploads - uploading a file # Uploads - uploading a file
path('scanupload/<wallet>', scanupload, name='scanupload'), # wallet=2020#01, not a path path('scanupload/<wallet>', scanupload, name='scanupload'), # wallet=2020#01, not a path
path('dwgupload/<path:folder>', dwgupload, name='dwgupload'), path('photoupload/', photoupload, name='photoupload'), # restricted to current year
path('dwgupload/', dwgupload, name='dwgupload'), path('photoupload/<path:folder>', photoupload, name='photoupload'), # restricted to current year
path('dwgupload/<path:folder>', dwgupload, name='dwgupload'),
path('dwgupload/', dwgupload, name='dwgupload'),
path('dwguploadnogit/', dwgupload, {'gitdisable': 'yes'}, name='dwguploadnogit'), # used in testing path('dwguploadnogit/', dwgupload, {'gitdisable': 'yes'}, name='dwguploadnogit'), # used in testing
path('dwguploadnogit/<path:folder>', dwgupload, {'gitdisable': 'yes'}, name='dwguploadnogit'), # used in testing path('dwguploadnogit/<path:folder>', dwgupload, {'gitdisable': 'yes'}, name='dwguploadnogit'), # used in testing