Skip to content

Commit

Permalink
Update the Laravel programing style to be able to update the containe…
Browse files Browse the repository at this point in the history
…r bindings.
  • Loading branch information
austinkregel committed Feb 17, 2024
1 parent 51df4d5 commit 30e69f2
Show file tree
Hide file tree
Showing 11 changed files with 132 additions and 25 deletions.
33 changes: 20 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,43 @@ Spork is a personal multi-tool, a place to let my creativity run while and autom
# How do I run it?
If you'd like to get this project up and running, it's pretty straight forward using docker and Laravel sail. Other deployment methods are not supported officially, but will likely work with little issue. I deploy this personally using Laravel Forge.

(This bin/sail script will automatically run composer install the first time if sail isn't installed already)
```bash
$ docker run --rm --pull=always -v "$(pwd)":/opt -w /opt laravelsail/php82-composer:latest bash -c "composer install"
$ ./sail up -d
$ ./bin/sail up -d
```
(On Mac or Linux)


# What does it do? Features?
- [x] Syncing domains from Namecheap
- [x] Syncing servers from Laravel Forge
- [x] Syncing registrar domains from Cloudflare
- [x] Syncing zones from Cloudflare
- [x] Dynamic routes and domains via a page editor
- [x] RSS Syncing & updating
- [x] DNS Validation/Verification
- [x] Projects, with relations to domains, servers, rss feeds, pages (and redirects), and people in a one to many association for organization.
- [-] Automatically adding and configuring purchased domains to Cloudflare & Laravel Forge, and provision out the routing automatically. (Still in progress)
- [x] Automatic SSL configuration via forge.
- [x] Projects, with relations to domains, servers, rss feeds, pages (and redirects), and people.
- [x] SSL configuration via forge.
- [x] Adding and configuring purchased domains to Cloudflare & Laravel Forge, and provision out the routing automatically. (Still in progress)
- [x] Plaid integration for asset syncing
- [x] Task management, tasks are created per project
- [x] Email syncing via IMAP
- [x] Tagging for Transactions based on manually defined rules
- [x] Fetching Weather for a location
- [x] A programmatic code editing system, which allows for mass refactoring based on programmatic logic; and a limited interface for controlling event listeners (controlling container bindings is a WIP).
- [x] Jira task syncing
- [x] Running scripts on servers remotely
- [x] Beeper authentication via Email Token


## Planned
- [ ] Built in [matrix.org client](https://matrix.org) I actually have code written in `docker/matrix-bot` to facilitate this, but I've been unsuccessful getting end-to-end encryption working.
- [ ] Dynamic routes and domains via a page editor
- [ ] IFTTT inspired Dynamic Automations
- [x] Plaid integration for asset syncing
- [-] Budgeting per project
- [ ] Budgeting per project
- [ ] Built-in project researching for Scholarly articles and browsing the web.
- [ ] Calendar integration for project and site wide events
- [ ] Task management, tasks are created per project
- [ ] Personal Dashboard
- [ ] List tasks from all projects
- [ ] List events from all projects
- [ ] List budget usage -- if applicable.
- [ ] Domain Purchasing and Renewals


- Single Chat interface
- Email interface
4 changes: 2 additions & 2 deletions app/Jobs/FetchResourcesFromCredentials.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ public function handle(QueueingDispatcher $dispatcher)
$credentials = Credential::all();

$jobs = $credentials->groupBy('user_id')
->map(fn (Collection $group) => $group->map(fn ($credential) => new FetchResourcesFromCredential($credential))->toArray()
)->toArray();
->map(fn (Collection $group) => $group->map(fn ($credential) => new FetchResourcesFromCredential($credential))->toArray())
->toArray();

$dispatcher->batch($jobs)
->name('Updatch Resources From Credentials')
Expand Down
9 changes: 9 additions & 0 deletions app/Models/Message.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,13 @@ public function to()
{
return $this->hasManyJson(Person::class, 'emails', 'to_email');
}

public function broadcastWith(string $event): array
{
$data = $this->toArray();
unset($data['html_message']);
unset($data['message']);

return $data;
}
}
4 changes: 1 addition & 3 deletions app/Providers/HorizonServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@ public function boot(): void
protected function gate(): void
{
Gate::define('viewHorizon', function ($user) {
return in_array($user->email, [
'[email protected]',
]);
return in_array($user->email, explode(',', env('SPORK_ADMIN_EMAILS', '')));
});
}
}
2 changes: 1 addition & 1 deletion app/Providers/RouteServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class RouteServiceProvider extends ServiceProvider
*
* @var string
*/
public const HOME = '/dashboard';
public const HOME = '/-/dashboard';

/**
* Define your route model bindings, pattern filters, and other route configuration.
Expand Down
1 change: 1 addition & 0 deletions app/Services/Code.php
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ public static function instancesOf(string $desiredParentClass): static
interface_exists($desiredParentClass) => array_values(array_filter(array_merge($interfaces, $classes), fn ($declaredClass) => isset(class_implements($declaredClass)[$desiredParentClass]))),
class_exists($desiredParentClass) => array_values(array_filter($classes, fn ($declaredClass) => is_subclass_of($declaredClass, $desiredParentClass))),
trait_exists($desiredParentClass) => array_values(array_filter(array_merge($traits, $classes), fn ($declaredClass) => in_array($desiredParentClass, trait_uses_recursive($declaredClass)))),
default => dd($desiredParentClass),
};

return new static($possibleInstances);
Expand Down
61 changes: 61 additions & 0 deletions app/Services/Programming/LaravelProgrammingStyle.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@

use App\Contracts\LogicalEvent;
use App\Contracts\LogicalListener;
use App\Providers\AppServiceProvider;
use App\Services\Code;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Str;
use Nette\InvalidArgumentException;
use Nette\PhpGenerator\Dumper;
use Nette\PhpGenerator\Literal;
Expand Down Expand Up @@ -368,6 +371,52 @@ protected function recurseGetUnionType(\ReflectionNamedType|\ReflectionUnionType
}, []);
}

public function getMethod(string $methodName)
{
foreach ($this->phpFiles as $phpFile) {
/**
* @var string $namespaceName
* @var PhpNamespace $namespace
*/
foreach ($phpFile->getNamespaces() as $namespace) {
$classes = $namespace->getClasses();
foreach ($classes as $class) {
if ($class->hasMethod($methodName)) {
return $class->getMethod($methodName);
}
}
}
}

return null;
}

public static function findContainerBindings(): array
{
$code = static::for(AppServiceProvider::class);

foreach ($code->getClasses() as $class) {
$c = static::for($class);
$method = $code->getMethod('register');
$registerMethodWithAppBindings = array_filter(explode("\n", $method->getBody()), fn ($line) => str_contains($line, '->bind('));


$bindings = array_reduce($registerMethodWithAppBindings, function ($allBindings, $bindLine) use ($c) {
$binding = $c->parseBindFromServiceProvider($bindLine);

return array_merge($allBindings,[
$binding['interface'] => array_merge(
$binding,
[
'instances' => static::instancesOf( $binding['interface'])->getClasses(),
]
),
]);
}, $bindings ?? []);
}

return$bindings;
}
public static function findLogicalEvents(): array
{
$code = static::instancesOf(LogicalEvent::class);
Expand Down Expand Up @@ -446,4 +495,16 @@ public static function findLogicalListeners(): array
{
return static::instancesOf(LogicalListener::class)->getClasses();
}

public function parseBindFromServiceProvider(string $bindLineFromServiceProvider)
{
// use a named regex to extract the binding and concrete class.
$matches = [];
preg_match_all('/((?P<interface>[a-z09\\\_]+::class), \/\*\(n\*\/(?P<concrete>[a-z09\\\_]+::class))/i', $bindLineFromServiceProvider, $matches);

return [
'interface' => trim(str_replace('::class', '', $matches['interface'][0]), '\\'),
'concrete' => trim(str_replace('::class', '', $matches['concrete'][0]), '\\'),
];
}
}
2 changes: 0 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@
"@headlessui/vue": "^1.7.16",
"@heroicons/vue": "^2.0.18",
"@kbco/query-builder": "^0.0.4",
"@matrix-org/matrix-sdk-crypto-nodejs": "^0.1.0-beta.11",
"@matrix-org/olm": "3.2.15",
"@meforma/vue-toaster": "^1.3.0",
"@types/matrix-js-sdk": "^11.1.0",
"chart.js": "^4.4.0",
Expand Down
36 changes: 32 additions & 4 deletions resources/js/Pages/Logic/Index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
WalletIcon
} from "@heroicons/vue/24/outline";
import SporkDynamicInput from "@/Components/Spork/SporkDynamicInput.vue";
import SporkSelect from '@/Components/Spork/SporkSelect.vue';
import SporkInput from "@/Components/Spork/SporkInput.vue";
import SporkButton from "@/Components/Spork/SporkButton.vue";
import { router } from '@inertiajs/vue3';
Expand All @@ -36,11 +37,42 @@ const removeListenerForEvent = async ({ event }, listener) => {
})
}, 1000)
};
const changeBinding = async (binding, face) => {
await axios.post('/api/logic/change-binding', { binding, interface: face })
setTimeout(() => {
router.reload({
only: ['container_bindings']
})
}, 1000)
};
</script>

<template>
<AppLayout title="Profile">
<div>
<div class="text-2xl my-8 mx-4">Container Bindings</div>
<div class="grid grid-cols-2 mx-4">
<div class="text-stone-400">
Change your container's bindings. Once saved, requests made after will use the new binding.
</div>

<div class="flex flex-col gap-4 mx-4">
<div v-for="(p, face) in page.props.container_bindings" class="bg-stone-800 p-4 rounded-xl gap-2 flex-col flex">
<span class="text-purple-400">{{ face.replace('App\\', '') }}<span class="text-stone-400">::</span><span class="text-orange-400">class</span></span>

<SporkSelect
v-model="p.concrete"
>
<template v-for="binding in p.instances" :key="binding">
<option :value="binding">{{ binding.replace('App\\', '') }}</option>
</template>
</SporkSelect>
</div>
</div>
</div>

<div class="text-2xl my-8 mx-4">Ways to handle events in your app</div>

<div class="gap-8 grid grid-cols-2 mx-auto max-w-7xl">
Expand Down Expand Up @@ -110,10 +142,6 @@ const removeListenerForEvent = async ({ event }, listener) => {
</div>
</div>
</div>

<div class=" mx-6 my-4">
Heloo
</div>
</div>
</AppLayout>
</template>
Expand Down
4 changes: 4 additions & 0 deletions resources/js/Pages/Projects/Project.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
</div>
<div class="py-8">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8 flex flex-col gap-4">
<div>
{{ $page.props.tasks }}
</div>

<div class="grid grid-cols-2 gap-6 w-full">
<div>
<h3 class="text-base font-semibold leading-6 text-stone-900 dark:text-stone-50 ">Servers</h3>
Expand Down
1 change: 1 addition & 0 deletions routes/pages/spork.php
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,7 @@

Route::get('/-/logic', function () {
return Inertia::render('Logic/Index', [
'container_bindings' => \App\Services\Programming\LaravelProgrammingStyle::findContainerBindings(),
'events' => \App\Services\Programming\LaravelProgrammingStyle::findLogicalEvents(),
'listeners' => \App\Services\Programming\LaravelProgrammingStyle::findLogicalListeners(),
]);
Expand Down

0 comments on commit 30e69f2

Please sign in to comment.