Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: create and implement attachment filename generator #725

Closed
wants to merge 57 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
e6798c8
feat: Import code from old branch to avoid merge
miggol Sep 17, 2024
db4e2e0
wip: Working on attachments in new branch
miggol Sep 23, 2024
6edcf59
Merge remote-tracking branch 'origin/major/4' into feature/attachments-4
miggol Sep 23, 2024
0662e3d
fix: Mishmash of migrations
miggol Sep 23, 2024
83c899a
wip: Various fixes for attachments
miggol Sep 23, 2024
8bd9e1e
feat: Attachment renderable templates & updates
miggol Sep 24, 2024
e87b9ba
feat: Change var name and minor changes
miggol Oct 1, 2024
5232642
feat: Verbose name for Attachment.upload
miggol Oct 1, 2024
1833621
feat: Attachment views
miggol Oct 1, 2024
c1039b2
feat: Attachment form template
miggol Oct 1, 2024
4767f4c
wip: Minor changes
miggol Oct 1, 2024
2e9474e
feat: Add author field to Attachment
miggol Oct 1, 2024
c88c247
feat: Classmethod to initialize kind from an attachment
miggol Oct 1, 2024
d58ff27
feat: Provide manager object to children
miggol Oct 2, 2024
3454a92
feat: Download view for attachments
miggol Oct 2, 2024
f04a8dc
feat: Break out BaseAttachFormView to make attachment edit view
miggol Oct 2, 2024
cc6c496
fix: Move classes around to prevent circular imports
miggol Oct 7, 2024
7254db5
wip: Remove attachments manager for now
miggol Oct 7, 2024
e74ed5d
Merge remote-tracking branch 'origin/major/4' into feature/attachments-4
miggol Oct 7, 2024
66c8f79
feat: Initialize stepper outside of context-getting
miggol Oct 7, 2024
dcbe8b4
wip: Start managing attachments by Checkers
miggol Oct 7, 2024
be1de99
feat: Make sure slots know what they're attaching to
miggol Oct 7, 2024
aa0176b
fix: Minor fixes and comment updates
miggol Oct 7, 2024
987d916
cleanup: Remove old code and simplify object getting
miggol Oct 7, 2024
97db730
feat: Just fill in study slots by hand for now
miggol Oct 7, 2024
c8198d8
feat: Detach functionality for Attachments
miggol Oct 9, 2024
d2f4fdf
feat: Get Attachment subclasses without kind
miggol Oct 11, 2024
9c64aa4
feat: Make slots less dependent on kinds
miggol Oct 11, 2024
9131b70
feat: Detach view and links, editing flag for AttachFormView
miggol Oct 11, 2024
2682a7c
feat: Extra/optional attachments with DMP example
miggol Oct 11, 2024
54c71a6
feat: New desiredness flags
miggol Oct 11, 2024
4212ced
feat: New add_slot method
miggol Oct 11, 2024
3141555
feat: Template enhancements and cleanup
miggol Oct 11, 2024
d82222c
style: Black
miggol Oct 14, 2024
19ca5e1
style: djlint
miggol Oct 14, 2024
ec17850
add cdh_files/ to .gitignore
EdoStorm96 Oct 22, 2024
3b62436
Merge branch 'major/4' into feature/attachments-4
EdoStorm96 Oct 22, 2024
563154b
fix: create and implement attachment filename generator
EdoStorm96 Oct 23, 2024
3f76485
Merge branch 'major/4' into feature/attachment_filename_generator
EdoStorm96 Nov 25, 2024
f489256
feat: proper implementation of filename generator
EdoStorm96 Nov 25, 2024
a8edd10
fix: bug in Study.research_settings_contains_schools
EdoStorm96 Nov 25, 2024
f11758f
Merge branch 'major/4' into feature/attachment_filename_generator
miggol Dec 18, 2024
24b9194
Merge remote-tracking branch 'origin/major/4' into feature/attachment…
miggol Jan 6, 2025
dd68a5f
fix: Remove FnGen from model
miggol Jan 6, 2025
36b8d72
feat: Auto retrieve Kind from attachment if none provided
miggol Jan 6, 2025
c58e0bb
feat: Classmethod to get a slot from a proposal
miggol Jan 6, 2025
b76cdb4
wip: Get filename from slot instead of kind
miggol Jan 6, 2025
e065c2e
feat: Rename and finalize generate_filename() function
miggol Jan 6, 2025
1b89cc9
feat: Point methods in right direction
miggol Jan 6, 2025
135b4a7
style
miggol Jan 6, 2025
c75fe13
feat: Custom fn_part for kinds
miggol Jan 6, 2025
352fc48
feat: Add order variable for Slots and FnGen
miggol Jan 7, 2025
4b87f00
fix: Turn get_fn_part into classmethod
miggol Jan 7, 2025
9858dfa
fix: Kind derivation for empty slot matching
miggol Jan 7, 2025
ab40cdb
fix: Delete anachronistic migration
miggol Jan 7, 2025
14e2783
feat: Functions to enumerate slots
miggol Jan 7, 2025
72b751f
feat: Template changes to display normalized filename after <br />
miggol Jan 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions attachments/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from django.urls import reverse
from main.utils import renderable


from cdh.files.db import FileField as CDHFileField

# Create your models here.
Expand Down
5 changes: 2 additions & 3 deletions attachments/templates/attachments/attachment_model.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@

<a href="{% url "proposals:download_attachment_original" proposal_pk=proposal.pk attachment_pk=attachment.pk %}">
{{ attachment.upload.original_filename }}</a>
{% if include_normalized %}
<span class="ms-2o"> (<a href="{% url "proposals:download_attachment" proposal_pk=proposal.pk attachment_pk=attachment.pk %}">{% trans "FETC-bestandsnaam" %}</a>)</span>
{% endif %}
{% if normalized_filename %}
<span class="ms-2o"><br /><a href="{% url "proposals:download_attachment" proposal_pk=proposal.pk attachment_pk=attachment.pk %}">{{ normalized_filename }}</a></span>{% endif %}
116 changes: 115 additions & 1 deletion attachments/utils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import mimetypes
from collections import Counter

from django.template.loader import get_template
from django.utils.translation import gettext as _
from django.urls import reverse
Expand Down Expand Up @@ -25,6 +28,14 @@ class AttachmentKind:
attached_field = "attachments"
desiredness = desiredness.OPTIONAL

@classmethod
def get_fn_part(cls):
if hasattr(cls, "fn_part"):
return cls.fn_part
# Capitalize DB name
parts = cls.db_name.split("_")
return "_".join([part.capitalize() for part in parts])


class AttachmentSlot(renderable):

Expand All @@ -37,15 +48,32 @@ def __init__(
kind=None,
force_desiredness=None,
optionality_group=None,
order=None,
):
self.attachment = attachment
self.attached_object = attached_object
self.kind = kind
self.order = order

if attachment and not kind:
# If an attachment was provided but no kind,
# attempt to get the kind from the attachment
self.kind = self.get_kind_from_attachment()
else:
self.kind = kind

self.force_desiredness = force_desiredness
self.optionality_group = optionality_group
if self.optionality_group:
self.optionality_group.members.append(self)

@classmethod
def from_proposal(attachment, proposal):
attached_object = attachment.get_owner_for_proposal(proposal)
return AttachmentSlot(
attached_object,
attachment=attachment,
)

def match(self, exclude=[]):
"""
Tries to find a matching attachment for this slot. If it finds one,
Expand All @@ -68,6 +96,16 @@ def match_and_set(self, exclude):
return self.attachment
return False

def get_kind_from_attachment(
self,
):
return get_kind_from_str(self.attachment.kind)

def get_fetc_filename(
self,
):
return generate_filename(self)

@property
def classes(self):
if self.required:
Expand Down Expand Up @@ -281,6 +319,82 @@ def merge_groups(slots):
return out


def generate_filename(slot):

proposal = slot.get_proposal()
chamber = proposal.reviewing_committee.name
lastname = proposal.created_by.last_name
refnum = proposal.reference_number
original_fn = slot.attachment.upload.original_filename
kind = slot.kind.get_fn_part()
order = slot.order

extension = (
"." + original_fn.split(".")[-1][-7:]
) # At most 7 chars seems reasonable

trajectory = None
if not type(slot.attached_object) is Proposal:
trajectory = "T" + str(slot.attached_object.order)

fn_parts = [
"FETC",
chamber,
refnum,
lastname,
trajectory,
kind,
order,
]

# Translations will trip up join(), so we convert them here.
# This will also remove the trajectory if None.
fn_parts = [str(p) for p in fn_parts if p]

return "-".join(fn_parts) + extension

def enumerate_slots(slots):
"""
Provides an order attribute to all attachment slots whose kind
appears more than once in the provided list.
"""
# Create seperate slot lists per attached_object
per_ao = sort_into_dict(
slots, lambda x: x.attached_object,
).values()
# Assign orders to them separately
for ao_slots in per_ao:
assign_orders(ao_slots)

def sort_into_dict(iterable, key_func):
"""
Split iterable into separate lists in a dict whose keys
are the shared response to all its items' key_func(item).
"""
out_dict = {}
for item in iterable:
key = key_func(item)
if key not in out_dict:
out_dict[key] = [item]
else:
out_dict[key].append(item)
return out_dict

def assign_orders(slots):
# Count total kind occurrences
totals = Counter(
[slot.kind for slot in slots]
)
# Create counter to increment gradually
kind_counter = Counter()
# Loop through the slots
for slot in slots:
if totals[slot.kind] < 2:
# Skip slots with unique kinds
continue
kind_counter[slot.kind] += 1
slot.order = kind_counter[slot.kind]

def get_kind_from_str(db_name):
from attachments.kinds import ATTACHMENTS, OtherAttachment

Expand Down
1 change: 1 addition & 0 deletions proposals/utils/checkers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1093,6 +1093,7 @@ def make_stepper_item(self):
self.stepper,
)
return item
return [TranslationChecker]


class TranslationChecker(
Expand Down
14 changes: 12 additions & 2 deletions proposals/utils/stepper.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from interventions.forms import InterventionForm

from proposals.utils.validate_sessions_tasks import validate_sessions_tasks
from attachments.utils import AttachmentSlot
from attachments.utils import AttachmentSlot, enumerate_slots
from attachments.kinds import desiredness


Expand Down Expand Up @@ -82,7 +82,17 @@ def attachment_slots(
success = empty_slot.match_and_set(exclude=exclude)
if success:
extra_slots.append(empty_slot)
return self._attachment_slots + extra_slots
all_slots = self._attachment_slots + extra_slots
enumerate_slots(all_slots)
return all_slots

@property
def filled_slots(
self,
):
return [
slot for slot in self.attachment_slots if slot.attachment
]

def get_context_data(self):
context = super().get_context_data()
Expand Down
12 changes: 6 additions & 6 deletions proposals/views/attachment_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from reviews.mixins import HideStepperMixin
from django.utils.translation import gettext as _
from attachments.kinds import ATTACHMENTS, KIND_CHOICES
from attachments.utils import AttachmentKind, merge_groups
from attachments.utils import AttachmentKind, merge_groups, AttachmentSlot
from cdh.core import forms as cdh_forms
from django.utils.translation import gettext as _
from reviews.mixins import UsersOrGroupsAllowedMixin
Expand Down Expand Up @@ -369,14 +369,14 @@ def get_filename(self):
if self.original_filename:
return self.attachment.upload.original_filename
else:
return self.get_filename_from_kind()
return self.get_filename_from_slot()

def get_filename_from_kind(self):
self.kind = AttachmentKind.from_proposal(
self.proposal,
def get_filename_from_slot(self):
self.slot = AttachmentSlot.from_proposal(
self.attachment,
self.proposal,
)
return self.kind.name
return self.slot.get_fetc_filename()

def get_file_response(self):
attachment_file = self.attachment.upload.file
Expand Down
2 changes: 1 addition & 1 deletion reviews/templates/reviews/review_attachments.html
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ <h6>{{ slot.kind.name }}</h6>
</tr>
<tr>
<td>{% trans "Bestand" %}</td>
<td>{% include slot.attachment with proposal=proposal include_normalized=True %}</td>
<td>{% include slot.attachment with proposal=proposal normalized_filename=slot.get_fetc_filename %}</td>
</tr>
<tr>
<td>{% trans "Commentaar" %}</td>
Expand Down
Loading