API Decouplng Part 2

removed all remaining API requests from the front end and removed the
FipamoAdminAPI js file, changing it to ContentRequest as it now handles
posting data to the system directly, authenticating it self by checking
the embedded CSRF token that regulary rotates

also renamed MaintenanceManager to Maintenance request and moved it to
the same dir as ContentRequest as they are both libraries that connect
to the backend
This commit is contained in:
ro 2024-07-17 15:08:10 -06:00
parent 3d17771f76
commit c5afbb9131
No known key found for this signature in database
GPG key ID: 29B551CDBD4D3B50
15 changed files with 176 additions and 132 deletions

View file

@ -3,6 +3,7 @@
namespace App\Http\Controllers;
use App\Interfaces\MemberRepositoryInterface;
use App\Services\Data\SettingsService;
class RouteGetController extends Controller
{
@ -11,6 +12,7 @@ class RouteGetController extends Controller
protected $theme;
protected $front;
protected $member;
protected $settings;
public function __construct(
DashController $dashController,
@ -18,12 +20,14 @@ class RouteGetController extends Controller
ThemeController $themeController,
FrontController $frontController,
MemberRepositoryInterface $memberRepo,
SettingsService $settingsService,
) {
$this->dash = $dashController;
$this->gate = $authController;
$this->theme = $themeController;
$this->front = $frontController;
$this->member = $memberRepo;
$this->dash = $dashController;
$this->gate = $authController;
$this->theme = $themeController;
$this->front = $frontController;
$this->member = $memberRepo;
$this->settings = $settingsService;
}
public function handleRequest($first = null, $second = null, $third = null, $fourth = null)
@ -52,9 +56,33 @@ class RouteGetController extends Controller
case 'archives':
return $this->front->page($first, $second, $third);
break;
case 'backup':
return $this->downloadBackup($second);
break;
}
} else {
return $this->front->index($first, $second, $third);
}
}
private function downloadBackup($type)
{
if ($this->member::status()) {
$latest = '';
$file = '';
if ($type == 'content-download') {
$latest = $this->settings->getGlobal()['last_content_backup'];
$file = 'backup-content-' . $latest . '.zip';
} else {
$latest = $this->settings->getGlobal()['last_files_backup'];
$file = 'backup-files-' . $latest . '.zip';
}
return response()->download(
'../content/backups/' . $file,
$file,
['Content-Type: application/zip']
);
}
}
}

View file

@ -6,23 +6,51 @@ use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
use App\Mail\SystemEmail;
use App\Interfaces\PageRepositoryInterface;
use App\Services\Upkeep\MaintenanceService;
use App\Services\Assets\FileUploadService;
use App\Interfaces\MemberRepositoryInterface;
use App\Services\Data\SettingsService;
use App\Services\UpKeep\InitService;
use App\Services\UpKeep\ResetService;
class RoutePostController extends Controller
{
protected $page;
protected $gate;
protected $maintenance;
protected $upload;
protected $settings;
protected $member;
protected $init;
protected $reset;
public function __construct(
PageRepositoryInterface $pageRepo,
AuthController $authController,
MaintenanceService $maintenanceService,
FileUploadService $fileUploadService,
SettingsService $settingsService,
MemberRepositoryInterface $memberRepo,
InitService $initService,
ResetService $resetService,
) {
$this->page = $pageRepo;
$this->gate = $authController;
$this->page = $pageRepo;
$this->gate = $authController;
$this->maintenance = $maintenanceService;
$this->upload = $fileUploadService;
$this->settings = $settingsService;
$this->member = $memberRepo;
$this->init = $initService;
$this->reset = $resetService;
}
public function handleRequest(Request $request)
{
$path = explode('/', $request->path());
switch ($path[0]) {
case 'init':
return $this->initTask($path[1], $request);
break;
case 'login':
return $this->gate->enter($request);
break;
@ -36,9 +64,44 @@ class RoutePostController extends Controller
return $this->sendNotify($request);
}
break;
case 'upload':
$type = null;
$result = $result = $this->upload->handleFile($request, $type);
//update configs for specfic uploads
switch ($request['source']) {
case 'avatar-upload':
$member = [];
$member = session('member');
$member['avatar'] = $result['filePath'];
$member = (object) $member;
$this->member->update($member);
break;
case 'background-upload':
$this->settings->updateGlobalData('background', $result['filePath']);
break;
}
return $result;
break;
}
}
private function initTask($task, $request)
{
$result = [];
switch ($task) {
case 'fresh':
$result = $this->init->fresh(json_decode($request->getContent()));
break;
case 'restore':
$result = $this->init->restore($request);
break;
case 'reset':
$result = $this->reset->site($request);
break;
}
return response()->json($result)->header('Content-Type', 'application/json');
}
private function sendNotify($request)
{
$result = [];

View file

@ -7,6 +7,7 @@ use App\Services\Assets\AssetService;
use App\Services\Assets\RenderService;
use App\Interfaces\MemberRepositoryInterface;
use App\Services\Data\SettingsService;
use App\Services\Upkeep\MaintenanceService;
use Illuminate\Http\Request;
class RoutePutController extends Controller
@ -16,6 +17,7 @@ class RoutePutController extends Controller
protected $render;
protected $settings;
protected $member;
protected $maintenance;
public function __construct(
PageRepositoryInterface $pageRepo,
@ -23,12 +25,14 @@ class RoutePutController extends Controller
RenderService $renderService,
SettingsService $settingsService,
MemberRepositoryInterface $memberRepo,
MaintenanceService $maintenanceService,
) {
$this->page = $pageRepo;
$this->assets = $assetService;
$this->render = $renderService;
$this->settings = $settingsService;
$this->member = $memberRepo;
$this->page = $pageRepo;
$this->assets = $assetService;
$this->render = $renderService;
$this->settings = $settingsService;
$this->member = $memberRepo;
$this->maintenance = $maintenanceService;
}
public function handleRequest(Request $request)
@ -43,6 +47,23 @@ class RoutePutController extends Controller
case 'settings':
return $this->settingsTasks($request, $path[1]);
break;
case 'backup':
return $this->createBackup($request);
break;
}
}
private function createBackup($request)
{
$body = json_decode($request->getContent());
if ($body->task == 'content_backup') {
return response()->json(
$this->maintenance->createContentBackUp()
)->header('Content-Type', 'application/json');
} else {
return response()->json(
$this->maintenance->createFileBackUp()
)->header('Content-Type', 'application/json');
}
}

View file

@ -21,7 +21,7 @@ class MaintenanceService
public function createContentBackUp()
{
//make sure back directory is there
$stamp = Carbon::now()->format("YmdGis");
$stamp = Carbon::now()->format("YmdHis");
if (!is_dir(env('FIPAMO_BACKUPS'))) {
mkdir(env('FIPAMO_BACKUPS'), 0755, true);
}
@ -130,7 +130,7 @@ class MaintenanceService
public function createFileBackUp()
{
$stamp = Carbon::now()->format("YmdGis");
$stamp = Carbon::now()->format("YmdHis");
$zip = new \ZipArchive();
$zip->open(
env('FIPAMO_BACKUPS') . '/backup-files-' . $stamp . '.zip',

View file

@ -1,4 +1,4 @@
import FipamoAdminAPI from '../../libraries/FipamoAdminAPI.js';
import ContentRequest from '../../libraries/ContentRequest.js';
import Notficaton from '../ui/Notifications.js';
const notify = new Notficaton();
export default class Mailer {
@ -20,7 +20,7 @@ export default class Mailer {
content: text,
mail_task: task
};
let admin = new FipamoAdminAPI();
let admin = new ContentRequest();
admin
.sendMail(mailData)
.then(result => {

View file

@ -1,44 +0,0 @@
import PostIndex from './PostIndex';
import SettingsIndex from './SettingsIndex';
import NaviIndex from './NavIndex';
import Menu from '../ui/Menu';
export default class DashManager {
//--------------------------
// constructor
//--------------------------
constructor() {
this.currentDisplay = '';
this.urlPieces = document.URL.split('/');
this.chooseDisplay(this.urlPieces[4], this.urlPieces[5]);
//start main menu handler
new Menu();
}
//--------------------------
// methods
//--------------------------
start() {}
chooseDisplay(section, page) {
this.currentDisplay = '';
switch (section) {
case 'page':
this.currentDisplay = new PostIndex(page);
break;
case 'settings':
this.currentDisplay = new SettingsIndex();
break;
case 'navigation':
this.currentDisplay = new NaviIndex();
break;
default:
//just chill
break;
}
this.start();
}
//--------------------------
// event handlers
//--------------------------
}

View file

@ -1,5 +1,5 @@
import FipamoAdminAPI from '../../libraries/FipamoAdminAPI.js';
import Maintenance from './MaintenanceManager.js';
import ContentRequest from '../../libraries/ContentRequest.js';
import Maintenance from '../../libraries/MaintenanceRequest.js';
import DataUitls from '../utils/DataUtils.js';
import * as DataEvent from '../events/DataEvent.js';
import Notfications from '../ui/Notifications.js';

View file

@ -1,4 +1,4 @@
import FipamoAdminAPI, { TASK_SYNC_NAV } from '../../libraries/FipamoAdminAPI.js';
import ContentRequest, { TASK_SYNC_NAV } from '../../libraries/ContentRequest.js';
import NavActions from '../actions/NavActions.js';
import * as DataEvent from '../events/DataEvent.js';
import Notifications from '../ui/Notifications.js';
@ -11,7 +11,7 @@ export default class NavIndex {
//--------------------------
constructor() {
this.processing = false;
this.admin = new FipamoAdminAPI(null);
this.cr = new ContentRequest(null);
this.start();
}
//--------------------------
@ -24,7 +24,7 @@ export default class NavIndex {
onUpdate: () => {
new NavActions().syncMenu().then(data => {
notify.alert('Updating Menu', null);
self.admin.sync(TASK_SYNC_NAV, data).then(r => {
self.cr.sync(TASK_SYNC_NAV, data).then(r => {
if (r.type == DataEvent.MENU_UPDATED) {
notify.alert(r.message, true);
} else {
@ -55,7 +55,7 @@ export default class NavIndex {
data.remove = e.target.getAttribute('data-uuid');
notify.alert('Editing Menu', null);
self.processing = true;
self.admin.sync(TASK_SYNC_NAV, data).then(r => {
self.cr.sync(TASK_SYNC_NAV, data).then(r => {
self.processing = false;
if (r.type == DataEvent.MENU_UPDATED) {
notify.alert(r.message, true);

View file

@ -1,10 +1,10 @@
//TOOLS
import FipamoAdminAPI, {
import ContentRequest, {
TASK_PAGE_CREATE,
TASK_PAGE_EDIT,
TASK_PAGE_DELETE
} from '../../libraries/FipamoAdminAPI.js';
import Maintenance from './MaintenanceManager.js';
} from '../../libraries/ContentRequest.js';
import Maintenance from '../../libraries/MaintenanceRequest.js';
import * as DataEvent from '../events/DataEvent.js';
import PageActions from '../actions/PageActions.js';
import * as EditorEvent from '../events/EditorEvent.js';
@ -19,8 +19,8 @@ export default class PostEditor {
constructor() {
this.processing = false;
let self = 'this';
this.admin = new FipamoAdminAPI(null, document.getElementById('notify-progress'));
this.mm = new Maintenance(null, null);
this.cr = new ContentRequest(null, document.getElementById('notify-progress'));
this.mr = new Maintenance(null, null);
this.urlPieces = document.URL.split('/');
this.post = [];
this.postID = null;
@ -145,7 +145,7 @@ export default class PostEditor {
new PageActions().collectInfo(this.fm.getFileOrder()).then(page => {
self.processing = true;
notify.alert('Writing down changes', null);
self.admin
self.cr
.pageActions(task, page)
.then(r => {
self.processing = false;
@ -179,7 +179,7 @@ export default class PostEditor {
.collectInfo(this.fm.getFileOrder())
.then(page => {
self.processing = true;
this.admin
this.cr
.pageActions(TASK_PAGE_DELETE, page)
.then(() => {
self.processing = false;
@ -207,7 +207,7 @@ export default class PostEditor {
let upload = new FormData();
upload.enctype = 'multipart/form-data';
upload.append('upload_files[]', files[0], files[0].name);
this.mm
this.mr
.filesUpload(files[0].type, upload)
.then(result => {
if (result.message == 'File Uploaded. Great!') {

View file

@ -1,6 +1,6 @@
import SettingsActions from '../actions/SettingsActions.js';
import Maintenance from './MaintenanceManager.js';
import FipamoAdminAPI, { TASK_SYNC_SETTNIGS } from '../../libraries/FipamoAdminAPI.js';
import Maintenance from '../../libraries/MaintenanceRequest.js';
import ContentRequest, { TASK_SYNC_SETTNIGS } from '../../libraries/ContentRequest.js';
import * as DataEvent from '../../../dash/app/events/DataEvent.js';
import Mailer from '../actions/Mailer.js';
import Notifications from '../ui/Notifications.js';
@ -12,8 +12,8 @@ export default class SettingsIndex {
constructor() {
this.processing = false;
this.start();
this.admin = new FipamoAdminAPI(null);
this.mm = new Maintenance(null, null);
this.cr = new ContentRequest(null);
this.mr = new Maintenance(null, null);
}
//--------------------------
// methods
@ -26,7 +26,7 @@ export default class SettingsIndex {
.getInfo()
.then(data => {
notify.alert('Saving Settings', null);
self.admin.sync(TASK_SYNC_SETTNIGS, data).then(r => {
self.cr.sync(TASK_SYNC_SETTNIGS, data).then(r => {
if (r.type == DataEvent.SETTINGS_UPDATED) {
notify.alert(r.message, true);
} else {
@ -98,7 +98,7 @@ export default class SettingsIndex {
'This cannot be undone, so please confirm.'
)
) {
this.mm
this.mr
.reset()
.then(r => {
if (r.type == 'COOL') {
@ -223,7 +223,7 @@ export default class SettingsIndex {
upload.append('source', type);
upload.append('upload_files[]', files[0], files[0].name);
this.mm
this.mr
.filesUpload(files[0].type, upload)
.then(r => {
if (type == 'avatar-upload') {
@ -248,7 +248,7 @@ export default class SettingsIndex {
let task = { task: 'PUBLISH_ALL' };
this.processing = true;
notify.alert('Publishing site...', null);
this.admin
this.cr
.publish(task)
.then(r => {
self.processing = false;
@ -274,7 +274,7 @@ export default class SettingsIndex {
notify.alert('Creating File Backup', null);
type = { task: 'file_backup' };
}
this.mm
this.mr
.backup(type)
.then(r => {
notify.alert(r.message, true);
@ -292,7 +292,7 @@ export default class SettingsIndex {
let task = { task: 'cleanup pages indexes' };
this.processing = true;
notify.alert('Cleaning up page indexes', null);
this.admin
this.cr
.handleReindex(task)
.then(r => {
self.processing = false;

View file

@ -2,7 +2,7 @@ import Sortable from '../vendor/sortable.core.esm.js';
import anime from '../vendor/anime.es.js';
import DataUtils from '../utils/DataUtils.js';
import Notfications from './Notifications.js';
import Maintenance from '../controllers/MaintenanceManager.js';
import Maintenance from '../../libraries/MaintenanceRequest.js';
const notify = new Notfications();
export default class FileManager {
@ -10,7 +10,7 @@ export default class FileManager {
// constructor
//--------------------------
constructor(upload, input, imageList, fileList) {
this.mm = new Maintenance(null, null, document.getElementById('notify-progress'));
this.mr = new Maintenance(null, null, document.getElementById('notify-progress'));
this.upload = upload;
this.input = input;
this.imageList = imageList;
@ -115,7 +115,7 @@ export default class FileManager {
progress = document.getElementById(
'pgs' + item.getAttribute('id')
);
self.mm
self.mr
.filesUpload(theFile.type, upload, progress)
.then(result => {
item.setAttribute('data-id', result.filePath);
@ -140,7 +140,7 @@ export default class FileManager {
progress = document.getElementById(
'pgs' + item.getAttribute('id')
);
self.mm
self.mr
.filesUpload(theFile.type, upload, progress)
.then(result => {
item.setAttribute('data-id', result.filePath);
@ -166,7 +166,7 @@ export default class FileManager {
progress = document.getElementById(
'pgs' + item.getAttribute('id')
);
self.mm
self.mr
.filesUpload(theFile.type, upload, progress)
.then(result => {
item.setAttribute('data-id', result.filePath);
@ -195,7 +195,7 @@ export default class FileManager {
progress = document.getElementById(
'pgs' + item.getAttribute('id')
);
self.mm
self.mr
.filesUpload(theFile.type, upload, progress)
.then(result => {
item.setAttribute('data-id', result.filePath);

View file

@ -41,7 +41,7 @@ export const API_ACCESS_BAD = 'apiUseNotAuthorized';
* A can of methods used to edit install settings, navigation pages and content pages
*/
class FipamoAdminAPI {
class ContentRequest {
/**
* @constructor
* @param {string} baseURL - url of site; uses local when empty
@ -413,4 +413,4 @@ class FipamoAdminAPI {
}
}
export { FipamoAdminAPI as default };
export { ContentRequest as default };

View file

@ -7,19 +7,16 @@ export const REQUEST_TYPE_DELETE = 'DELETE';
export const CONTENT_TYPE_JSON = 'json';
export const CONTENT_TYPE_FORM = 'x-www-form-urlencoded';
//** API URLS **//
export const API_STATUS = '/api/v1/status';
export const API_INIT = '/api/v1/init';
export const API_RESTORE = '/api/v1/restore';
export const API_RESET = '/api/v1/reset';
export const API_GET_SECRET = '/api/v1/get-secret';
export const API_RESET_PASS = '/api/v1/reset-password';
export const API_CREATE_BACKUP = '/api/v1/backup/create';
export const API_DOWNLOAD_BACKUP = '/api/v1/backup/download';
export const API_RESTORE_BACKUP = '/api/v1/backup/restore';
export const API_UPLOAD_AVATAR = '/api/v1/settings/add-avatar';
export const API_UPLOAD_BACKGROUND = '/api/v1/settings/add-feature-background';
export const API_IMAGE_UPLOAD = '/api/v1/page/add-entry-image';
export const API_FILES_UPLOAD = '/api/v1/files';
export const API_INIT = '/init/fresh';
export const API_RESTORE = '/init/restore';
export const API_RESET = '/init/reset';
export const API_CREATE_BACKUP = '/backup/create';
export const API_DOWNLOAD_BACKUP = '/backup/download';
export const API_RESTORE_BACKUP = '/backup/restore';
export const API_FILES_UPLOAD = '/upload/files';
//export const API_RESET_PASS = '/api/v1/reset-password';
//** API TASKS **//
export const TASK_SITE_INIT = 'blogInit';
export const TASK_BACKUP_RESTORE = 'restoreBackup';
@ -58,19 +55,6 @@ class MaintenanceManager {
this.key = null;
if (key) this.key = key;
if (baseURL) this.baseURL = baseURL;
//if key is valid, checks to see if a session is active and returns
this._request(
this.baseURL
? this.baseURL + API_STATUS + '?key=' + this.key
: API_STATUS + '?key=' + this.key
).then(response => {
if (response.type === API_ACCESS_GOOD) {
this.token = response.token;
} else {
//don't set token
//console.log("NO TOKEN");
}
});
}
/**
@ -271,6 +255,10 @@ class MaintenanceManager {
self.handleLoadProgress(e, progressBar)
);
request.open(requestType, requestURL, true);
request.setRequestHeader(
'X-CSRF-TOKEN',
document.querySelector('meta[name="csrf-token"]').content
);
request.onload = () => {
if (request.status == 200) {
let response = JSON.parse(request['response']);
@ -281,14 +269,6 @@ class MaintenanceManager {
}
};
if (requestType == REQUEST_TYPE_PUT || requestType == REQUEST_TYPE_POST) {
if (
eventType === TASK_UPLOAD_FILES ||
eventType === TASK_BACKUP_CREATE ||
eventType === TASK_SITE_INIT
) {
request.setRequestHeader('fipamo-access-token', self.token);
}
switch (contentType) {
case CONTENT_TYPE_JSON:
request.setRequestHeader(

View file

@ -100,7 +100,7 @@
<span>
@if($lastContentBackup != '')
MOST RECENT:
<a href="/api/v1/backup/content-download">{{ $lastContentBackup }}</a><br/>
<a href="/backup/content-download">{{ $lastContentBackup }}</a><br/>
@else
<span>span No back ups. Frowny face.</span>
@endif
@ -116,7 +116,7 @@
<span>
@if($lastFilesBackup != '')
MOST RECENT:
<a href="/api/v1/backup/files-download">{{ $lastFilesBackup }}</a><br/>
<a href="/backup/files-download">{{ $lastFilesBackup }}</a><br/>
@else
<span>span No back ups. Frowny face.</span>
@endif

View file

@ -1,7 +1,6 @@
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\API\AuthAPIController;
use App\Http\Controllers\API\PageAPIController;
use App\Http\Controllers\API\FileUploadAPIController;
use App\Http\Controllers\API\SettingsAPIController;
@ -19,9 +18,6 @@ use App\Http\Controllers\API\MailAPIController;
|
*/
//check if session is active
Route::get("/v1/status", [AuthAPIController::class, 'status']);
//site setup
Route::post("/v1/init", [InitAPIController::class, 'setupFresh']);
Route::post("/v1/restore", [InitAPIController::class, 'setupRestore']);