<?php
namespace Taeluf\ProjectViewer;
class ProjectRouter extends \Lia\Compo {
const PROJECT_NOT_ALLOWED = 'PROJECT_NOT_ALLOWED';
const FILE_NOT_FOUND = 'FILE_NOT_FOUND';
protected $active;
protected $vendors;
protected $webhookUrl = '/project-viewer/update-project/';
public $baseUrl;
protected $srcDir;
/**
* Pass an options array to the package like:
* ```php
* [
* 'projects'=>
* [
* 'VendorName'=>['url'=>'/base-url/', 'dir'=>'/absolute/path/']
* Currently, we only support one vendor.
* ],
* //exclude 'permit' to allow all projects or pass 'permit'=>['VendorName/*'] to permit all projects under a given vendor or 'permit'=>['*'] (allow all projects)
* 'this-is-not-active-yet-permit'=>[
* 'VendorName/ProjectDirectory'
* 'VendorName/Project2Dir'
* ]
* ]
* ```
*
* @export(Usage.SetupProjects)
*/
public function __construct($package){
parent::__construct($package);
$this->projectDirs = $package->get('projects');
$this->baseUrl = $package->get('baseUrl');
// /base/vendor/project(-src)?(:branch_name)?/DocFile/?
$this->lia->addRoute($this->baseUrl, function(){echo "zeep";exit;});
var_dump($this->baseUrl);
$this->lia->append('lia:route.routers', [$this, 'newRoute']);
$this->srcDir = array_values((array)$this->vendors)[0]['dir'];
$vendorName = array_keys((array)$this->vendors)[0];
$serverDir = array_values((array)$this->vendors)[0]['dir'];
$this->vendorDir = $serverDir.'/repos/'.$vendorName.'/';
}
public function newRoute($request){
// see route() below for actual code to use maybe
//
// I want to parse the url into its relevant pieces
// Ultimately, I just have a pattern that the url matches
//
// Starts with base url
// then... vendor? then project name?
// then :branch_name (unless we're on default branch)
// If it ends with a `/` then its a directory, not a file
// Maybe just deliver with .md extension
//
//
//
}
public function isDocsRequest(){
if ($this->active->mode=='docs')return true;
return false;
}
public function isRequested($url){
if ($this->urlRelToBase($url)===false)return false;
return true;
}
public function handleProjectError($errorType, $msg){
switch ($errorType){
case self::PROJECT_NOT_ALLOWED:
echo "Project Not allowed\n<br>\n{$msg}";
break;
case self::FILE_NOT_FOUND:
echo "You asked for file that does not seem to exist!";
break;
}
}
public function isProjectAllowed($projectName) {
if (is_dir($path=$this->vendorDir.$projectName))return true;
return false;
}
/**
* Returns false if base url is not present in $url
* otherwise returns the url with the base url removed. There is no leading slash
*/
public function urlRelToBase($url){
if (substr($url,0,$len=strlen($this->baseUrl))!==$this->baseUrl)return false;
$rel = substr($url,$len);
if (strlen($rel)>0&&$rel[0]=='/')$rel = substr($rel,1);
return $rel;
}
public function getActiveProject(){
return $this->active;
}
public function urlFor($project, $relUrl){
$url = $this->baseUrl.'/'.$project->name.'/'.$relUrl;
$url = str_replace(['///','//'],'/',$url);
return $url;
}
// public function urlForFilePath($project, $filePath){
// $filePath = substr($filePath,strlen($this->safeDir));
// $parts = explode('/',$filePath);
// $relUrl = '/'.implode('/',array_slice($parts,4));
// $url = $this->baseUrl.'/'.$project->name.'/'.$relUrl;
// $url = str_replace(['///','//'],'/',$url);
// $url = str_replace(' ', '%20', $url);
// return $url;
// }
public function urlForFilePath($path){
$srcDir = $this->srcDir;
$path = substr($path,strlen($srcDir));
$base = $this->baseUrl;
$base .= $this->active->project->urlForVendorFile($this->active->branch, $this->active->mode, $path);
$base = str_replace(' ', '%20', $base);
$base = str_replace('//','/',$base);
return $base;
}
public function isActive($relUrl){
$url = str_replace(['///','//'],'/',$relUrl.'/');
$requested = $this->getFileUrl($this->requestUrl);
if (substr($requested,0,strlen($url))==$url){
return true;
}
return false;
}
public function getFileUrl($url){
$relPath = substr($url,strlen($this->baseUrl));
if (strlen($relPath)==0){
return null;
}
$parts = explode('/',$relPath);
$projectName = array_shift($parts);
return '/'.implode('/',$parts);
}
public function getProject($url){
$relPath = substr($url,strlen($this->baseUrl));
if (strlen($relPath)==0){
return null;
}
$parts = explode('/',$relPath);
$projectName = array_shift($parts);
foreach ($this->projects as $project){
if (strtolower($projectName)==strtolower($project->name)){
return $project;
}
}
return null;
}
public function projectUrl($project){
$base = $this->baseUrl.'/';
$base .= $project->urlForRequest($this->active->branch,$this->active->mode,'');
return str_replace('//','/',$base);
}
public function defaultBranchUrl($project){
$path = $this->baseUrl.'/'.$project->name.'/';
return str_replace('//','/',$path);
}
protected function handleWebhook(){
try {
$rootDir = $this->dir;
$wh = new \tlf\GithubWebhook(
$_POST['payload'],
$this->webhookKey,
$rootDir.'/work/',
$rootDir.'/repos/',
$this->repos,
);
$wh->outputCurrentBranch();
ob_start();
} catch (\Exception $e){
echo 'we caught an exception';
} catch (\Throwable $e){
echo 'we caught a throwable';
} catch (\Error $e){
echo 'We caught an error';
} finally {
//so I'm not accidentally passing anything sensitive back to github, such as my username on my server!
ob_get_clean();
}
exit;
}
static public function packageDir(){
return dirname(__DIR__);
}
public function getProjects(){
if ($this->projects!=null)return $this->projects;
$list = [];
foreach (scandir($this->srcDir) as $projDir){
if ($projDir=='.'||$projDir=='..'||!is_dir($this->srcDir.'/'.$projDir))continue;
$list[] = $project = new Project($this->srcDir.'/'.$projDir);
}
$this->projects = $list;
return $list;
}
public function curBranch(){
return $this->active->branch;
}
public function filesFor($url){
return $this->active->project->filesForRequest($this->active->branch, $this->active->mode, $url);
}
public function fileFor($url){
$url = str_replace('%20', ' ',$url);
// var_dump("<br>\n--".$url."\n<br>");
// exit;
return $this->active->project->fileForRequest($this->active->branch, $this->active->mode, $url);
}
public function getBranchUrl($branchName){
$route = $this->active->project->urlForRequest($branchName, $this->active->mode, '');
$base = $this->baseUrl;
return $base.$route;
}
public function getFullUrl($rel){
$route = $this->active->project->urlForRequest($this->active->branch, $this->active->mode, $rel);
$base = $this->baseUrl;
return $base.$route;
}
public function docsUrlFor($rel){
$route = $this->active->project->urlForRequest($this->active->branch, 'docs', $rel);
$base = $this->baseUrl;
return $base.$route;
}
public function srcUrlFor($rel){
$route = $this->active->project->urlForRequest($this->active->branch, 'src', $rel);
$base = $this->baseUrl;
return $base.$route;
}
public function isWebhookRequest($url){
return false;
}
public function requestedVendors($url){
//@TODO cache vendors so I don't create the same vendor over and over
$list = [];
foreach ($this->vendors as $name=>$vData){
$len = strlen($vData['url']);
$urlCheck = substr($url,0,$len);
if ($vData['url']!=$urlCheck)continue;
$list[] = new Vendor($name,$vData);
}
if ($list===[])return false;
return $list;
}
public function requestedProjectAndVendor($url){
$projects = [];
$matchedVendor = false;
foreach ($this->requestedVendors($url) as $vendor){
$p = $vendor->projectForUrl($url);
if ($p==false)continue;
$matchedVendor = $vendor;
$projects[] = $p;
}
if (count($projects)>1){
throw new \Exception("Multiple projects were found for this page...");
}
if ($projects==[])return false;
return [
'project'=>$projects[0],
'vendor'=>$vendor
];
}
public function deliver(\Lia\Obj\Route $route, \Lia\Obj\Response $response){
$this->lia->view('Docu/Resources').'';
$response->content = "OKAY MAYBE THIS IS GOOD NOW!?";
$url = $route->url();
$this->setActiveProject($url);
$vendors=$this->requestedVendors($url);
if ($this->isWebhookRequest($url)){
echo "webhook request";
exit;
return;
} else if ($pair=$this->requestedProjectAndVendor($url)) {
$url = $this->urlRelToBase($url);
if ($url[0]=='/')$url = substr($url,1);
$url = substr($url, strpos($url, '/'));
if ($url[0]=='/')$url = substr($url,1);
// var_dump($url);
// exit;
// var_dump(substr($this->urlRelToBase($url), strpos('/', $ur)));
// exit;
$response->content = $this->lia->view('Docu/ProjectLayout', ['docu'=>$this, 'project'=>$pair['project'],'vendor'=>$pair['vendor'],
'url'=>$url, 'router'=>$this]);
} else if ($vendors=$this->requestedVendors($url)){
foreach ($vendors as $vendor){
$response->content .= $this->lia->view('Docu/ProjectSelector', ['vendor'=>$vendor]);
}
} else {
echo "Something went wrong loading the projects...";
}
return;
}
public function route(\Lia\Obj\Request $request){
$url = $request->url();
ob_start();
$this->lia->view('Docu/Resources');
if (!$this->isRequested($url)){
return false;
}
$this->requestUrl = $url;
$route = new \Lia\Obj\Route(
[
'url' => $request->url(),
'method'=>$request->method(),
'target'=>[$this, 'deliver']
]
);
return [$route];
}
protected function setActiveProject($url){
// \Lia\JSExt\Autowire::setup($this->lia);
$relBaseUrl = $this->urlRelToBase($url);
$parts = explode('/',$relBaseUrl);
$details = array_shift($parts);
$relPath = implode('/',$parts);
$splitBranch = explode(':',$details,2);
$project = $splitBranch[0];
$mode = 'docs';
if (substr($project,-4)=='-src'){
$project = substr($project,0,-4);
$mode = 'src';
}
$projectName = $project;
if (!$this->isProjectAllowed($projectName)){
$this->handleProjectError(self::PROJECT_NOT_ALLOWED, "Project '{$projectName}' error...");
return;
}
$project = new Project($this->vendorDir.'/'.$projectName, 'idk');
$branch = $splitBranch[1] ?? $project->defaultBranch();
$this->active = (object)[
'project'=>$project,
'branch'=>$branch,
'request'=>$relPath,
'mode'=>$mode,
'file'=>$project->fileForRequest($branch,$mode,$relPath)
];
}
}