implemented install from scratch
activated the fresh install process for setting up a brand new fipamo install
This commit is contained in:
parent
08b79cecdf
commit
2f0e1fdc62
14 changed files with 391 additions and 23 deletions
app
Helpers
Http/Controllers
Providers
Services
public/assets
resources/views
routes
|
@ -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;
|
||||
}
|
||||
|
|
24
app/Http/Controllers/API/InitAPIController.php
Normal file
24
app/Http/Controllers/API/InitAPIController.php
Normal 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');
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,12 +6,19 @@ use App\Http\Controllers\Controller;
|
|||
|
||||
class StartController extends Controller
|
||||
{
|
||||
protected $settings;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
return response()->file('../public/index.html');
|
||||
//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"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -51,10 +51,15 @@ class DocService
|
|||
DocTools::writeSettings('../config/settings.json', $settings);
|
||||
}
|
||||
|
||||
public static function writeSettings($fileContents)
|
||||
public static function writeSettings($fileContents, $location = null)
|
||||
{
|
||||
$fileLocation = env('SETTINGS_PATH');
|
||||
$message = [];
|
||||
if (is_null($location)) {
|
||||
$fileLocation = env('SETTINGS_PATH');
|
||||
} else {
|
||||
$fileLocation = $location;
|
||||
}
|
||||
|
||||
$message = [];
|
||||
try {
|
||||
if (!is_file($fileLocation)) {
|
||||
file_put_contents($fileLocation, json_encode($fileContents));
|
||||
|
|
118
app/Services/InitService.php
Normal file
118
app/Services/InitService.php
Normal 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 \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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
9
public/assets/scripts/dash/app/Init.js
Normal file
9
public/assets/scripts/dash/app/Init.js
Normal file
|
@ -0,0 +1,9 @@
|
|||
import Init from './controllers/InitController.js';
|
||||
|
||||
document.addEventListener(
|
||||
'DOMContentLoaded',
|
||||
function () {
|
||||
new Init();
|
||||
},
|
||||
false
|
||||
);
|
127
public/assets/scripts/dash/app/controllers/InitController.js
Normal file
127
public/assets/scripts/dash/app/controllers/InitController.js
Normal 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';
|
||||
}
|
||||
}
|
||||
}
|
17
resources/views/back/init.blade.php
Normal file
17
resources/views/back/init.blade.php
Normal 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
|
15
resources/views/forms/init-fresh.blade.php
Normal file
15
resources/views/forms/init-fresh.blade.php
Normal 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>
|
16
resources/views/forms/init-restore.blade.php
Normal file
16
resources/views/forms/init-restore.blade.php
Normal 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>
|
|
@ -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']);
|
||||
|
|
Loading…
Add table
Reference in a new issue