implemented install from scratch

activated the fresh install process for setting up a brand new fipamo
install
This commit is contained in:
ro 2024-04-16 15:36:57 -06:00
parent 08b79cecdf
commit 2f0e1fdc62
No known key found for this signature in database
GPG key ID: 29B551CDBD4D3B50
14 changed files with 391 additions and 23 deletions

View file

@ -40,3 +40,18 @@ function safeString($string)
)
);
}
function randomString(int $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];
}
return $string;
}

View file

@ -0,0 +1,24 @@
<?php
namespace App\Http\Controllers\API;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Services\InitService;
class InitAPIController extends Controller
{
protected $init;
public function __construct(InitService $initService)
{
$this->init = $initService;
}
//init stuff
public function setupFresh(Request $request)
{
$result = $this->init->fresh(json_decode($request->getContent()));
return response()->json($result)->header('Content-Type', 'application/json');
}
}

View file

@ -61,4 +61,11 @@ class SettingsAPIController extends Controller
return response()->download('../content/backups/' . $file, $file, ['Content-Type: application/zip']);
}
}
//init stuff
public function setupFresh(Request $request)
{
$body = json_decode($request->getContent());
dd($body);
}
}

View file

@ -6,12 +6,19 @@ use App\Http\Controllers\Controller;
class StartController extends Controller
{
protected $settings;
public function __construct()
{
}
public function index()
{
//check if configs are present
if (file_exists(env('FOLKS_PATH')) && file_exists(env('SETTINGS_PATH'))) {
return response()->file('../public/index.html');
} else {
return view('back.init', ["status" => false, "title" => "Set Up"]);
}
}
}

View file

@ -16,6 +16,7 @@ use App\Services\RenderService;
use App\Services\SortingService;
use App\Services\AssetService;
use App\Services\MaintenanceService;
use App\Services\InitService;
class FipamoServiceProvider extends ServiceProvider
{
@ -86,6 +87,10 @@ class FipamoServiceProvider extends ServiceProvider
new SettingsService(new DocService(), new ContentService())
);
});
$this->app->bind(InitService::class, function ($app) {
return new InitService(new DocService());
});
}
/**

View file

@ -51,9 +51,14 @@ class DocService
DocTools::writeSettings('../config/settings.json', $settings);
}
public static function writeSettings($fileContents)
public static function writeSettings($fileContents, $location = null)
{
if (is_null($location)) {
$fileLocation = env('SETTINGS_PATH');
} else {
$fileLocation = $location;
}
$message = [];
try {
if (!is_file($fileLocation)) {

View file

@ -0,0 +1,118 @@
<?php
namespace App\Services;
use ReallySimpleJWT\Token;
use ReallySimpleJWT\Exception\BuildException;
use Carbon\Carbon;
class InitService
{
protected $docs;
public function __construct(DocService $docService)
{
$this->docs = $docService;
}
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 (BuildException $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
$newFolks = json_decode(
file_get_contents('../content/config/init/folks-template.json'),
true
);
$newSettings = json_decode(
file_get_contents('../content/config/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
$index = [
'id' => 1,
'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
$this->docs->writeSettings($newSettings, '../content/config/settings.json');
$this->docs->writeSettings($newFolks, '../content/config/folks.json');
$this->docs->writeSettings([], '../content/config/tags.json');
$object = (object) $index;
$this->docs->writePages(
'create',
'start',
'../content/pages/start/index.md',
$this->docs::objectToMD($object)
);
$result = ['type' => 'blogInitGood', 'message' => 'Site Created'];
return $result;
}
}

View file

@ -1,9 +1,9 @@
/* LOGIN */
section.login,
section[role="password-reset"],
section[role="restore-fresh"],
section[role="restore-backup"] {
section.password-reset,
section.restore-fresh,
section.restore-backup {
margin: 15% auto;
padding: 10px;
width: 500px;
@ -14,7 +14,7 @@ section[role="restore-backup"] {
visibility: visible;
}
section[role="restore-backup"] {
section.restore-backup {
display: none;
visibility: hidden;
color: var(--white);
@ -47,12 +47,12 @@ section.login form a {
/* PASSWORD-RESET */
section[role="password-reset"] form button {
section.password-reset form button {
padding: 10px 5px;
width: 82%;
}
section[role="password-reset"] form input {
section.password-reset form input {
width: 95%;
height: 30px;
padding: 5px;
@ -61,24 +61,24 @@ section[role="password-reset"] form input {
/* SITE RESTORE */
section[role="restore-fresh"] form button {
section.restore-fresh form button {
padding: 10px 5px;
width: 82%;
}
section[role="restore-fresh"] form input {
section.restore-fresh form input {
width: 95%;
height: 30px;
padding: 5px;
margin-bottom: 10px;
}
section[role="restore-backup"] form button {
section.restore-backup form button {
padding: 10px 5px;
width: 82%;
}
section[role="restore-backup"] form input {
section.restore-backup form input {
width: 95%;
height: 30px;
padding: 5px;
@ -89,25 +89,25 @@ section[role="restore-backup"] form input {
@media only screen and (max-width: 500px) {
section.login,
section[role="password-reset"],
section[role="restore-fresh"],
section[role="restore-backup"] {
section.password-reset,
section.restore-fresh,
section.restore-backup {
width: 97%;
}
}
@media only screen and (max-width: 375px) {
section.login,
section[role="password-reset"],
section[role="restore-fresh"],
section[role="restore-backup"] {
section.password-reset,
section.restore-fresh,
section.restore-backup {
grid-template-columns: 1fr;
}
section.login img,
section[role="password-reset"] img,
section[role="restore-fresh"] img,
section[role="restore-backup"] img {
section.password-reset img,
section.restore-fresh img,
section.restore-backup img {
width: 50px;
}
}

View file

@ -0,0 +1,9 @@
import Init from './controllers/InitController.js';
document.addEventListener(
'DOMContentLoaded',
function () {
new Init();
},
false
);

View file

@ -0,0 +1,127 @@
import FipamoAdminAPI from '../../libraries/FipamoAdminAPI.js';
import Maintenance from './MaintenanceManager.js';
import DataUitls from '../utils/DataUtils.js';
import * as DataEvent from '../events/DataEvent.js';
import Notfications from '../ui/Notifications.js';
const data = new DataUitls();
const notify = new Notfications();
export default class InitController {
//--------------------------
// constructor
//--------------------------
constructor() {
this.processing = false;
this.start();
}
//--------------------------
// methods
//--------------------------
//TODO: Move init functions and set up to their own class
start() {
if (document.getElementById('login') || document.querySelector('.site-restore')) {
var options = document.getElementsByClassName('init-option');
for (let index = 0; index < options.length; index++) {
options[index].addEventListener('click', e => this.handleOptions(e));
}
if (document.getElementById('login')) {
document
.getElementById('login-btn')
.addEventListener('click', e => this.handleLogin(e));
} else {
document
.getElementById('init-blog')
.addEventListener('click', e => this.handleSetup(e));
document
.getElementById('blog-restore')
.addEventListener('click', e => this.handleRestore(e));
}
} else if (document.getElementById('dash-reset')) {
document
.getElementById('get-secret-btn')
.addEventListener('click', e => this.handleReset(e));
document
.getElementById('reset-btn')
.addEventListener('click', e => this.handleReset(e));
}
}
//--------------------------
// event handlers
//--------------------------
handleSetup(e) {
if (this.processing) return;
let self = this;
e.stopPropagation();
e.preventDefault();
let setUpForm = data.formDataToJSON(document.getElementById('init-form'));
let mm = new Maintenance();
this.processing = true;
mm.create(setUpForm)
.then(response => {
if (response.type === DataEvent.API_INIT_LAME) {
self.processing = false;
e.target.innerHTML = response.message;
} else {
self.processing = false;
e.target.innerHTML = response.message;
setTimeout(() => {
window.location = '/dashboard';
}, 700);
}
})
.catch(err => {
self.processing = false;
//notify.alert(err, false);
});
}
handleRestore(e) {
if (this.processing) return;
let self = this;
e.stopPropagation();
e.preventDefault();
let mm = new Maintenance();
var form = document.getElementById('init-restore');
this.processing = true;
mm.restore(form)
.then(response => {
if (response.type === DataEvent.REQUEST_LAME) {
self.processing = false;
e.target.innerHTML = response.message;
} else {
self.processing = false;
e.target.innerHTML = response.message;
setTimeout(() => {
window.location = '/dashboard';
}, 1500);
}
})
.catch(err => {
self.processing = false;
e.target.innerHTML = err;
});
}
handleOptions(e) {
e.stopPropagation();
e.preventDefault();
let init = document.querySelector('.restore-fresh');
let restore = document.querySelector('.restore-backup');
if (e.target.id === 'init-switch-restore') {
init.style.display = 'none';
init.style.visibility = 'hidden';
restore.style.display = 'grid';
restore.style.visibility = 'visible';
} else {
init.style.display = 'grid';
init.style.visibility = 'visible';
restore.style.display = 'none';
restore.style.visibility = 'hidden';
}
}
}

View file

@ -0,0 +1,17 @@
@extends('frame')
@section('title', 'The Dash | Set Up Fipamo')
@section('main-content')
<article class="site-restore">
<section class="restore-fresh">
@include('forms.init-fresh')
</section>
<section class="restore-backup">
@include('forms.init-restore')
</section>
</article>
@endsection
@section('scripting')
<script type="module" src="/assets/scripts/dash/app/Init.js"></script>
@endsection

View file

@ -0,0 +1,15 @@
<div>
<a href="/dashboard">
<img class="logo-medium" src="/assets/images/global/fipamo-logo-secondary.svg"/>
</a>
</div>
<form id="init-form" method="POST" onsubmit="return false;">
<input type="text" name="new_member_handle" id="new_member_handle" placeholder="handle"/>
<input type="text" name="new_member_email" id="new_member_email" placeholder="email"/>
<input type="text" name="new_member_pass" id="new_member_pass" placeholder="password"/>
<input type="text" name="new_member_pass2" id="new_member_pass2" placeholder="password confirm"/>
<input type="text" name="new_member_title" id="new_member_title" placeholder="title"/>
<button id="init-blog" data-action='blog-init' type='submit'>SET UP YOUR SITE</button>
<br/><br/>
<button class="init-option" id="init-switch-restore">RESTORE FROM BACKUP</button>
</form>

View file

@ -0,0 +1,16 @@
<div>
<a href="/dashboard">
<img class="logo-medium" src="/assets/images/global/fipamo-logo-secondary.svg"/>
</a>
</div>
<form id="init-restore" method="POST">
<input type="text" name="restore_member_handle" id="restore_member_handle" placeholder="handle"/><input type="password" name="restore_member_pass" id="restore_member_pass" placeholder="password"/>
<div>
<label>Grab your backup zip</label>
<input id="backup-upload" type="file" name="backup-upload" placeholder="Backup Zip"/>
</div>
<br/><br/>
<button id="blog-restore" data-action='blog-restore' type='submit'>RESTORE</button>
<br/><br/>
<button class="init-option" id="init-switch-fresh">OR INSTALL FROM SCRATCH</button>
</form>

View file

@ -5,6 +5,7 @@ use App\Http\Controllers\API\AuthAPIController;
use App\Http\Controllers\API\PageAPIController;
use App\Http\Controllers\API\FileUploadAPIController;
use App\Http\Controllers\API\SettingsAPIController;
use App\Http\Controllers\API\InitAPIController;
/*
|--------------------------------------------------------------------------
@ -30,3 +31,5 @@ Route::put("/v1/settings/sync", [SettingsAPIController::class, 'sync']);
Route::put("/v1/settings/nav-sync", [SettingsAPIController::class, 'navSync']);
Route::put("/v1/backup/create", [SettingsAPIController::class, 'createBackup']);
Route::get("/v1/backup/download", [SettingsAPIController::class, 'downloadBackup']);
//init
Route::post("/v1/init", [InitAPIController::class, 'setupFresh']);