����JFIF��`�`�����Viewing File: /home/u820193700/domains/thereown.com/public_html/api/index.php
<?php
// ═══ REOWN API ROUTER — /api/index.php?action=... ═══
require __DIR__.'/config.php';
$in=json_decode(file_get_contents('php://input'),true)?:[];
$act=$_GET['action']??$in['action']??'';

switch($act){

// ── AUTH ─────────────────────────────────────
case 'login': {
  // simple brute-force damper: 1s delay + lockout after 8 fails/session
  $_SESSION['fails']=$_SESSION['fails']??0;
  if($_SESSION['fails']>8) out(['error'=>'Too many attempts. Try later.'],429);
  usleep(800000);
  $s=db()->prepare("SELECT * FROM users WHERE active=1");
  $s->execute();
  $users = $s->fetchAll(PDO::FETCH_ASSOC);
  $u = null;
  foreach($users as $user) {
    if(password_verify($in['password']??'',$user['pass_hash'])) {
      $u = $user;
      break;
    }
  }
  if(!$u){
    $_SESSION['fails']++; log_act('Failed login','Unknown User');
    out(['error'=>'Invalid credentials'],401);
  }
  session_regenerate_id(true);
  $_SESSION['uid']=$u['id']; $_SESSION['role']=$u['role']; $_SESSION['fails']=0;
  log_act('Login',$u['name']);
  out(['ok'=>true,'role'=>$u['role'],'name'=>$u['name']]);
}
case 'logout': { log_act('Logout'); session_destroy(); out(['ok'=>true]); }
case 'me': out(['role'=>$_SESSION['role']??null]);

// ── BIKES ────────────────────────────────────
case 'bikes': {
  $staff=!empty($_SESSION['role']);
  $sql="SELECT b.*, (SELECT file_path FROM media m WHERE m.bike_id=b.id AND m.kind='gallery' ORDER BY sort_order LIMIT 1) cover,
        (SELECT COUNT(*) FROM media m2 WHERE m2.bike_id=b.id AND m2.kind='spin') spin_count,
        (SELECT COUNT(*) FROM media m3 WHERE m3.bike_id=b.id AND m3.kind='video') video_count,
        (SELECT COUNT(*) FROM media m4 WHERE m4.bike_id=b.id AND m4.kind='gallery') gallery_count
        FROM bikes b".($staff?"":" WHERE b.approval='approved'")." ORDER BY FIELD(b.status,'available','booked','sold')";
  out(db()->query($sql)->fetchAll(PDO::FETCH_ASSOC));
}
case 'bike_view': {  // public view counter + log
  $s=db()->prepare("UPDATE bikes SET views=views+1 WHERE id=?"); $s->execute([(int)($in['id']??0)]);
  log_act('Viewed bike','bike #'.(int)($in['id']??0));
  out(['ok'=>true]);
}
case 'add_bike': {
  require_role('Executive','Manager','Director');
  $appr=in_array($_SESSION['role'],['Manager','Director'])?'approved':'pending';
  $s=db()->prepare("INSERT INTO bikes (name,variant,reg,chassis,model_year,km,owner_count,ins_valid,cc,power,type,hue,hue2,asking,market,new_price,new_ref,approval,added_by)
    VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
  $s->execute([$in['name'],$in['variant'],$in['reg'],$in['chassis']??'',$in['year'],$in['km'],$in['owner']??'1st Owner',
    $in['ins']??'',$in['cc']??350,$in['power']??'',$in['type']??'',$in['hue']??'#2E5C43',$in['hue2']??'#C9A84C',
    (int)$in['asking'],(int)($in['market']??0),(int)($in['newPrice']??0),$in['newRef']??'',$appr,$_SESSION['uid']]);
  log_act('Added motorcycle',$in['name'].' ('.$in['reg'].')'.($appr==='pending'?' — pending':''));
  out(['ok'=>true,'id'=>db()->lastInsertId(),'approval'=>$appr]);
}
case 'approve': case 'deny': {
  require_role('Manager','Director');
  $s=db()->prepare("UPDATE bikes SET approval=? WHERE id=?");
  $s->execute([$act==='approve'?'approved':'denied',(int)$in['id']]);
  log_act(($act==='approve'?'Approved':'Denied').' listing','bike #'.(int)$in['id']);
  out(['ok'=>true]);
}
case 'set_status': {
  require_role('Executive','Manager','Director');
  $st=in_array($in['status']??'',['available','booked','sold'])?$in['status']:'available';
  $s=db()->prepare("UPDATE bikes SET status=?, booked_on=? WHERE id=?");
  $s->execute([$st,$st==='booked'?date('Y-m-d'):null,(int)$in['id']]);
  log_act('Status change','bike #'.(int)$in['id'].' → '.$st);
  out(['ok'=>true]);
}
case 'set_price': {
  require_role('Executive','Manager','Director');
  $s=db()->prepare("UPDATE bikes SET asking=? WHERE id=?");
  $s->execute([(int)$in['asking'],(int)$in['id']]);
  log_act('Changed price','bike #'.(int)$in['id'].' → ₹'.(int)$in['asking']);
  out(['ok'=>true]);
}
case 'delete_bike': {
  require_role('Executive','Manager','Director');
  $s=db()->prepare("DELETE FROM bikes WHERE id=?"); $s->execute([(int)$in['id']]);
  log_act('Deleted listing','bike #'.(int)$in['id']);
  out(['ok'=>true]);
}

// ── MEDIA UPLOAD (multipart) ─────────────────
case 'upload': {
  require_role('Executive','Manager','Director');
  $bike = !empty($_POST['bike_id']) ? (int)$_POST['bike_id'] : null; 
  $kind = $_POST['kind']??'gallery';
  if(!in_array($kind,['gallery','spin','video','hero','delivery'])) out(['error'=>'bad kind'],400);
  $saved=[];
  $debug_log = [];
  foreach($_FILES['files']['tmp_name']??[] as $i=>$tmp){
    if($_FILES['files']['error'][$i] !== UPLOAD_ERR_OK) {
        $debug_log[] = "error not ok for file $i: " . $_FILES['files']['error'][$i];
        continue;
    }
    if(!is_uploaded_file($tmp)) {
        $debug_log[] = "not uploaded file for file $i";
        continue;
    }
    $mime=@mime_content_type($tmp);
    if (!$mime || (!str_starts_with($mime,'image/') && !str_starts_with($mime,'video/'))) {
        $mime = $_FILES['files']['type'][$i] ?? '';
    }
    $isVid=str_starts_with($mime,'video/'); $isImg=str_starts_with($mime,'image/');
    if($kind==='video'? !$isVid : !$isImg) {
        $debug_log[] = "wrong type for file $i. mime: $mime";
        continue;
    }
    $mb=$_FILES['files']['size'][$i]/1048576;
    if($mb > ($isVid?MAX_VID_MB:MAX_IMG_MB)) {
        $debug_log[] = "too big for file $i";
        continue;
    }
    $ext=$isVid?'mp4':(str_contains($mime,'png')?'png':'jpg');
    
    $namePrefix = bin2hex(random_bytes(16));
    if (!empty($_POST['labels'][$i])) {
      $labelSafe = preg_replace('/[^a-zA-Z0-9_]/', '', str_replace(' ', '_', $_POST['labels'][$i]));
      $namePrefix .= '__label_' . $labelSafe;
    }
    if (!empty($_POST['tire_pcts'][$i])) {
      $pct = (int)$_POST['tire_pcts'][$i];
      $namePrefix .= '__pct_' . $pct;
    }
    
    $name=$namePrefix.'.'.$ext;
    
    $sortOrder = (int)($_POST['sort']??999);
    if (!empty($_POST['labels'][$i]) && $_POST['labels'][$i] === 'cover') {
      $sortOrder = 0;
    }
    
    if(move_uploaded_file($tmp,UPLOAD_DIR.$name)){
      $s=db()->prepare("INSERT INTO media (bike_id,kind,file_path,sort_order,uploaded_by) VALUES (?,?,?,?,?)");
      $s->execute([$bike,$kind,'uploads/'.$name,$sortOrder,$_SESSION['uid']]);
      $saved[]='uploads/'.$name;
    } else {
        $debug_log[] = "move_uploaded_file failed for file $i";
    }
  }
  log_act('Uploaded '.$kind,count($saved).' file(s) — bike #'.$bike . ' Debug: '.json_encode($debug_log));
  if (count($saved) == 0 && count($debug_log) > 0) {
      out(['ok'=>false, 'error'=>implode(", ", $debug_log)]);
  }
  out(['ok'=>true,'files'=>$saved]);
}
case 'media': {
  $s=db()->prepare("SELECT * FROM media WHERE bike_id=? ORDER BY kind,sort_order");
  $s->execute([(int)($_GET['bike_id']??0)]);
  out($s->fetchAll(PDO::FETCH_ASSOC));
}
case 'set_cover': {
  require_role('Executive','Manager','Director');
  db()->prepare("UPDATE media SET sort_order=sort_order+1 WHERE bike_id=? AND kind='gallery'")->execute([(int)$in['bike_id']]);
  db()->prepare("UPDATE media SET sort_order=0 WHERE id=?")->execute([(int)$in['media_id']]);
  log_act('Changed cover','bike #'.(int)$in['bike_id']);
  out(['ok'=>true]);
}
case 'delete_media': {
  require_role('Executive','Manager','Director');
  $fullPath = UPLOAD_DIR . basename($in['file_path']);
  if(file_exists($fullPath) && is_file($fullPath)){
    unlink($fullPath);
  }
  $s=db()->prepare("DELETE FROM media WHERE file_path=?");
  $s->execute([$in['file_path']]);
  log_act('Deleted media',$in['file_path']);
  out(['ok'=>true]);
}

// ── LEADS (booking / sell / enquiry) ─────────
case 'lead': {
  $bike_id = !empty($in['bike_id']) ? (int)$in['bike_id'] : null;
  $s=db()->prepare("INSERT INTO leads (kind,bike_id,name,phone,payload) VALUES (?,?,?,?,?)");
  $s->execute([$in['kind']??'enquiry',$bike_id,mb_substr($in['name']??'',0,80),
    mb_substr($in['phone']??'',0,20),json_encode($in['payload']??[])]);
  log_act('Lead: '.($in['kind']??'enquiry'),($in['name']??'').' '.($in['phone']??''));
  out(['ok'=>true]);
}
case 'get_leads': {
  require_role('Executive','Manager','Director');
  $s=db()->prepare("SELECT * FROM leads ORDER BY created_at DESC");
  $s->execute();
  out($s->fetchAll(PDO::FETCH_ASSOC));
}
case 'update_lead_status': {
  require_role('Executive','Manager','Director');
  $s=db()->prepare("UPDATE leads SET status=? WHERE id=?");
  $s->execute([$in['status']??'new', (int)($in['id']??0)]);
  log_act('Updated lead status', 'Lead #'.(int)($in['id']??0).' -> '.($in['status']??'new'));
  out(['ok'=>true]);
}

// ── DELIVERIES ───────────────────────────────
case 'get_deliveries': {
  $s=db()->prepare("SELECT * FROM deliveries ORDER BY created_at DESC");
  $s->execute();
  out($s->fetchAll(PDO::FETCH_ASSOC));
}
case 'add_delivery': {
  require_role('Executive','Manager','Director');
  $bike_id = $_POST['bike_id'] ?? null;
  $name = mb_substr($_POST['name']??'',0,80);
  $sub = mb_substr($_POST['sub']??'',0,255);
  $location = mb_substr($_POST['location']??'',0,255);
  $imgPath = null;
  
  if(!empty($_FILES['file']['tmp_name'])){
      $tmp = $_FILES['file']['tmp_name'];
      $mime=@mime_content_type($tmp);
      if (!$mime || (!str_starts_with($mime,'image/'))) {
          $mime = $_FILES['file']['type'] ?? '';
      }
      $ext=str_contains($mime,'png')?'png':'jpg';
      $fileName=bin2hex(random_bytes(16)).'.'.$ext;
      if(move_uploaded_file($tmp,UPLOAD_DIR.$fileName)){
          $imgPath = 'uploads/'.$fileName;
      }
  }

  $s=db()->prepare("INSERT INTO deliveries (bike_id,name,sub,location,img) VALUES (?,?,?,?,?)");
  $s->execute([$bike_id, $name, $sub, $location, $imgPath]);
  log_act('Added delivery', $name.' - '.$sub);
  out(['ok'=>true]);
}
case 'delete_delivery': {
  require_role('Executive','Manager','Director');
  $s=db()->prepare("DELETE FROM deliveries WHERE id=?");
  $s->execute([(int)$in['id']]);
  log_act('Deleted delivery','ID '.(int)$in['id']);
  out(['ok'=>true]);
}

// ── DIRECTOR MONITOR ─────────────────────────
case 'monitor': {
  require_role('Director');
  $stats=[]; 
  foreach(['Login'=>'logins','Viewed bike'=>'views','Added motorcycle'=>'added'] as $a=>$k){
    $s=db()->prepare("SELECT COUNT(*) FROM activity WHERE action=?");$s->execute([$a]);$stats[$k]=(int)$s->fetchColumn();
  }
  $stats['leads']=(int)db()->query("SELECT COUNT(*) FROM leads")->fetchColumn();
  $stats['total_events']=(int)db()->query("SELECT COUNT(*) FROM activity")->fetchColumn();
  $log=db()->query("SELECT a.*,u.name uname FROM activity a LEFT JOIN users u ON u.id=a.user_id ORDER BY a.id DESC LIMIT 200")->fetchAll(PDO::FETCH_ASSOC);
  $top=db()->query("SELECT id,name,variant,reg,views FROM bikes ORDER BY views DESC LIMIT 5")->fetchAll(PDO::FETCH_ASSOC);
  $byrole=db()->query("SELECT role,COUNT(*) c FROM activity GROUP BY role")->fetchAll(PDO::FETCH_ASSOC);
  out(['stats'=>$stats,'log'=>$log,'top_bikes'=>$top,'by_role'=>$byrole]);
}

default: out(['error'=>'Unknown action'],404);
}
Back to Directory �������}�!1AQa"q2���#B��R��$3br� %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz�������������������������������������������������������������������������������� ������w�!1AQaq"2�B���� #3R�br� $4�%�&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz������������������������������������������������������������������������ ��?��_��+��?��(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(���(�����