Skip to content

Commit

Permalink
Merge pull request #141 from DagmawitGT/17.0-develop
Browse files Browse the repository at this point in the history
Registry - Profile Photo
  • Loading branch information
shibu-narayanan authored Aug 16, 2024
2 parents 2cad8b1 + 44f9ede commit 32ad938
Show file tree
Hide file tree
Showing 13 changed files with 731 additions and 1 deletion.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ Available addons
addon | version | maintainers | summary
--- | --- | --- | ---
[g2p_bank](g2p_bank/) | 17.0.1.0.0 | | G2P Registry: Bank Details
[g2p_bank_rest_api](g2p_bank_rest_api/) | 17.0.1.0.0 | | G2P Registry: Bank Details Rest API
[g2p_bank_rest_api](g2p_bank_rest_api/) | 17.0.1.0.0 | | G2P Registry: Bank Details Rest AP
[g2p_profile_image](g2p_profile_image/) | 17.0.1.0.0 | | OpenG2P Profile Image
[g2p_enumerator](g2p_enumerator/) | 17.0.1.0.0 | | G2P Enumerator
[g2p_registry_addl_info](g2p_registry_addl_info/) | 17.0.1.0.0 | | G2P Registry: Additional Info
[g2p_registry_base](g2p_registry_base/) | 17.0.1.0.0 | | G2P Registry: Base
Expand Down
52 changes: 52 additions & 0 deletions g2p_profile_image/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
=====================
OpenG2P Profile Image
=====================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:7bdf68b1fba30669d416a0928115edd95a9cfb1ee7091d4b593a0506ac530e20
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/github-OpenG2P%2Fopeng2p--registry-lightgray.png?logo=github
:target: https://github.com/OpenG2P/openg2p-registry/tree/17.0-develop/g2p_profile_image
:alt: OpenG2P/openg2p-registry

|badge1| |badge2|

G2P Profile Image

**Table of contents**

.. contents::
:local:

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OpenG2P/openg2p-registry/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OpenG2P/openg2p-registry/issues/new?body=module:%20g2p_profile_image%0Aversion:%2017.0-develop%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
~~~~~~~

* OpenG2P

Maintainers
~~~~~~~~~~~

This module is part of the `OpenG2P/openg2p-registry <https://github.com/OpenG2P/openg2p-registry/tree/17.0-develop/g2p_profile_image>`_ project on GitHub.

You are welcome to contribute.
1 change: 1 addition & 0 deletions g2p_profile_image/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
24 changes: 24 additions & 0 deletions g2p_profile_image/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Part of OpenG2P Social Registry. See LICENSE file for full copyright and licensing details.
{
"name": "OpenG2P Profile Image",
"category": "G2P",
"version": "17.0.1.0.0",
"sequence": 1,
"author": "OpenG2P",
"website": "https://openg2p.org",
"license": "Other OSI approved licence",
"depends": [
"g2p_registry_base",
"g2p_registry_documents",
],
"external_dependencies": {
"python": ["pillow==9.0.1"],
},
"data": [],
"assets": {},
"demo": [],
"images": [],
"application": True,
"installable": True,
"auto_install": False,
}
1 change: 1 addition & 0 deletions g2p_profile_image/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import profile_image, document_file
42 changes: 42 additions & 0 deletions g2p_profile_image/models/document_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import logging

from odoo import _, models
from odoo.exceptions import UserError

_logger = logging.getLogger(__name__)


class G2PDocumentFile(models.Model):
_inherit = "storage.file"

def create(self, vals):
_logger.info("Creating storage file with values: %s", vals)
if isinstance(vals, dict):
self._check_profile_tag(vals)
elif isinstance(vals, list):
for i in range(len(vals)):
vals_obj = vals[i]
self._check_profile_tag(vals_obj)

return super().create(vals)

def _check_profile_tag(self, vals_obj):
_logger.info("Checking profile tag for values: %s", vals_obj)
profile_tag = self.env["g2p.document.tag"].get_tag_by_name("Profile Image")
profile_tag_id = profile_tag.id
tags_ids = vals_obj.get("tags_ids", [])
has_profile_tag = any(tag[1] == profile_tag_id for tag in tags_ids)

if has_profile_tag:
existing_file = self.search(
[("registrant_id", "=", vals_obj.get("registrant_id")), ("tags_ids", "in", [profile_tag.id])],
limit=1,
)

if existing_file:
raise UserError(
_(
"Profile image already exists. To change your profile picture,"
"hover over your current image and click the edit button."
)
)
106 changes: 106 additions & 0 deletions g2p_profile_image/models/profile_image.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import base64
import io

from PIL import Image

from odoo import api, models
from odoo.exceptions import ValidationError


class G2PImageStorage(models.Model):
_inherit = "res.partner"

def _process_profile_image(self, values):
profile_tag = self.env["g2p.document.tag"].get_tag_by_name("Profile Image")

if not profile_tag:
profile_tag = self.env["g2p.document.tag"].create({"name": "Profile Image"})

storage_file = self.env["storage.file"].search(
[("registrant_id", "=", self.id), ("tags_ids", "in", [profile_tag.id])], limit=1
)

backend_id = self.env["storage.backend"].search([("name", "=", "Default S3 Document Store")], limit=1)

if values and values.get("image_1920") is not False:
img = values.get("image_1920", False)
if img:
binary_image = base64.b64decode(img)
image_size = len(binary_image)

if image_size > 1 * 1024 * 1024: # Image is > 1 MB
try:
# Scale down the image to be less than 1 MB
scaled_down_image = self._resize_image(binary_image)
values["image_1920"] = scaled_down_image

except Exception as e:
raise ValidationError(f"Error: {e}") from e

storage_file_vals = {
"data": img,
"file_size": image_size,
"name": "Profile Image",
"tags_ids": [(4, profile_tag.id)],
"registrant_id": self.id,
"backend_id": backend_id.id,
}

if storage_file:
storage_file.unlink()
self.env["storage.file"].create(storage_file_vals)
else:
if storage_file:
storage_file.unlink()
values["image_1920"] = img

else:
if values and storage_file:
storage_file.unlink()

def write(self, values):
self._process_profile_image(values)
result = super().write(values)
return result

@api.model
def create(self, values):
new_record = super().create(values)
new_record._process_profile_image(values)
return new_record

def _resize_image(self, binary_image):
image_stream = io.BytesIO(binary_image)
image = Image.open(image_stream)
image_format = image.format
max_size = 1 * 1024 * 1024 # 1 MB

# resizing with thumbnail
image.thumbnail((1024, 1024), Image.ANTIALIAS)

buffered = io.BytesIO()
image.save(buffered, format=image_format, optimize=True, quality=85)

# size of the buffered image
if buffered.tell() <= max_size:
return base64.b64encode(buffered.getvalue())

for quality in range(80, 20, -10):
buffered = io.BytesIO()
image.save(buffered, format=image_format, optimize=True, quality=quality)
if buffered.tell() <= max_size:
return base64.b64encode(buffered.getvalue())

# If quality reduction is not enough, reduce dimensions further
new_width = image.size[0]
new_height = image.size[1]
while buffered.tell() > max_size and (new_width > 100 and new_height > 100):
new_width = int(new_width * 0.9)
new_height = int(new_height * 0.9)
image = image.resize((new_width, new_height), Image.ANTIALIAS)
buffered = io.BytesIO()
image.save(buffered, format=image_format, optimize=True, quality=85)
if buffered.tell() <= max_size:
break

return base64.b64encode(buffered.getvalue())
3 changes: 3 additions & 0 deletions g2p_profile_image/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"
1 change: 1 addition & 0 deletions g2p_profile_image/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
G2P Profile Image
Loading

0 comments on commit 32ad938

Please sign in to comment.