Skip to content

Commit

Permalink
[IMP] hr_attendance_location_ip_check: adopt hook pattern when check …
Browse files Browse the repository at this point in the history
…attendance ip address for better compatibility and scalability
  • Loading branch information
kongkea-aditi committed Dec 19, 2024
1 parent 2a5abcd commit 24b7751
Show file tree
Hide file tree
Showing 3 changed files with 198 additions and 146 deletions.
6 changes: 4 additions & 2 deletions hr_attendance_location_ip_check/models/hr_attendance.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ def create(self, vals_list):
for vals in vals_list:
employee = self.env["hr.employee"].browse(vals.get("employee_id"))
if employee.work_location_id:
self._validate_location_ip(employee)
action = "check_in"
employee._attendance_action_check(action)

return super().create(vals_list)

Expand All @@ -24,7 +25,8 @@ def write(self, vals):
for attendance in self:
if attendance.employee_id.work_location_id:
action = "check_out" if "check_out" in vals else "check_in"
self._validate_location_ip(attendance.employee_id, action)
# Use the hook method
attendance.employee_id._attendance_action_check(action)
return super().write(vals)

def _validate_location_ip(self, employee, action="check_in"):
Expand Down
88 changes: 46 additions & 42 deletions hr_attendance_location_ip_check/models/hr_employee.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,42 +19,22 @@ class HrEmployee(models.Model):
groups="hr.group_hr_user",
)

@api.model
def fields_get(self, allfields=None, attributes=None):
res = super().fields_get(allfields, attributes)
if not self.env.user.has_group("hr.group_hr_manager"):
if "bypass_ip_check" in res:
res["bypass_ip_check"]["readonly"] = True
return res

def write(self, vals):
if "bypass_ip_check" in vals and not self.env.user.has_group(
"hr.group_hr_manager"
):
raise AccessError(
_("Only HR Managers can modify the IP check bypass setting.")
)
return super().write(vals)

def attendance_manual(self, next_action, entered_pin=None):
"""Validate IP before processing manual attendance."""
def _attendance_action_check(self, action_type):
"""Hook method for attendance IP validation.
Called from hr.attendance during create/write operations.
Args:
action_type: String indicating 'check_in' or 'check_out'
Returns:
True if validation passes
Raises:
ValidationError if IP check fails
"""
self.ensure_one()
action_type = (
"check_out" if self.attendance_state == "checked_in" else "check_in"
)
self._validate_ip_address(action_type)
return super().attendance_manual(next_action, entered_pin)

def _get_ip_check_enabled(self):
"""Get global IP check setting."""
return const_eval(
self.env["ir.config_parameter"]
.sudo()
.get_param("hr_attendance.ip_check_enabled", "False")
)
if not self._is_ip_check_required():
return True

def _validate_ip_address(self, action_type):
"""Validate current IP for attendance actions."""
remote_ip = self._get_remote_ip()
if not remote_ip:
raise ValidationError(
Expand All @@ -67,14 +47,22 @@ def _validate_ip_address(self, action_type):
_("IP %(ip)s not allowed for %(action)s")
% {"ip": remote_ip, "action": action_type}
)
return True

def _get_ip_check_enabled(self):
"""Get global IP check setting."""
return const_eval(
self.env["ir.config_parameter"]
.sudo()
.get_param("hr_attendance.ip_check_enabled", "False")
)

def _is_ip_check_required(self):
"""Determine if IP check is required for this employee"""
"""Determine if IP check is required for this employee."""
self.ensure_one()

# Check if global IP check is enabled
global_check = self._get_ip_check_enabled()
if not global_check:
if not self._get_ip_check_enabled():
return False

# Employee bypass takes precedence
Expand All @@ -89,12 +77,9 @@ def _is_ip_check_required(self):
return self.work_location_id.check_ip

def _is_ip_allowed(self, ip_addr):
"""Check if IP is allowed for this employee"""
if not self._is_ip_check_required():
return True

"""Check if IP is allowed for this employee."""
if not ip_addr:
raise ValidationError(_("No IP address detected"))
return False

Check warning on line 82 in hr_attendance_location_ip_check/models/hr_employee.py

View check run for this annotation

Codecov / codecov/patch

hr_attendance_location_ip_check/models/hr_employee.py#L82

Added line #L82 was not covered by tests

try:
ip = ipaddress.ip_address(ip_addr)
Expand Down Expand Up @@ -135,4 +120,23 @@ def _get_remote_ip(self):
return request.httprequest.remote_addr if request else None
except Exception as e:
_logger.error("Error getting IP: %s", str(e))
raise ValidationError(_("Unable to determine IP address")) from e
return None

Check warning on line 123 in hr_attendance_location_ip_check/models/hr_employee.py

View check run for this annotation

Codecov / codecov/patch

hr_attendance_location_ip_check/models/hr_employee.py#L119-L123

Added lines #L119 - L123 were not covered by tests

@api.model
def fields_get(self, allfields=None, attributes=None):
"""Restrict bypass_ip_check field modification."""
res = super().fields_get(allfields, attributes)
if not self.env.user.has_group("hr.group_hr_manager"):
if "bypass_ip_check" in res:
res["bypass_ip_check"]["readonly"] = True

Check warning on line 131 in hr_attendance_location_ip_check/models/hr_employee.py

View check run for this annotation

Codecov / codecov/patch

hr_attendance_location_ip_check/models/hr_employee.py#L131

Added line #L131 was not covered by tests
return res

def write(self, vals):
"""Restrict bypass_ip_check modification to HR managers."""
if "bypass_ip_check" in vals and not self.env.user.has_group(
"hr.group_hr_manager"
):
raise AccessError(
_("Only HR Managers can modify the IP check bypass setting.")
)
return super().write(vals)
Loading

0 comments on commit 24b7751

Please sign in to comment.