i have odoo17 project and i have these files, check them, test them and fix them, ip Must be in the format A.B.C.D, For example: 73.9.149.180, we need to get users location from its api that we will get from request, heres my files check them and fix them, someone touched to my location and api logic so i need your help: 
ip_geolocation.py:
import requests
from typing import Optional, Dict
import asyncio
import logging

_logger = logging.getLogger(__name__)


def get_client_ip(self, request) -> str:
    if hasattr(request, 'httprequest'):
        return (
            request.httprequest.headers.get('X-Forwarded-For', '').split(',')[0].strip() or
            request.httprequest.headers.get('X-Real-IP') or
            request.httprequest.remote_addr
        )
    return None


def get_location_from_ip_sync(ip_address: str) -> Optional[Dict[str, str]]:
    url = 'https://api.api-ninjas.com/v1/iplookup?address={}'.format(ip_address)
    try:
        response = requests.get(url, headers={'X-Api-Key': '5AwewQhdD9'})
        _logger.critical("Response Status", response)
        data = response.json()
        _logger.critical("Response Data", data)
        if data.get("status") == "success":
            location = {
                "country": data.get("country"),
                "region": data.get("region"),
                "timezone": data.get("timezone"),
                "adress": data.get("address"),
            }
            return location
        else:
            return None
    except Exception as e:
        return None


async def get_location_from_ip(ip_address: str) -> Optional[Dict[str, str]]:
    loop = asyncio.get_event_loop()
    return await loop.run_in_executor(None, get_location_from_ip_sync, ip_address)

session_router: @router.get("/sessions", response_model=SessionResponse)
async def get_sessions(
    request: Request,
    env: Annotated[Environment, Depends(odoo_env)],
    partner: Annotated[Partner, Depends(get_partner_with_session)],
    current_session_id: str = Depends(get_partner_with_session_id)
):
    user_id = partner.id
    session_ids = redis_session_manager.redis.smembers(f"user_sessions:{user_id}")

    current_session_data = redis_session_manager.get_session(current_session_id)
    if not current_session_data:
        raise HTTPException(status_code=404, detail=_("Current session not found"))

    if not current_session_data.get('location'):
        client_ip = request.client.host
        location_data = get_location_from_ip_sync(client_ip)
        if location_data:
            location_string = f"{location_data.get('city', '')}, {location_data.get('country', '')}"
            current_session_data['location'] = location_string
            current_session_data['ip_address'] = client_ip
            current_session_data['location_data'] = location_data
            redis_session_manager.update_session(current_session_id, current_session_data)

    response = SessionResponse(
        current_session=SessionSchema(
            session_id=current_session_id,
            app_version=current_session_data.get('app_version'),
            device_name=current_session_data.get('device_name'),
            ip_address=current_session_data.get('ip_address'),
            location=current_session_data.get('location'),
            last_activity=current_session_data.get('last_activity'),
            is_ios=current_session_data.get('is_ios') or False,
            status=current_session_data.get('status', UserStatus.OFFLINE)
        ),
        other_sessions=[]
    )

    for session_id in session_ids:
        if session_id != current_session_id:
            session_data = redis_session_manager.get_session(session_id)
            if session_data:
                session_info = SessionSchema(
                    session_id=session_id,
                    app_version=session_data.get('app_version'),
                    device_name=current_session_data.get('device_name'),
                    ip_address=current_session_data.get('ip_address'),
                    location=current_session_data.get('location'),
                    last_activity=session_data.get('last_activity'),
                    is_ios=session_data.get('is_ios') or False,
                    status=session_data.get('status', UserStatus.OFFLINE)
                )
                response.other_sessions.append(session_info)

    return response

auth.py: from odoo import http
from odoo.http import request
from dotenv import load_dotenv
import os 
import json
import logging
from odoo.addons.fastapi_addon.utils.ip_geolocation import get_client_ip


_logger = logging.getLogger(__name__)

class CommetaApi(http.Controller):
    @http.route('/api/auth/generate-link', type='http', auth='public', methods=['GET'])
    def generate_commeta_auth_link(self):
        result = request.env['res.partner'].sudo().generate_commeta_oauth_link()
        # return result
        print(result)
        return http.request.make_response(json.dumps(result), headers={'Content-Type': 'application/json'})
    
    
    @http.route('/api/auth/callback', type='json', auth='public', methods=['POST'], csrf=False)
    def commeta_exchange(self, **kw):
        # Try to get parameters from both query string and request body
    

        try:
            # Manually parse JSON data from the request body
            body = request.httprequest.data.decode('utf-8')
            ip_address = get_client_ip(request)
            data = json.loads(body)
            code = data.get('code')
            code_verifier = data.get('code_verifier')
            device_data = {
                'device_name': data.get('device_name'),
                'device_unique_name': data.get('device_unique_name'),
                'is_ios': data.get('is_ios')
            }
        except json.JSONDecodeError:
            _logger.error("Failed to parse JSON body")
            return {"error": "Invalid JSON in request body"}

        if not code or not code_verifier:
            _logger.error("Authorization code and code verifier are required")
            return "Error: Authorization code and code verifier are required"

        try:
            token_data = request.env['res.partner'].sudo().commeta_exchange_code(code, code_verifier)
            if not token_data:
                _logger.error("Failed to exchange code for token")
                return "Error: Failed to exchange code for token"

            _logger.info(f"Token data received: {token_data}")

            result = request.env['res.partner'].sudo().commeta_authenticate(token_data, device_data, ip_address)
            if 'error' in result:
                _logger.error(f"Authentication error: {result['error']}")
                return f"Error: {result['error']}"

            _logger.info("Authentication successful")
            print(result, 'this is result')
            return result

        except Exception as e:
            _logger.exception("Exception during authentication process")
            return f"Error: An unexpected error occurred - {str(e)}"

redis_session.py: import redis
from datetime import datetime, timezone
import json
import uuid
import asyncio
from ..schemas.user_session_schema import UserStatus
from odoo.addons.fastapi_addon.utils.ip_geolocation import get_location_from_ip_sync

class IntegratedAuthSessionManager:
    def __init__(self, redis_url):
        self.redis = redis.Redis(host=redis_url, port=6379, decode_responses=True)
        self.cleanup_interval = 60
        self.activity_timeout = 300  # 5 minutes for idle status
        self.websocket_connections: Dict[str, Set[str]] = {}

    async def start_cleanup_task(self):
        while True:
            await self.cleanup_expired_sessions()
            await self.update_idle_status()
            await asyncio.sleep(self.cleanup_interval)

    async def update_idle_status(self):
        current_time = datetime.now(timezone.utc)
        for key in self.redis.scan_iter("session:*"):
            session_data = self.redis.get(key)
            if session_data:
                session = json.loads(session_data)
                last_activity = datetime.fromisoformat(session['last_activity'])

                if (current_time - last_activity).total_seconds() > self.activity_timeout:
                    session['status'] = UserStatus.IDLE
                    self.redis.set(key, json.dumps(session))

    async def cleanup_expired_sessions(self):
        current_time = datetime.now(timezone.utc).isoformat()
        for key in self.redis.scan_iter("session:*"):
            session_data = self.redis.get(key)
            if session_data:
                session = json.loads(session_data)
                if session['expires_at'] <= current_time:
                    self.end_session(key.decode('utf-8').split(':')[1])

    def create_session(self, user_data, ip_address="86.62.2.249"):
        user_id = user_data['user_id']
        session_id = str(uuid.uuid4())

        location_data = None
        if ip_address:
            location_data = get_location_from_ip_sync(ip_address)

        location_string = None
        if location_data:
            location_string = f"{location_data.get('city', '')}, {location_data.get('country', '')}"

        session_data = {
            'user_id': user_id,
            'device_name': user_data['device_name'],
            'device_id': user_data['device_id'],
            'expires_at': user_data['expires_at'].isoformat(),
            'app_version': user_data.get('app_version'),
            'location': user_data.get('location'),
            'last_activity': datetime.now(timezone.utc).isoformat(),
            'device_unique_name': user_data.get('device_unique_name'),
            'is_ios': user_data.get('is_ios'),
            'status': UserStatus.ONLINE,
            'lock_timestamp': datetime.now(timezone.utc).isoformat()
        }

        self.redis.setex(
            f"session:{session_id}",
            int(user_data['expires_at'].timestamp()) - int(datetime.now(timezone.utc).timestamp()),
            json.dumps(session_data)
        )
        self.redis.sadd(f"user_sessions:{user_id}", session_id)

        return session_id

        # Store the session data with expiration
        self.redis.setex(f"session:{session_id}", int(user_data['expires_at'].timestamp()) - int(datetime.now(timezone.utc).timestamp()), json.dumps(session_data))

        # Add this session to the user's set of active sessions
        self.redis.sadd(f"user_sessions:{user_id}", session_id)

        return session_id

    def get_session(self, session_id):
        session_data = self.redis.get(f"session:{session_id}")
        if not session_data:
            return None

        session = json.loads(session_data)

        # Check if the session has expired
        current_time = datetime.now(timezone.utc).isoformat()
        if current_time > session['expires_at']:
            self.end_session(session_id)
            return None

        return session

    def end_session(self, session_id):
        session_data = self.redis.get(f"session:{session_id}")
        if session_data:
            session = json.loads(session_data)
            user_id = session['user_id']
            self.redis.delete(f"session:{session_id}")
            self.redis.srem(f"user_sessions:{user_id}", session_id)

    def update_last_activity(self, session_id):
        session_data = self.get_session(session_id)
        if session_data:
            session_data['last_activity'] = datetime.now(timezone.utc).isoformat()
            self.redis.set(f"session:{session_id}", json.dumps(session_data))

    def update_session(self, session_id, user_data):
        session_data = self.get_session(session_id)
        if session_data:
            session_data.update(user_data)
            self.redis.set(f"session:{session_id}", json.dumps(session_data))


    def get_sessions_by_user_and_device(self, user_id, device_id):
        """
        Retrieve all active sessions for a specific user and device.
        """
        # Get all session IDs associated with the user
        session_ids = self.redis.smembers(f"user_sessions:{user_id}")
        active_sessions = []

        # Iterate over all session IDs and filter by device_id
        for session_id in session_ids:
            session_data = self.get_session(session_id)
            if session_data:
                # Check if the session belongs to the given device_id
                if session_data.get('device_id') == device_id:
                    active_sessions.append(session_id)

        return active_sessions

    def update_session_status(self, session_id: str, status: UserStatus):
        session_data = self.get_session(session_id)
        if session_data:
            session_data['status'] = status
            session_data['last_activity'] = datetime.now(timezone.utc).isoformat()
            self.redis.set(f"session:{session_id}", json.dumps(session_data))

    def register_websocket(self, session_id: str, websocket_id: str):
        if session_id not in self.websocket_connections:
            self.websocket_connections[session_id] = set()
        self.websocket_connections[session_id].add(websocket_id)
        self.update_session_status(session_id, UserStatus.ONLINE)

    def unregister_websocket(self, session_id: str, websocket_id: str):
        if session_id in self.websocket_connections:
            self.websocket_connections[session_id].discard(websocket_id)
            if not self.websocket_connections[session_id]:
                self.update_session_status(session_id, UserStatus.OFFLINE)
                del self.websocket_connections[session_id]

redis_session_manager = IntegratedAuthSessionManager("redis")

users_model_auth_method:     @api.model
    def commeta_authenticate(self, token_data, device_data, ip_address=None):
        if not token_data:
            return {'error': 'No token data provided'}

        user_info = self.commeta_get_user_info(token_data['access_token'])
        if not user_info:
            return {'error': 'Failed to get user info'}



        user = self.sudo().search([('phone_number', '=', user_info['phone'])], limit=1)
        profile = user_info['profile']

        avatar_data = None
        if 'avatar' in profile and profile['avatar'] and (not user or not user.avatar):
            try:
                response = requests.get(profile['avatar'])
                if response.status_code == 200:
                    avatar_data = base64.b64encode(BytesIO(response.content).read()).decode('utf-8')
            except requests.RequestException as e:
                _logger.error(f"Failed to download avatar: {e}")

        if not user:
            # Create a new user if none exists
            user_data = {
                'first_name': profile['first_name'],
                'name': profile['first_name'],
                'last_name': profile['last_name'],
                'middle_name': profile['middle_name'],
                'phone_number': user_info['phone'],
                'birth_date': profile['birth_date'],
                # 'avatar': profile['avatar'],  # TODO avatar for user
                'gender': 'male' if profile['gender'] == 'M' else 'female',
                'last_login': datetime.now(),
                'pnfl': profile['pinfl'],
            }
            if avatar_data:
                user_data['avatar'] = avatar_data
            user = self.sudo().create(user_data)
        else:
            # Update only missing or outdated fields
            profile = user_info['profile']
            update_fields = {}

            try:
                if not user.first_name:
                    update_fields['first_name'] = profile['first_name']
                    update_fields['name'] = profile['first_name']

                if not user.last_name:
                    update_fields['last_name'] = profile['last_name']

                if not user.middle_name:
                    update_fields['middle_name'] = profile['middle_name']

                if not user.birth_date:
                    update_fields['birth_date'] = profile['birth_date']

                if not user.avatar and avatar_data:
                    update_fields['avatar'] = avatar_data # TODO Avatar For user

                if not user.gender:
                    update_fields['gender'] = 'male' if profile['gender'] == 'M' else 'female'

                if not user.pnfl:
                    update_fields['pnfl'] = profile['pinfl']
            except KeyError as e:
                return {'error': f"Missing required field in profile: {e}"}

            if update_fields:
                update_fields['last_login'] = datetime.now()  # Update the last login time
                user.write(update_fields)

        device_user = self.env['user.device'].sudo().search([
            ('partner_id', '=', user.id),
            ('device_name', '=', device_data.get('device_name')),
            ('device_unique_name', '=', device_data.get('device_unique_name')),
        ])
        if not device_user:
            device_user = self.env['user.device'].sudo().create({
                'partner_id': user.id,
                'device_name': device_data.get('device_name'),
                'device_unique_name': device_data.get('device_unique_name'),
                'is_ios': device_data.get('is_ios'),
            })

        existing_sessions = redis_session_manager.get_sessions_by_user_and_device(user.id, device_user.id)

        if existing_sessions:
            session_id = existing_sessions[0]  # Assuming sessions are stored as a list
            session_data = redis_session_manager.get_session(session_id)
        else:
            # Create a new session if no existing session is found
            user_data = {
                'user_id': user.id,
                'expires_at': datetime.now(timezone.utc) + timedelta(days=365),
                'device_name': device_data.get('device_name'),
                'device_id': device_user.id,
                'device_unique_name': device_data.get('device_unique_name'),
                'is_ios': device_data.get('is_ios'),
            }
            session_id = redis_session_manager.create_session(user_data=user_data, ip_address=ip_address)

        project_token_data = {
            'user_id': user.id,
            'phone': user.phone_number,
            'device_user_id': device_user.id,
            'session_id': session_id
        }
        access_token, refresh_token = self.create_tokens(project_token_data)

        access_token_expire = datetime.now(timezone.utc) + timedelta(days=365)

        return {
            'user_id': user.id,
            "username": user.name,
            'access_token': access_token,
            'refresh_token': refresh_token,
            'expires_at': access_token_expire.isoformat(),
            'is_verified': bool(user.pnfl),
        }

schema: from pydantic import BaseModel
from typing import List
from enum import Enum


class UserStatus(str, Enum):
    ONLINE = "online"
    OFFLINE = "offline"
    IDLE = "idle"


class SessionSchema(BaseModel):
    session_id: str
    app_version: str | None
    device_name: str | None
    location: str | None
    ip_address: str | None
    last_activity: str | None
    is_ios: bool | None
    status: UserStatus = UserStatus.OFFLINE


class SessionResponse(BaseModel):
    current_session: SessionSchema
    other_sessions: List[SessionSchema]