Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
austinkregel committed Feb 2, 2024
1 parent 7998b6d commit 7bb768a
Show file tree
Hide file tree
Showing 43 changed files with 265 additions and 153 deletions.
28 changes: 2 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ $ ./sail up -d

## Planned
- [ ] IFTTT inspired Dynamic Automations
- [ ] Plaid integration for asset syncing
- [ ] Budgeting per project
- [x] Plaid integration for asset syncing
- [-] 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
Expand All @@ -37,27 +37,3 @@ $ ./sail up -d

- Single Chat interface
- Email interface
# Domain Feature Details
This presently uses Cloudflare DNS.

We can configure and manage any DNS records that Cloudflare supports.

We also want to be able to update the NS of registrars to point to Cloudflare

## Domain Syncing
This will sync domains from Namecheap to Cloudflare. It will also sync domains from Cloudflare to Laravel Forge.

# Server Feature Details
We can manage any server listed in our database as long as there is at least an SSH server configured.

Servers house code or perform jobs. They are not necessarily web servers, but can be. When accessed via SSH, you have full access to everything that user has access to.

## Server Feature Details
Laravel Forge, and Digital Ocean are both supported providers, but any server can be added manually and accessed via SSH.

# RSS Feature Details
RSS feeds are synced and updated on a schedule. This is done via a job that runs every 15 minutes.

# Page Feature Details
Pages are dynamic routes that can be configured to point to any domain, or server. They can also be configured to redirect to another page, or domain.

2 changes: 2 additions & 0 deletions app/Contracts/Services/GeocodingServiceContract.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace App\Contracts\Services;

interface GeocodingServiceContract
Expand Down
2 changes: 2 additions & 0 deletions app/Http/Controllers/TaskController.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace App\Http\Controllers;

use App\Http\Requests\StoreTaskRequest;
Expand Down
2 changes: 2 additions & 0 deletions app/Http/Requests/StoreTaskRequest.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
Expand Down
2 changes: 2 additions & 0 deletions app/Http/Requests/UpdateTaskRequest.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
Expand Down
2 changes: 1 addition & 1 deletion app/Jobs/Finance/SyncPlaidTransactionsJob.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Psr\Log\LoggerInterface;

class SyncPlaidTransactionsJob implements ShouldQueue
{
Expand Down Expand Up @@ -104,6 +103,7 @@ protected function createLocalTransaction($transaction)
'data' => $transaction,
]);
$this->syncTags($transaction, $localTransaction);

return $localTransaction;
}

Expand Down
46 changes: 24 additions & 22 deletions app/Jobs/SyncMailboxIfCredentialsAreSet.php
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<?php

declare(strict_types=1);

namespace App\Jobs;

use App\Models\Message;
use App\Models\Person;
use App\Services\ImapService;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Console\OutputStyle;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
Expand All @@ -21,8 +21,7 @@ class SyncMailboxIfCredentialsAreSet implements ShouldQueue
public function __construct(
protected ?Person $me = null,
protected ?Carbon $since = null,
)
{
) {
$this->me = Person::first();
$this->since = now()->subDay();
}
Expand All @@ -32,19 +31,19 @@ public function handle(): void
// The goal of this job is to use the imap service if we have credentials
$imapHost = env('IMAP_HOST');
$imapUser = env('IMAP_USERNAME');
if (!isset($imapUser) || !isset($imapHost)) {
if (! isset($imapUser) || ! isset($imapHost)) {
// imap not set
return;
}

$imapService = new ImapService();

info("Imap service seems to have credentials, trying to access inbox");
info('Imap service seems to have credentials, trying to access inbox');
$start = now();
$messages = $imapService->findAllFromDate('INBOX', $this->since);
$end = now();

info('Found '. count($messages). ' messages in '. $start->diffInSeconds($end). ' seconds');
info('Found '.count($messages).' messages in '.$start->diffInSeconds($end).' seconds');

foreach ($messages as $i => $message) {
$trackedMessage = Message::query()->firstWhere([
Expand All @@ -56,8 +55,8 @@ public function handle(): void
$body = $imapService->findMessage($message['id']);
$trackedMessage = Message::create([
'from_person' => $this->getPersonFromEmail($message),
'from_email' => (empty($message['from']['email'])? null : $message['from']['email']) ?? $message['addressed-from']['email'] ?? null,
'to_email' => (empty($message['to']['email'])? null : $message['to']['email']) ?? $message['addressed-to']['email'] ?? null,
'from_email' => (empty($message['from']['email']) ? null : $message['from']['email']) ?? $message['addressed-from']['email'] ?? null,
'to_email' => (empty($message['to']['email']) ? null : $message['to']['email']) ?? $message['addressed-to']['email'] ?? null,
'type' => 'email',
'event_id' => $message['id'],
'originated_at' => $message['date'],
Expand All @@ -76,14 +75,14 @@ public function handle(): void
'is_decrypted' => true,
'message' => $body['body'],
'html_message' => $body['view'],
'from_email' => (empty($message['from']['email'])? null : $message['from']['email']) ?? $message['addressed-from']['email'] ?? null,
'to_email' => (empty($message['to']['email'])? null : $message['to']['email']) ?? $message['addressed-to']['email'] ?? null,
'from_email' => (empty($message['from']['email']) ? null : $message['from']['email']) ?? $message['addressed-from']['email'] ?? null,
'to_email' => (empty($message['to']['email']) ? null : $message['to']['email']) ?? $message['addressed-to']['email'] ?? null,
'subject' => $body['subject'],
'seen' => $body['seen'],
'spam' => $body['spam'],
'answered' => $body['answered'],
])->map(function ($value, $key) use ($trackedMessage) {
if ($trackedMessage->$key !== $value) {
if ($value !== $trackedMessage->$key) {
$trackedMessage->$key = $value;
}
});
Expand All @@ -95,15 +94,15 @@ public function handle(): void
'html_message',
'seen',
'spam',
'answered'
'answered',
])) {
$this->getPersonToEmail($message);
$this->getPersonFromEmail($message);
$trackedMessage->save();
}
}

info('Processed ' . $i.'/'.count($messages));
info('Processed '.$i.'/'.count($messages));
}
}

Expand All @@ -114,7 +113,8 @@ protected function getPersonFromEmail(array $message)

if (empty($fromEmail)) {
dd('no email found, where should we get an email', $message);
return null;

return;
}

$person = Person::whereJsonContains('emails', $fromEmail)
Expand All @@ -126,30 +126,32 @@ protected function getPersonFromEmail(array $message)
if (empty($person)) {
$person = Person::create([
'name' => $fromName,
'emails' => [$fromEmail]
'emails' => [$fromEmail],
]);
}
$emails = array_values(array_unique(array_filter(array_merge($person->emails, [$message['from']['email']]), fn ($val) => !empty($val))));
$emails = array_values(array_unique(array_filter(array_merge($person->emails, [$message['from']['email']]), fn ($val) => ! empty($val))));

if (!empty(array_diff($person->emails, $emails)) || !empty(array_diff($emails, $person->emails))) {
if (! empty(array_diff($person->emails, $emails)) || ! empty(array_diff($emails, $person->emails))) {
$person->update(compact('emails'));
}

return $person->id;
}

protected function getPersonToEmail(array $message)
{
$fromName = $message['to']['name'] ?? $message['addressed-to']['name'] ?? $message['to']['email'];
$fromEmail = (empty($message['to']['email'])? null : $message['to']['email']) ?? $message['addressed-to']['email'] ?? null;
$fromEmail = (empty($message['to']['email']) ? null : $message['to']['email']) ?? $message['addressed-to']['email'] ?? null;

if (empty($fromEmail)) {
dd('no email found, where should we get an email', $message);
return null;

return;
}

$emails = array_values(array_unique(array_filter(array_merge($this->me->emails, [$fromEmail]), fn ($val) => !empty($val))));
$emails = array_values(array_unique(array_filter(array_merge($this->me->emails, [$fromEmail]), fn ($val) => ! empty($val))));

if (!empty(array_diff($this->me->emails, $emails)) || !empty(array_diff($emails, $this->me->emails))) {
if (! empty(array_diff($this->me->emails, $emails)) || ! empty(array_diff($emails, $this->me->emails))) {
$this->me->update(compact('emails'));
}

Expand Down
12 changes: 4 additions & 8 deletions app/Listeners/Finance/ApplyUserAutomatedTagsToTransaction.php
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
<?php

declare(strict_types=1);

namespace App\Listeners\Finance;

use App\Events\Models\Transaction\TransactionCreated;
use App\Models\Finance\Account;
use App\Models\Finance\Transaction;
use App\Models\User;
use App\Services\Condition\AbstractLogicalOperator;
use App\Services\ConditionService;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Arr;
use Psr\Log\LoggerInterface;

Expand All @@ -21,8 +18,7 @@ class ApplyUserAutomatedTagsToTransaction
*/
public function __construct(
protected LoggerInterface $logger
)
{
) {
//
}

Expand All @@ -40,13 +36,13 @@ public function handle(TransactionCreated $event): void

$user = $credential->user;


if (empty($user)) {
$this->logger->warning('No user found for account', [
'account' => $account->id,
'transaction' => $transaction->id,
'credential' => $account->credential?->user_id
'credential' => $account->credential?->user_id,
]);

return;
}

Expand Down
4 changes: 2 additions & 2 deletions app/Listeners/Finance/CreateDefaultAutomatedTags.php
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<?php

declare(strict_types=1);

namespace App\Listeners\Finance;

use App\Events\Models\User\UserCreated;
use App\Models\Condition;
use App\Models\Tag;
use App\Models\User;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;

class CreateDefaultAutomatedTags
{
Expand Down
13 changes: 13 additions & 0 deletions app/Models/Condition.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
class Condition extends Model implements Crud
{
use HasFactory;

public const ALL_COMPARATORS = [
self::COMPARATOR_EQUALS,
self::COMPARATOR_LIKE_STRICT,
Expand All @@ -33,17 +34,29 @@ class Condition extends Model implements Crud
];

public const COMPARATOR_EQUALS = 'EQUALS';

public const COMPARATOR_NOT_EQUAL = 'NOT_EQUAL';

public const COMPARATOR_LIKE = 'LIKE';

public const COMPARATOR_LIKE_STRICT = 'LIKE_STRICT';

public const COMPARATOR_NOT_LIKE = 'NOTLIKE';

public const COMPARATOR_IN = 'IN';

public const COMPARATOR_NOT_IN = 'NOTIN';

public const COMPARATOR_STARTS_WITH = 'STARTS_WITH';

public const COMPARATOR_ENDS_WITH = 'ENDS_WITH';

public const COMPARATOR_LESS_THAN = 'LESS_THAN';

public const COMPARATOR_LESS_THAN_EQUAL = 'LESS_THAN_EQUAL';

public const COMPARATOR_GREATER_THAN = 'GREATER_THAN';

public const COMPARATOR_GREATER_THAN_EQUAL = 'GREATER_THAN_EQUAL';

public $fillable = [
Expand Down
1 change: 1 addition & 0 deletions app/Models/Message.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class Message extends Model
'originated_at' => 'timestamp',
'settings' => 'json',
];

public $appends = ['is_user'];

public $dispatchesEvents = [
Expand Down
2 changes: 1 addition & 1 deletion app/Models/Tag.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
use Illuminate\Database\Eloquent\Factories\HasFactory;

/**
* @property bool $must_all_conditions_pass
* @property bool $must_all_conditions_pass
*/
class Tag extends \Spatie\Tags\Tag implements Conditionable, Crud, ModelQuery
{
Expand Down
2 changes: 2 additions & 0 deletions app/Models/Task.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
Expand Down
2 changes: 1 addition & 1 deletion app/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ class User extends Authenticatable implements ModelQuery
use HasFactory;
use HasProfilePhoto;
use HasRoles;
use HasTags;
use HasTeams;
use LogsActivity;
use Notifiable;
use TwoFactorAuthenticatable;
use HasTags;

/**
* The attributes that are mass assignable.
Expand Down
3 changes: 2 additions & 1 deletion app/Policies/TaskPolicy.php
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
<?php

declare(strict_types=1);

namespace App\Policies;

use App\Models\Task;
use App\Models\User;
use Illuminate\Auth\Access\Response;

class TaskPolicy
{
Expand Down
2 changes: 1 addition & 1 deletion app/Providers/EventServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class EventServiceProvider extends ServiceProvider
],
Events\Models\Transaction\TransactionCreated::class => [
Listeners\Finance\ApplyUserAutomatedTagsToTransaction::class,
]
],
];

/**
Expand Down
Loading

0 comments on commit 7bb768a

Please sign in to comment.