Saving and deletion of images

conforming to GDPR (General Data Protection Regulation) / DSGVO (Datenschutz-Grundverordnung)

General info

All image uploads in the platform, delete previous uploads. E.g when a user uploads a new profile picture, their past picture gets deleted.
Same for projects, organisations and the modules, the new image will replace the old one.
Images associated to users and organisations gets deleted when they are deleted. Images uploaded by users for projects and modules are not deleted when a user is deleted, except when the project or the modules are deleted.

API

The code implementation of the image replacement function is part of Adhocracy4.
More specifically it happens in the files images/service.py and images/signals.py.
Inside service.py the function delete_images gets a list of image fields as a function attribute and deletes both the image and the thumbnail of each image field from their respective storage. The delete_images function is called from the signals.py file, which defines what object actions (create, save, update, delete an object) should trigger signals.
The signal post_save is triggered when an object (user, project, idea, etc) saves a new image, then the old ones, if any, are deleted (original upload and generated thumbnail) and the new ones are added as a list attribute.
E.g
project.image and project.tile_image are added as a list --> project._a4images_image_fields_current_images which returns a list of the image paths
The signal post_init, which is called every time an object is created, also sets the above attribute for the list of images associated to the object. Finally, the signal post_delete deletes all the images asscociated with the object when the object is deleted.

Users

user's image is refered to as avatar and it is saved under:

       "media/users/images"

user avatar gets deleted when their account is deleted via the user dashboard in the browser, which calls the endpoint:

accounts.views.AccountDeletionView.form_valid()

account_deletion  # the namespace defined in the accounts.urls.py

Project

Image storage for projects is categorised by date, and a project's two images are saved under:

       "media/projects/backgrounds/YYYY/MM/DD"  # decorative background image
       "media/projects/tiles/YYYY/MM/DD"       # project's tile image

project images are deleted when its organisation is deleted, and when the project is deleted via the user dashboard in the browser, which calls the endpoint:

projects.views.ProjectDeleteView
project-delete  # the namespace defined in projects.urls.py

Organisation

organisation's two images are saved under:

"organisations/logos"
"organisations/backgrounds"  # header image

organisation images are deleted when organisation is deleted via django-admin (also this is how an organisation is created).
When an organisation is deleted, all its related projects with their modules get deleted too.

Modules

Idea

Image storage for ideas is categorised by date, and an idea's image is saved under:

       "media/ideas/images/YYYY/MM/DD"

idea image gets deleted when an idea is deleted via its idea detail page in the browser, which calls the endpoint:


ideas.views.IdeaDeleteView  # inherits from AbstractIdeaDeleteView

the URI is defined as:

idea-delete  # defined in the ideas.urls.py

Budgeting, MapIdea, Topicrio

for those modules, images are deleted when the module is deleted either via the module page or the user dashboard. Their deletion inherits from the AbstractIdeaDeleteView and their images are also uploaded to:

       "media/ideas/images/YYYY/MM/DD"

Budgeting

Module is defined as Proposal and inherits from AbstractMapIdea, thus upload path is defined in the Parent class. It gets deleted from the budget page in the browser and calls the endpoint:

budgeting.views.ProposalDeleteView
proposal-delete  # the namespace defined in the budgeting.urls.py

MapIdea

Module inherits from AbstractIdea, thus upload path is defined in the Parent class. It gets deleted from the mapidea page in the browser and calls the endpoint:

mapideas.views.MapIdeaDeleteView
mapidea-delete  # the namespace defined in the mapideas.urls.py

Topicrio

Module inherits from adhocracy4 Item, thus upload path is defined in the child class and points to media/ideas/images. It gets deleted from the user dashboard and thus it also inherits from adhocracy4.DashboardComponentFormSignalMixin.
It calls the endpoint:

topicrio.views.TopicDeleteView
topic-detail  # the namespace defined in the topicrio.urls.py

Interactive Event

Image is saved under:

        "media/interactiveevents/images"

Image gets deleted when module is deleted from the user dashboard.

OfflineEvent

Module inherits from adhocracy4 UserGeneratedContentModel and has no image property. Images can be uploaded via CKEditor5.

Debate

Module is defined as Subject class and inherits from adhocracy4 Item and has no image property.

Document

Module is defined as Chapter class and inherits from adhocracy4 Item. It has a one to many relation with Paragraph class, which inherits from adhocracy4 TimeStampedModel. Paragraph can have images uploaded from CKEditor5.

Poll

Module inherits from adhocracy4 Item and has no image upload.

Map

Module inherits from adhocracy4 map fields and has no image upload property.