i have odoo17 enterprise and fastapi project and we need to add location to sessions list and detail and we get it from ip adress of user that we get from request, heres my files, dont use external libraries for location:
redis_session.py: import redis
from datetime import datetime, timezone
import json
import uuid
import asyncio
from ..schemas.user_session_schema import UserStatus

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):
        user_id = user_data['user_id']
        session_id = str(uuid.uuid4())

        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")





user_session_router - from fastapi import APIRouter, HTTPException, Depends, WebSocket, WebSocketDisconnect
import asyncio
from datetime import timedelta, timezone
from typing import Annotated
from odoo.api import Environment
from odoo import _
from ..dependencies import odoo_env, get_partner_with_session, get_partner_with_session_id
from ..schemas.user_session_schema import UserStatus
from odoo.addons.base.models.res_partner import Partner
from odoo.addons.fastapi_addon.utils.redis_session import redis_session_manager
from odoo.addons.fastapi_addon.schemas.user_session_schema import (
    SessionSchema,
    SessionResponse,
)
from datetime import datetime

router = APIRouter(tags=['User Session'])


@router.websocket("/ws/{session_id}")
async def websocket_endpoint(
        websocket: WebSocket,
        session_id: str,
        env: Annotated[Environment, Depends(odoo_env)],
        partner: Annotated[Partner, Depends(get_partner_with_session)]
):
    await websocket.accept()
    websocket_id = str(uuid.uuid4())
    redis_session_manager.register_websocket(session_id, websocket_id)

    try:
        while True:
            await websocket.receive_text()
            redis_session_manager.update_last_activity(session_id)

    except WebSocketDisconnect:
        redis_session_manager.unregister_websocket(session_id, websocket_id)
    except Exception as e:
        redis_session_manager.unregister_websocket(session_id, websocket_id)
        await websocket.close()


@router.get("/sessions", response_model=SessionResponse)
async def get_sessions(
    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"))

    response = SessionResponse(
        current_session=SessionSchema(
            session_id=current_session_id,
            app_version=current_session_data.get('app_version'),
            device_name=current_session_data['device_name'],
            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),
            lock_timestamp=current_session_data.get('lock_timestamp') or datetime.now(timezone.utc)
        ),
        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=session_data['device_name'],
                    location=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),
                    lock_timestamp=session_data.get('lock_timestamp') or datetime.now(timezone.utc)
                )
                response.other_sessions.append(session_info)

    return response


@router.get("/session/{session_id}", response_model=SessionSchema)
async def get_session_detail(
        session_id: str,
        env: Annotated[Environment, Depends(odoo_env)],
        partner: Annotated[Partner, Depends(get_partner_with_session)]
):
    
    user_id = partner.id
    user_sessions = redis_session_manager.redis.smembers(f"user_sessions:{user_id}")

    if session_id not in user_sessions:
        raise HTTPException(status_code=404, detail=_("Session not found"))

    session_data = redis_session_manager.get_session(session_id)
    if not session_data:
        raise HTTPException(status_code=404, detail=_("Session data not found"))
    session_detail = SessionSchema(
        session_id=session_id,
        app_version=session_data.get('app_version'),
        device_name=session_data['device_name'],
        location=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),
        lock_timestamp=session_data.get('lock_timestamp') if 'lock_timestamp' in session_data else None,
    )

    return session_detail


@router.delete("/logout/all-except-current", status_code=204)
async def logout_all_except_current(
        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
    user_sessions = redis_session_manager.redis.smembers(f"user_sessions:{user_id}")

    for session_id in user_sessions:
        if session_id != current_session_id:
            session_data = redis_session_manager.get_session(current_session_id)
            if session_data:
                lock_timestamp = datetime.fromisoformat(session_data['lock_timestamp'])
                if (datetime.now(timezone.utc) - lock_timestamp) < timedelta(minutes=15):
                    raise HTTPException(status_code=403, detail=_("Cannot end other sessions within 24 hours of login"))

            redis_session_manager.end_session(session_id)   

    return None


@router.delete("/logout/current", status_code=204)  
async def logout_current_session(
        env: Annotated[Environment, Depends(odoo_env)],
        partner: Annotated[Partner, Depends(get_partner_with_session)],
        current_session_id: str = Depends(get_partner_with_session_id)
):
    redis_session_manager.end_session(current_session_id)
    return None


@router.delete("/logout/{session_id}", status_code=204)
async def logout_from_session(
        session_id: str,
        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
    user_sessions = redis_session_manager.redis.smembers(f"user_sessions:{user_id}")

    if session_id not in user_sessions:
        raise HTTPException(status_code=404, detail=_("Session not found"))

    if session_id == current_session_id:
        raise HTTPException(status_code=400, detail=_("Cannot logout from current session using this endpoint"))

    session_data = redis_session_manager.get_session(current_session_id)
    if session_data:
        lock_timestamp = datetime.fromisoformat(session_data['lock_timestamp'])
        if (datetime.now(timezone.utc) - lock_timestamp) < timedelta(hours=24):
            raise HTTPException(status_code=403, detail=_("Cannot end other sessions within 24 hours of login"))

    redis_session_manager.end_session(session_id)
    return None

session_schema.py:
from pydantic import BaseModel
from typing import List, Optional
from datetime import datetime
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
    last_activity: str | None
    is_ios: bool | None
    status: UserStatus = UserStatus.OFFLINE
    lock_timestamp: Optional[datetime] | None


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