forked from projects/fipamo
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
|
@ -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()
|
||||
{
|
||||
//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,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)) {
|
||||
|
|
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 ![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;
|
||||
}
|
||||
}
|
|
@ -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…
Reference in a new issue