commit 4d98f20cc292474b0d8c31b91a2658fd4ef5b0e7 Author: Suherdy Yacob Date: Mon Dec 29 13:49:37 2025 +0700 first commit diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..4027237 --- /dev/null +++ b/__init__.py @@ -0,0 +1 @@ +from . import wizard diff --git a/__manifest__.py b/__manifest__.py new file mode 100644 index 0000000..3e968bf --- /dev/null +++ b/__manifest__.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +{ + 'name': 'Survey Attachment Cleanup', + 'version': '18.0.1.0.0', + 'summary': 'Batch delete survey image attachments', + 'category': 'Tools', + 'author': 'Suherdy Yacob', + 'depends': ['base', 'survey', 'website'], + 'data': [ + 'security/ir.model.access.csv', + 'wizard/sh_survey_attachment_cleanup_wizard_views.xml', + ], + 'installable': True, + 'application': False, + 'license': 'LGPL-3', +} diff --git a/__pycache__/__init__.cpython-312.pyc b/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..5a92110 Binary files /dev/null and b/__pycache__/__init__.cpython-312.pyc differ diff --git a/security/ir.model.access.csv b/security/ir.model.access.csv new file mode 100644 index 0000000..7905d40 --- /dev/null +++ b/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_sh_survey_attachment_cleanup_wizard,sh.survey.attachment.cleanup.wizard,model_sh_survey_attachment_cleanup_wizard,base.group_user,1,1,1,1 diff --git a/wizard/__init__.py b/wizard/__init__.py new file mode 100644 index 0000000..833c6cc --- /dev/null +++ b/wizard/__init__.py @@ -0,0 +1 @@ +from . import sh_survey_attachment_cleanup_wizard diff --git a/wizard/__pycache__/__init__.cpython-312.pyc b/wizard/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..8f39ebc Binary files /dev/null and b/wizard/__pycache__/__init__.cpython-312.pyc differ diff --git a/wizard/__pycache__/sh_survey_attachment_cleanup_wizard.cpython-312.pyc b/wizard/__pycache__/sh_survey_attachment_cleanup_wizard.cpython-312.pyc new file mode 100644 index 0000000..a1c9351 Binary files /dev/null and b/wizard/__pycache__/sh_survey_attachment_cleanup_wizard.cpython-312.pyc differ diff --git a/wizard/sh_survey_attachment_cleanup_wizard.py b/wizard/sh_survey_attachment_cleanup_wizard.py new file mode 100644 index 0000000..8c038ad --- /dev/null +++ b/wizard/sh_survey_attachment_cleanup_wizard.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- +from odoo import api, fields, models + +class SurveyAttachmentCleanupWizard(models.TransientModel): + _name = 'sh.survey.attachment.cleanup.wizard' + _description = 'Survey Attachment Cleanup Wizard' + + website_id = fields.Many2one('website', string="Website") + limit = fields.Integer(string="Batch Limit", default=0, help="Limit number of deletions per batch (0 for no limit)") + attachment_count = fields.Integer(string="Attachments Found", compute='_compute_attachment_count') + + @api.depends('website_id') + def _compute_attachment_count(self): + for record in self: + domain = [ + ('answer_type', '=', 'upload_file'), + ] + + # Find all relevant lines first + lines = self.env['survey.user_input.line'].search(domain) + + total_count = 0 + # Iterate to count attachments + # NOTE: this might be slow for huge datasets, but accurate given the m2m structure + # To optimize, we could do SQL, but ORM is safer for now given < 15k records + + # We can't easily search ir.attachment directly because the relationship is via m2m table + # `survey_user_input_line_rel` (or similar, depending on define). + # Actually, `value_file_data_ids` is Many2many('ir.attachment') + + # Let's collect IDs first (limit to reasonable number if performance issue?) + # But count needs to be accurate-ish. + + # Filter attachments + # We search ir.attachment directly to find ALL matching files, including orphans. + # Criteria: Mimetype JPEG, Website Matches, No Res Model (typical for M2M/Orphans) + + domain = [ + ('mimetype', '=', 'image/jpeg'), + ('res_model', '=', False), + ('res_field', '=', False), + ] + + if record.website_id: + domain.append(('website_id', '=', record.website_id.id)) + + # Count directly + count = self.env['ir.attachment'].search_count(domain) + record.attachment_count = count + + def action_delete_attachments(self): + self.ensure_one() + + domain = [ + ('mimetype', '=', 'image/jpeg'), + ('res_model', '=', False), + ('res_field', '=', False), + ] + + if self.website_id: + domain.append(('website_id', '=', self.website_id.id)) + + # Search with limit if needed + limit = self.limit if self.limit > 0 else None + attachments_to_delete = self.env['ir.attachment'].search(domain, limit=limit) + + return attachments_to_delete.unlink() + diff --git a/wizard/sh_survey_attachment_cleanup_wizard_views.xml b/wizard/sh_survey_attachment_cleanup_wizard_views.xml new file mode 100644 index 0000000..c3c57c9 --- /dev/null +++ b/wizard/sh_survey_attachment_cleanup_wizard_views.xml @@ -0,0 +1,34 @@ + + + + sh.survey.attachment.cleanup.wizard.form + sh.survey.attachment.cleanup.wizard + +
+ + + + + +
+
+
+
+
+ + + Survey Attachment Cleanup + sh.survey.attachment.cleanup.wizard + form + new + + + + +