403Webshell
Server IP : 3.147.158.171  /  Your IP : 216.73.216.216
Web Server : Apache/2.4.67 (Amazon Linux) OpenSSL/3.5.5
System : Linux ip-172-31-2-178.us-east-2.compute.internal 6.1.172-216.329.amzn2023.x86_64 #1 SMP PREEMPT_DYNAMIC Wed May 20 06:31:34 UTC 2026 x86_64
User : ec2-user ( 1000)
PHP Version : 8.4.21
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : OFF
Directory :  /tsai/repo/api/app/services/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /tsai/repo/api/app/services/site_config_service.py
import json
import logging
import os
from pathlib import Path
from typing import List, Optional
from urllib.parse import urlparse
from ..appTypes import SiteConfig

CACHE_DIR = Path(__file__).parent.parent / 'data'


class SiteConfigService:
    _sites: List[SiteConfig] = []
    _loaded: bool = False

    def __init__(self):
        if not SiteConfigService._loaded:
            self._load_config()
            SiteConfigService._loaded = True

    def _get_cache_path(self) -> Path:
        env = os.getenv('TSAI_ENV', 'development')
        if env == 'production':
            return CACHE_DIR / 'site_configs_tsai.json'
        elif env == 'scike_ai':
            return CACHE_DIR / 'site_configs_scike.json'
        return CACHE_DIR / 'site_configs_development.json'

    def _load_config(self):
        try:
            self._load_from_drupal()
        except Exception as e:
            logging.warning(f"Drupal site config fetch failed, using cache: {e}")
            self._load_from_cache()

        self._load_dev_aliases()

    def _load_from_drupal(self):
        from .drupal import DrupalService
        drupal_svc = DrupalService()
        data_list, included_list = drupal_svc.fetch_all_site_configs()
        sites = drupal_svc.parse_site_config_nodes(data_list, included_list)

        if not sites:
            raise Exception("Drupal returned 0 site configs — content type may not be installed yet")

        SiteConfigService._sites = sites
        self._write_cache(sites)
        print(f"Loaded {len(sites)} site configs from Drupal")

    def _load_from_cache(self):
        cache_path = self._get_cache_path()
        if not cache_path.exists():
            logging.error(f"No cache file at {cache_path} and Drupal is unreachable")
            SiteConfigService._sites = []
            return

        with open(cache_path) as f:
            config = json.load(f)

        api_host = os.getenv('API_HOST', 'http://localhost:8000/api/v1')
        drupal_host = os.getenv('DRUPAL_HOST', 'http://drupal.test')
        drupal_api = os.getenv('DRUPAL_API', '/jjknkk/jptb69dhj027ooae/jsonapi')

        sites = []
        for site_data in config.get('sites', []):
            sites.append(SiteConfig(
                cb_host=site_data['cb_host'],
                wp_host=site_data['wp_host'],
                wp_dir=site_data['wp_dir'],
                slug=site_data['slug'],
                api_host=api_host,
                drupal_host=drupal_host,
                drupal_api=drupal_api,
                drupal_uid=site_data.get('drupal_uid'),
                drupal_target_id=site_data.get('drupal_target_id'),
                drupal_node_id=site_data.get('drupal_node_id'),
            ))

        SiteConfigService._sites = sites
        print(f"Loaded {len(sites)} site configs from cache: {cache_path.name}")

    def _write_cache(self, sites: List[SiteConfig]):
        cache_path = self._get_cache_path()
        cache_data = {
            "sites": [
                {
                    "cb_host": s.cb_host,
                    "wp_host": s.wp_host,
                    "wp_dir": s.wp_dir,
                    "slug": s.slug,
                    "drupal_uid": s.drupal_uid,
                    "drupal_target_id": s.drupal_target_id,
                    "drupal_node_id": s.drupal_node_id,
                }
                for s in sites
            ]
        }
        try:
            with open(cache_path, 'w') as f:
                json.dump(cache_data, f, indent=2)
        except Exception as e:
            logging.warning(f"Failed to write site config cache: {e}")

    def _load_dev_aliases(self):
        env = os.getenv('TSAI_ENV', 'development')
        if env in ('production', 'scike_ai'):
            return

        aliases_path = CACHE_DIR / 'dev_aliases.json'
        if not aliases_path.exists():
            return

        try:
            with open(aliases_path) as f:
                aliases = json.load(f)
        except Exception as e:
            logging.warning(f"Failed to read dev aliases: {e}")
            return

        count = 0
        for alias_host, slug in aliases.items():
            site = self.get_site_by_slug(slug)
            if not site:
                logging.warning(f"Dev alias {alias_host} → {slug}: slug not found, skipping")
                continue
            alias_site = site.model_copy(update={'cb_host': alias_host, 'drupal_node_id': None})
            SiteConfigService._sites.append(alias_site)
            count += 1

        if count:
            print(f"Loaded {count} dev aliases")

    @classmethod
    def reload(cls):
        """Force a fresh reload from Drupal."""
        cls._loaded = False
        cls._sites = []
        cls()

    def get_all_sites(self) -> List[SiteConfig]:
        return SiteConfigService._sites

    def get_site_by_cb_host(self, host: str) -> Optional[SiteConfig]:
        for site in SiteConfigService._sites:
            if site.cb_host == host:
                return site
        wp_hostname = urlparse(host if '://' in host else f'//{host}').hostname
        if not wp_hostname:
            return None
        for site in SiteConfigService._sites:
            if urlparse(site.wp_host).hostname == wp_hostname:
                return site
        return None

    def get_site_by_slug(self, slug: str) -> Optional[SiteConfig]:
        for site in SiteConfigService._sites:
            if site.slug == slug:
                return site
        return None

    def get_drupal_user(self, username: str) -> Optional[str]:
        """Get a Drupal user UUID by site slug."""
        site = self.get_site_by_slug(username)
        return site.drupal_uid if site else None

    def get_slug_by_drupal_uuid(self, uuid: str) -> Optional[str]:
        """Get a site slug by Drupal user UUID."""
        for site in SiteConfigService._sites:
            if site.drupal_uid == uuid:
                return site.slug
        return None

    async def add_site(self, cb_host: str, wp_host: str, wp_dir: str, slug: str, drupal_user: str = "") -> SiteConfig:
        """Create a site_config node in Drupal and add to in-memory cache."""
        from .drupal import DrupalService
        import requests as req

        drupal_svc = DrupalService()
        api_host = os.getenv('API_HOST', 'http://localhost:8000/api/v1')
        drupal_host = os.getenv('DRUPAL_HOST', 'http://drupal.test')
        drupal_api = os.getenv('DRUPAL_API', '/jjknkk/jptb69dhj027ooae/jsonapi')

        owner_uuid = None
        drupal_target_id = None

        session = req.Session()
        try:
            await drupal_svc.login(session)
            csrf_token = await drupal_svc.get_csrf_token(session)

            if drupal_user:
                owner_uuid, drupal_target_id = drupal_svc.fetch_drupal_user_by_name(drupal_user, session=session)

            node_data = await drupal_svc.create_site_config_node(
                session, csrf_token,
                slug=slug, cb_host=cb_host, wp_host=wp_host,
                wp_dir=wp_dir,
                owner_uuid=owner_uuid or '',
            )
            node_uuid = node_data.get('id') if node_data else None
        finally:
            session.close()

        new_site = SiteConfig(
            cb_host=cb_host,
            wp_host=wp_host,
            wp_dir=wp_dir,
            slug=slug,
            api_host=api_host,
            drupal_host=drupal_host,
            drupal_api=drupal_api,
            drupal_uid=owner_uuid,
            drupal_target_id=drupal_target_id,
            drupal_node_id=node_uuid,
        )

        SiteConfigService._sites.append(new_site)
        self._write_cache(SiteConfigService._sites)
        return new_site

    async def remove_site(self, cb_host: str) -> Optional[dict]:
        """Remove a site_config node from Drupal and from in-memory cache."""
        from .drupal import DrupalService
        import requests as req

        site = None
        for s in SiteConfigService._sites:
            if s.cb_host == cb_host:
                site = s
                break

        if not site:
            return None

        removed = {
            'cb_host': site.cb_host,
            'slug': site.slug,
            'drupal_user': site.slug,
        }

        if site.drupal_node_id:
            drupal_svc = DrupalService()
            session = req.Session()
            try:
                await drupal_svc.login(session)
                csrf_token = await drupal_svc.get_csrf_token(session)
                await drupal_svc.delete_site_config_node(session, csrf_token, site.drupal_node_id)
            except Exception as e:
                logging.error(f"Failed to delete site_config node from Drupal: {e}")
            finally:
                session.close()

        SiteConfigService._sites = [s for s in SiteConfigService._sites if s.cb_host != cb_host]
        self._write_cache(SiteConfigService._sites)
        return removed

Youez - 2016 - github.com/yon3zu
LinuXploit