fipamo/app/Services/Upkeep/InitService.php
ro c85e145774
added getbyIndex for pages, urlencode page titles
the theme controller was grabbing the index by its page name, which was
bad because that might change. that was replaced with a getById function
since the index id will always be 0 since it's the first page. this is a
seperate function from getByUuid which is a unique indentifier for each
page which was being used interchangably before the fix. all of those
references have been cleaned up to reference which type of id is needed

there was also a bug that happened on rendering when there were special
characters in the title. this was solved by saving the title as a
urlencoded string and then just decodded when it was needed for display
on the front end
2024-09-04 14:32:36 -06:00

287 lines
12 KiB
PHP

<?php
namespace App\Services\Upkeep;
use ReallySimpleJWT\Token;
use ReallySimpleJWT\Exception\EncodeException;
use App\Services\Assets\DocService;
use Carbon\Carbon;
use function _\find;
class InitService
{
protected $docs;
protected $filePaths = [];
public function __construct(DocService $docService)
{
$this->docs = $docService;
$this->filePaths = ['../public/assets/images/blog',
'../public/assets/images/user', '../public/assets/video/blog',
'../public/assets/docs/blog', '../public/assets/sound/blog'];
}
private static function validSecret($length)
{
$alphanum = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$special = '*&!@%^#$';
$alphabet = $alphanum . $special;
$random = openssl_random_pseudo_bytes($length);
$alphabet_length = strlen($alphabet);
$string = '';
for ($i = 0; $i < $length; ++$i) {
$string .= $alphabet[ord($random[$i]) % $alphabet_length];
}
//secret needs to be a valid token
if ($length == 12) {
try {
$secret = Token::create(12, $string, time() + 3600, 'localhost');
return $string;
} catch (EncodeException $e) {
//bad secret, so try agiain
return self::validSecret(12);
}
if (Token::validate($key, $string)) {
return $string;
} else {
return self::validSecret(12);
}
}
}
public function fresh($body)
{
//grab template files
//TODO: Remove hardcoded link and set up init path in settings
$newFolks = json_decode(
file_get_contents(env('FIPAMO_INIT') . '/folks-template.json'),
true
);
$newSettings = json_decode(
file_get_contents(env('FIPAMO_INIT') . '/settings-template.json'),
true
);
//get form values
//$body = $request->getParsedBody();
$handle = $body->new_member_handle;
$email = $body->new_member_email;
$pass = $body->new_member_pass;
$title = $body->new_member_title;
$now = Carbon::now();
//setup folks config
$hash = password_hash($pass, PASSWORD_DEFAULT);
$newFolks[0]['id'] = 0;
$newFolks[0]['handle'] = $handle;
$newFolks[0]['email'] = $email;
$newFolks[0]['password'] = $hash;
$newFolks[0]['key'] = password_hash($email, PASSWORD_DEFAULT);
$newFolks[0]['secret'] = self::validSecret(12);
$newFolks[0]['role'] = 'hnic';
$newFolks[0]['created'] = $now->format("Y-m-d\TH:i:sP");
$newFolks[0]['updated'] = $now->format("Y-m-d\TH:i:sP");
//set up settings config
$newSettings['global']['title'] = $title;
//create index file
//TODO: upate path attribute to use env variable
$index = [
'id' => 0,
'uuid' => createUUID(),
'title' => 'FIRST!',
'imageList' => '/assets/images/global/default-bg.jpg',
'fileList' => '',
'path' => 'content/pages/start',
'layout' => 'index',
'tags' => 'start, welcome',
'author' => $handle,
'created' => $now->format("Y-m-d\TH:i:sP"),
'updated' => $now->format("Y-m-d\TH:i:sP"),
'deleted' => 'false',
'slug' => 'first',
'menu' => 'false',
'featured' => 'false',
'published' => 'true',
'content' => "# F**k Yes \n\nIf you're seeing this, you're up and running. NICE WORK!\n\nFrom here, feel free to start dropping pages to your heart's content.\n\nFor some tips about using Fipamo, check out the ![docs](https://code.playvicio.us/Are0h/Fipamo/wiki/02-Usage)\n\nAll good? Feel free to edit this page to whatever you want!\n\nYOU'RE THE CAPTAIN NOW.",
];
//once all files created, write down
mkdir(env('FIPAMO_CONFIG'), 0755, true);
$this->docs->writeSettings($newSettings, env('FIPAMO_CONFIG') . '/settings.json');
$this->docs->writeSettings($newFolks, env('FIPAMO_CONFIG') . '/folks.json');
$this->docs->writeSettings([], env('FIPAMO_CONFIG') . '/tags.json');
$object = (object) $index;
$this->docs->writePages(
'create',
'start',
env('PAGES_PATH') . '/start/index.md',
$this->docs::objectToMD($object)
);
$result = ['type' => 'blogInitGood', 'message' => 'Site Created'];
return $result;
}
public function restore($request)
{
//content required, so check it
$result = [];
$contentArchive = $request->file('backup-content-upload');
$fileArchive = $request->file('backup-files-upload');
if ($contentArchive == null || $contentArchive == '') {
return $result = [
'type' => 'requestLame',
'message' => 'Content Archive EMPTY',
];
}
$result = $this->restoreContent($contentArchive, $request);
if ($result['type'] == 'requestLame') {
return $result;
}
//file upload is optional, so if it's present, restore it
if ($fileArchive != null || $fileArchive != '') {
$result = $this->restoreFiles($fileArchive);
}
return $result;
}
private function restoreContent($contentUpload, $request)
{
$contentUpload->move(env('FIPAMO_DIR') . '/', $contentUpload->getClientOriginalName());
$contentZip = new \ZipArchive();
$result = [];
$tempDir = env('FIPAMO_DIR') . '/_temp';
if ($contentZip->open(env('FIPAMO_DIR') . '/' . $contentUpload->getClientOriginalName()) === true) {
$folks = json_decode($contentZip->getFromName('config/folks.json'), true);
$found = find($folks, ['handle' => $request->restore_member_handle]);
if ($found) {
if (password_verify($request->restore_member_pass, $found['password'])) {
//restore assets from previous site
if ($request->restore_former_url != '' || $request->restore_former_url != null) {
$this->moveAssets($contentZip, $request->restore_former_url);
}
$newFolks = [];
if (!isset($found['secret'])) {
$found['secret'] = self::validSecret(12);
}
array_push($newFolks, $found);
//make temp folder and dump file in there
mkdir($tempDir, 0755, true);
$contentZip->extractTo($tempDir);
//load up old config file
$newConfig = json_decode(
file_get_contents($tempDir . '/config/settings.json'),
true
);
//check for key, add if not there
if (!isset($newConfig['global']['externalAPI'])) {
$newConfig['global']['externalAPI'] = 'false';
}
//make dir and write new config files
if (!is_dir(env('FIPAMO_CONFIG'))) {
mkdir(env('FIPAMO_CONFIG'), 0755, true);
}
$this->docs->writeSettings($newConfig, env('FIPAMO_CONFIG') . '/settings.json');
$this->docs->writeSettings($newFolks, env('FIPAMO_CONFIG') . '/folks.json');
rename($tempDir . '/config/tags.json', env('FIPAMO_CONFIG') . '/tags.json');
//move saved markdown pages
rename($tempDir . '/content/pages/', env('PAGES_PATH'));
//clean up temp dir and zip file
$this->docs::deleteFolder($tempDir);
$contentZip->close();
unlink(env('FIPAMO_DIR') . '/' . $contentUpload->getClientOriginalName());
$result = [
'type' => 'requestGood',
'message' => 'Content Restored! Redirecting',
];
} else {
$result = [
'type' => 'requestLame',
'message' => 'Check that password, champ.',
];
}
} else {
$result = [
'type' => 'requestLame',
'message' => 'Uh Oh. Check that handle',
];
}
};
return $result;
}
private function restoreFiles($filesUpload)
{
$filesUpload->move(env('FIPAMO_DIR') . '/', $filesUpload->getClientOriginalName());
$filesZip = new \ZipArchive();
$tempDir = env('FIPAMO_DIR') . '/_file_temp';
$result = [];
if ($filesZip->open(env('FIPAMO_DIR') . '/' . $filesUpload->getClientOriginalName()) === true) {
$filesZip->extractTo($tempDir);
//clear and move dir if present
foreach ($this->filePaths as $path) {
delete_directory($path, false);
//non image directories don't exist, so they need to be created
$pathing = explode("/", $path);
if ($pathing[3] != 'images') {
if (!is_dir('../public/assets/' . $pathing[3])) {
mkdir('../public/assets/' . $pathing[3]);
}
}
$tempPath = $tempDir . '/' . substr($path, 3);
if (is_dir($tempPath)) {
rename($tempPath, $path);
}
}
$result = [
'type' => 'requestGood',
'message' => 'Files & Content Restored! Redirecting',
];
}
delete_directory($tempDir);
$filesZip->close();
unlink(env('FIPAMO_DIR') . '/' . $filesUpload->getClientOriginalName());
return $result;
}
private function moveAssets($zip, $url)
{
$assetFail = 0;
$assetList = [];
array_push($assetList, json_decode($zip->getFromName('assets/blog_images.json'), true));
array_push($assetList, json_decode($zip->getFromName('assets/user_images.json'), true));
array_push($assetList, json_decode($zip->getFromName('assets/blog_docs.json'), true));
array_push($assetList, json_decode($zip->getFromName('assets/blog_videos.json'), true));
foreach ($assetList as $list) {
foreach ($list as $asset) {
$path = explode('/', $asset['path']);
$type = $path[3];
$section = $path[4];
$year = $path[5];
$month = $path[6];
$blogDir = '../public/assets/' . $type . '/' . $section . '/' . $year . '/' . $month;
if (!is_dir($blogDir)) {
mkdir($blogDir, 0755, true);
}
$externalPath = '/assets/' . $type . '/' . $section . '/' . $year . '/' . $month;
$asset_url = $url . $externalPath . '/' . $asset['file'];
try {
file_put_contents(
$asset['path'] . '/' . $asset['file'],
file_get_contents($asset_url)
);
} catch (\Throwable $e) {
$assetFail++;
}
}
}
}
}