From 3caa90f226cd811b9b8adb15a966ffa2e3095f61 Mon Sep 17 00:00:00 2001
From: ShreyasSridhar24 <102874119+ShreyasSridhar24@users.noreply.github.com>
Date: Thu, 11 Jul 2024 14:44:42 -0400
Subject: [PATCH 1/2] Take in pdf files, sanitize, serve
---
coldfront/config/base.py | 3 ++
coldfront/config/urls.py | 2 ++
coldfront/core/project/forms.py | 3 ++
coldfront/core/project/models.py | 11 +++++--
.../project/project_attribute_create.html | 32 ++++++++++++++++++-
coldfront/core/project/urls.py | 3 ++
coldfront/core/project/views.py | 14 ++++++--
coldfront/core/utils/validate.py | 17 ++++++++--
8 files changed, 77 insertions(+), 8 deletions(-)
diff --git a/coldfront/config/base.py b/coldfront/config/base.py
index d9f71d972..6688f328b 100644
--- a/coldfront/config/base.py
+++ b/coldfront/config/base.py
@@ -155,3 +155,6 @@
# Add system site static files
if os.path.isdir('/usr/share/coldfront/site/static'):
STATICFILES_DIRS.insert(0, '/usr/share/coldfront/site/static')
+
+MEDIA_URL = '/media/'
+MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
\ No newline at end of file
diff --git a/coldfront/config/urls.py b/coldfront/config/urls.py
index 353e3602e..249cf327e 100644
--- a/coldfront/config/urls.py
+++ b/coldfront/config/urls.py
@@ -5,6 +5,7 @@
from django.contrib import admin
from django.urls import include, path
from django.views.generic import TemplateView
+from django.conf.urls.static import static
import coldfront.core.portal.views as portal_views
@@ -36,3 +37,4 @@
if 'django_su.backends.SuBackend' in settings.AUTHENTICATION_BACKENDS:
urlpatterns.append(path('su/', include('django_su.urls')))
+urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
diff --git a/coldfront/core/project/forms.py b/coldfront/core/project/forms.py
index beeea24e9..28820843f 100644
--- a/coldfront/core/project/forms.py
+++ b/coldfront/core/project/forms.py
@@ -142,6 +142,9 @@ def __init__(self, *args, **kwargs):
super(ProjectAttributeAddForm, self).__init__(*args, **kwargs)
user =(kwargs.get('initial')).get('user')
self.fields['proj_attr_type'].queryset = self.fields['proj_attr_type'].queryset.order_by(Lower('name'))
+ self.fields['doc'].required = False
+ self.fields['value'].required = False
+
if not user.is_superuser:
self.fields['proj_attr_type'].queryset = self.fields['proj_attr_type'].queryset.filter(is_private=False)
diff --git a/coldfront/core/project/models.py b/coldfront/core/project/models.py
index 45f9470ac..84849fcb6 100644
--- a/coldfront/core/project/models.py
+++ b/coldfront/core/project/models.py
@@ -400,6 +400,9 @@ def __str__(self):
def __repr__(self) -> str:
return str(self)
+
+
+
class Meta:
ordering = ['name', ]
@@ -418,6 +421,7 @@ class ProjectAttribute(TimeStampedModel):
value = models.CharField(max_length=128)
history = HistoricalRecords()
+ doc = models.FileField(default=False, upload_to='documents/')
def save(self, *args, **kwargs):
""" Saves the project attribute. """
@@ -433,8 +437,9 @@ def clean(self):
self.proj_attr_type))
expected_value_type = self.proj_attr_type.attribute_type.name.strip()
-
- validator = AttributeValidator(self.value)
+ # if not self.doc:
+ validator = AttributeValidator(self.value, self.doc)
+
if expected_value_type == "Int":
validator.validate_int()
@@ -444,6 +449,8 @@ def clean(self):
validator.validate_yes_no()
elif expected_value_type == "Date":
validator.validate_date()
+ elif expected_value_type == "Upload":
+ validator.validate_doc()
def __str__(self):
return '%s' % (self.proj_attr_type.name)
diff --git a/coldfront/core/project/templates/project/project_attribute_create.html b/coldfront/core/project/templates/project/project_attribute_create.html
index 39c7beb43..846d3d1c5 100644
--- a/coldfront/core/project/templates/project/project_attribute_create.html
+++ b/coldfront/core/project/templates/project/project_attribute_create.html
@@ -12,11 +12,41 @@
{% block content %}
Adding project attribute to {{ project }}
-
+
+
{% endblock %}
\ No newline at end of file
diff --git a/coldfront/core/project/urls.py b/coldfront/core/project/urls.py
index 748b6495c..b5c273679 100644
--- a/coldfront/core/project/urls.py
+++ b/coldfront/core/project/urls.py
@@ -1,4 +1,6 @@
from django.urls import path
+from django.conf import settings
+from django.conf.urls.static import static
import coldfront.core.project.views as project_views
@@ -26,3 +28,4 @@
path('/project-attribute-update/', project_views.ProjectAttributeUpdateView.as_view(), name='project-attribute-update'),
]
+urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
diff --git a/coldfront/core/project/views.py b/coldfront/core/project/views.py
index a71dda349..92ea67959 100644
--- a/coldfront/core/project/views.py
+++ b/coldfront/core/project/views.py
@@ -1169,7 +1169,7 @@ class ProjectNoteCreateView(LoginRequiredMixin, UserPassesTestMixin, CreateView)
model = ProjectUserMessage
fields = '__all__'
template_name = 'project/project_note_create.html'
-
+ enctype = 'multipart/form-data'
def test_func(self):
""" UserPassesTestMixin Tests"""
@@ -1210,7 +1210,8 @@ class ProjectAttributeCreateView(LoginRequiredMixin, UserPassesTestMixin, Create
model = ProjectAttribute
form_class = ProjectAttributeAddForm
template_name = 'project/project_attribute_create.html'
-
+ enctype="multipart/form-data"
+ # print("kjenf")
def test_func(self):
""" UserPassesTestMixin Tests"""
project_obj = get_object_or_404(Project, pk=self.kwargs.get('pk'))
@@ -1233,7 +1234,6 @@ def get_initial(self):
initial['project'] = get_object_or_404(Project, pk=pk)
initial['user'] = self.request.user
return initial
-
def get_form(self, form_class=None):
"""Return an instance of the form to be used in this view."""
form = super().get_form(form_class)
@@ -1244,8 +1244,16 @@ def get_context_data(self, *args, **kwargs):
pk = self.kwargs.get('pk')
context = super().get_context_data(*args, **kwargs)
context['project'] = get_object_or_404(Project, pk=pk)
+ text_based_input_attributes = []
+ for m in ProjectAttribute.objects.all():
+ # print(m.doc)
+ if(m.proj_attr_type.attribute_type.name != "Upload"):
+ text_based_input_attributes.append(m.proj_attr_type.attribute_type.name)
+ context["text_based_input_attributes"] = text_based_input_attributes
+
return context
+
def get_success_url(self):
return reverse('project-detail', kwargs={'pk': self.object.project_id})
diff --git a/coldfront/core/utils/validate.py b/coldfront/core/utils/validate.py
index 5597a1408..c74dc9994 100644
--- a/coldfront/core/utils/validate.py
+++ b/coldfront/core/utils/validate.py
@@ -3,11 +3,13 @@
from django.core.validators import MinValueValidator
import formencode
from formencode import validators, Invalid
+import magic
class AttributeValidator:
- def __init__(self, value):
+ def __init__(self, value, doc):
self.value = value
+ self.doc = doc
def validate_int(self):
try:
@@ -38,4 +40,15 @@ def validate_date(self):
datetime.datetime.strptime(self.value.strip(), "%Y-%m-%d")
except:
raise ValidationError(
- f'Invalid Value {self.value}. Date must be in format YYYY-MM-DD and date must be today or later.')
\ No newline at end of file
+ f'Invalid Value {self.value}. Date must be in format YYYY-MM-DD and date must be today or later.')
+
+ def validate_doc(self):
+ # try:
+ if self.doc:
+ if self.doc.size > 10485760 :
+ raise ValidationError("This document exceeds size limits")
+ content_mime_type = magic.Magic(mime=True)
+ # file_type = content_mime_type.from_buffer(self.doc.read())
+ if content_mime_type.from_buffer(self.doc.read()) != "application/pdf":
+ raise ValidationError("Invalid file type")
+ self.doc.seek(0)
From 82230177ad3cb858838a691b77ae78b2bd689693 Mon Sep 17 00:00:00 2001
From: ShreyasSridhar24 <102874119+ShreyasSridhar24@users.noreply.github.com>
Date: Thu, 25 Jul 2024 11:26:54 -0400
Subject: [PATCH 2/2] Add support for allocations
---
coldfront/core/allocation/forms.py | 2 ++
coldfront/core/allocation/models.py | 16 +++++++++++++---
coldfront/core/allocation/urls.py | 4 +++-
coldfront/core/allocation/views.py | 7 ++++++-
4 files changed, 24 insertions(+), 5 deletions(-)
diff --git a/coldfront/core/allocation/forms.py b/coldfront/core/allocation/forms.py
index 970024477..71c2c599a 100644
--- a/coldfront/core/allocation/forms.py
+++ b/coldfront/core/allocation/forms.py
@@ -259,3 +259,5 @@ class Meta:
def __init__(self, *args, **kwargs):
super(AllocationAttributeCreateForm, self).__init__(*args, **kwargs)
self.fields['allocation_attribute_type'].queryset = self.fields['allocation_attribute_type'].queryset.order_by(Lower('name'))
+ self.fields['doc'].required = False
+ self.fields['value'].required = False
diff --git a/coldfront/core/allocation/models.py b/coldfront/core/allocation/models.py
index b89826b2c..1986eb677 100644
--- a/coldfront/core/allocation/models.py
+++ b/coldfront/core/allocation/models.py
@@ -12,7 +12,7 @@
from django.utils.module_loading import import_string
from model_utils.models import TimeStampedModel
from simple_history.models import HistoricalRecords
-
+import magic
from coldfront.core.project.models import Project, ProjectPermission
from coldfront.core.resource.models import Resource
from coldfront.core.utils.common import import_from_settings
@@ -412,6 +412,8 @@ class AllocationAttributeType(TimeStampedModel):
is_private = models.BooleanField(default=True)
is_changeable = models.BooleanField(default=False)
history = HistoricalRecords()
+
+
def __str__(self):
return '%s' % (self.name)
@@ -433,7 +435,7 @@ class AllocationAttribute(TimeStampedModel):
allocation = models.ForeignKey(Allocation, on_delete=models.CASCADE)
value = models.CharField(max_length=128)
history = HistoricalRecords()
-
+ doc = models.FileField(default=False, upload_to='documents/')
def save(self, *args, **kwargs):
""" Saves the allocation attribute. """
@@ -466,7 +468,15 @@ def clean(self):
except ValueError:
raise ValidationError(
'Invalid Value "%s" for "%s". Date must be in format YYYY-MM-DD' % (self.value, self.allocation_attribute_type.name))
-
+ elif expected_value_type == "Upload":
+ if self.doc:
+ if self.doc.size > 10485760 :
+ raise ValidationError("This document exceeds size limits")
+ content_mime_type = magic.Magic(mime=True)
+ # file_type = content_mime_type.from_buffer(self.doc.read())
+ if content_mime_type.from_buffer(self.doc.read()) != "application/pdf":
+ raise ValidationError("Invalid file type")
+ self.doc.seek(0)
def __str__(self):
return '%s' % (self.allocation_attribute_type.name)
diff --git a/coldfront/core/allocation/urls.py b/coldfront/core/allocation/urls.py
index 9d0f747be..3cc75982b 100644
--- a/coldfront/core/allocation/urls.py
+++ b/coldfront/core/allocation/urls.py
@@ -1,7 +1,8 @@
from django.urls import path
import coldfront.core.allocation.views as allocation_views
-
+from django.conf import settings
+from django.conf.urls.static import static
urlpatterns = [
path('', allocation_views.AllocationListView.as_view(), name='allocation-list'),
path('project//create',
@@ -45,3 +46,4 @@
path('allocation-account-list/', allocation_views.AllocationAccountListView.as_view(),
name='allocation-account-list'),
]
+urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
\ No newline at end of file
diff --git a/coldfront/core/allocation/views.py b/coldfront/core/allocation/views.py
index 216c3531c..ffb50b32a 100644
--- a/coldfront/core/allocation/views.py
+++ b/coldfront/core/allocation/views.py
@@ -775,7 +775,7 @@ class AllocationAttributeCreateView(LoginRequiredMixin, UserPassesTestMixin, Cre
model = AllocationAttribute
form_class = AllocationAttributeCreateForm
template_name = 'allocation/allocation_allocationattribute_create.html'
-
+ enctype="multipart/form-data"
def test_func(self):
""" UserPassesTestMixin Tests"""
@@ -789,6 +789,11 @@ def get_context_data(self, **kwargs):
pk = self.kwargs.get('pk')
allocation_obj = get_object_or_404(Allocation, pk=pk)
context['allocation'] = allocation_obj
+ text_based_input_attributes = []
+ for m in AllocationAttribute.objects.all():
+ if(m.proj_attr_type.attribute_type.name != "Upload"):
+ text_based_input_attributes.append(m.proj_attr_type.attribute_type.name)
+ context["text_based_input_attributes"] = text_based_input_attributes
return context
def get_initial(self):