diff --git a/.env.example b/.env.example index 31321ce8e6..17130c1460 100644 --- a/.env.example +++ b/.env.example @@ -4,6 +4,7 @@ APP_KEY=base64:RR++yx2rJ9kdxbdh3+AmbHLDQu+Q76i++co9Y8ybbno= APP_DEBUG=false APP_URL=http://localhost +REACT_URL=http://localhost:3001 DB_CONNECTION=mysql MULTI_DB_ENABLED=false @@ -33,8 +34,8 @@ MAIL_PORT=2525 MAIL_USERNAME=null MAIL_PASSWORD=null MAIL_ENCRYPTION=null -MAIL_FROM_ADDRESS='user@example.com' -MAIL_FROM_NAME='Self Hosted User' +MAIL_FROM_ADDRESS="user@example.com" +MAIL_FROM_NAME="Self Hosted User" POSTMARK_API_TOKEN= REQUIRE_HTTPS=false @@ -67,4 +68,4 @@ MICROSOFT_REDIRECT_URI= APPLE_CLIENT_ID= APPLE_CLIENT_SECRET= -APPLE_REDIRECT_URI= +APPLE_REDIRECT_URI= \ No newline at end of file diff --git a/VERSION.txt b/VERSION.txt index 3b338e2992..db4dd40c58 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -5.6.13 \ No newline at end of file +5.6.14 \ No newline at end of file diff --git a/app/Console/Commands/ImportMigrations.php b/app/Console/Commands/ImportMigrations.php index 7e07073e2c..9e227c72bd 100644 --- a/app/Console/Commands/ImportMigrations.php +++ b/app/Console/Commands/ImportMigrations.php @@ -64,8 +64,6 @@ class ImportMigrations extends Command */ public function __construct() { - $this->faker = Factory::create(); - parent::__construct(); } @@ -76,6 +74,8 @@ class ImportMigrations extends Command */ public function handle() { + $this->faker = Factory::create(); + $this->buildCache(); $path = $this->option('path') ?? public_path('storage/migrations/import'); diff --git a/app/Console/Commands/MobileLocalization.php b/app/Console/Commands/MobileLocalization.php index e4d12c98bc..482cf9042a 100644 --- a/app/Console/Commands/MobileLocalization.php +++ b/app/Console/Commands/MobileLocalization.php @@ -93,17 +93,6 @@ class MobileLocalization extends Command $text = str_replace(['', ''], '', $text); $text = str_replace(['', ''], '', $text); -//replace the three lines above with this -// if($language->locale == 'ar') { -// $text = str_replace('\n', " ", $text); -// } - -// $text = str_replace(['', '','', '','', ''], '', $text); -// $text = str_replace('"', "'", $text); - - - - echo "'$key': '$text',\n"; } diff --git a/app/Http/Controllers/ExportController.php b/app/Http/Controllers/ExportController.php index ab2f95a253..f459a27333 100644 --- a/app/Http/Controllers/ExportController.php +++ b/app/Http/Controllers/ExportController.php @@ -11,10 +11,12 @@ namespace App\Http\Controllers; -use App\Http\Requests\Export\StoreExportRequest; -use App\Jobs\Company\CompanyExport; -use App\Utils\Traits\MakesHash; +use Illuminate\Support\Str; use Illuminate\Http\Response; +use App\Utils\Traits\MakesHash; +use App\Jobs\Company\CompanyExport; +use Illuminate\Support\Facades\Cache; +use App\Http\Requests\Export\StoreExportRequest; class ExportController extends BaseController { @@ -54,8 +56,12 @@ class ExportController extends BaseController */ public function index(StoreExportRequest $request) { - CompanyExport::dispatch(auth()->user()->getCompany(), auth()->user()); + $hash = Str::uuid(); + $url = \Illuminate\Support\Facades\URL::temporarySignedRoute('protected_download', now()->addHour(), ['hash' => $hash]); + Cache::put($hash, $url, now()->addHour()); - return response()->json(['message' => 'Processing'], 200); + CompanyExport::dispatch(auth()->user()->getCompany(), auth()->user(), $hash); + + return response()->json(['message' => 'Processing', 'url' => $url], 200); } } diff --git a/app/Http/Controllers/ProtectedDownloadController.php b/app/Http/Controllers/ProtectedDownloadController.php new file mode 100644 index 0000000000..452989efda --- /dev/null +++ b/app/Http/Controllers/ProtectedDownloadController.php @@ -0,0 +1,41 @@ +hash); + + if (!$hashed_path) { + throw new SystemError('File no longer available', 404); + abort(404, 'File no longer available'); + } + + UnlinkFile::dispatch(config('filesystems.default'), $hashed_path)->delay(now()->addSeconds(10)); + + return response()->streamDownload(function () use ($hashed_path) { + echo Storage::get($hashed_path); + }, basename($hashed_path), []); + + } + +} diff --git a/app/Http/Controllers/Reports/PaymentReportController.php b/app/Http/Controllers/Reports/PaymentReportController.php index fedc5859b1..44ea8d5e20 100644 --- a/app/Http/Controllers/Reports/PaymentReportController.php +++ b/app/Http/Controllers/Reports/PaymentReportController.php @@ -83,4 +83,5 @@ class PaymentReportController extends BaseController echo $csv; }, $this->filename, $headers); } + } diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index c7fcc7b5ce..f0cf330a16 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -41,6 +41,7 @@ use App\Http\Middleware\VerifyCsrfToken; use App\Http\Middleware\ContactTokenAuth; use Illuminate\Auth\Middleware\Authorize; use App\Http\Middleware\SetDbByCompanyKey; +use App\Http\Middleware\ValidateSignature; use App\Http\Middleware\PasswordProtection; use App\Http\Middleware\ClientPortalEnabled; use App\Http\Middleware\CheckClientExistence; @@ -49,16 +50,13 @@ use Illuminate\Http\Middleware\SetCacheHeaders; use Illuminate\Session\Middleware\StartSession; use App\Http\Middleware\CheckForMaintenanceMode; use App\Http\Middleware\RedirectIfAuthenticated; -use Illuminate\Routing\Middleware\ThrottleRequests; use Illuminate\Foundation\Http\Kernel as HttpKernel; -use Illuminate\Routing\Middleware\ValidateSignature; use Illuminate\Auth\Middleware\EnsureEmailIsVerified; use Illuminate\Routing\Middleware\SubstituteBindings; use Illuminate\View\Middleware\ShareErrorsFromSession; use Illuminate\Auth\Middleware\AuthenticateWithBasicAuth; use Illuminate\Foundation\Http\Middleware\ValidatePostSize; use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse; -use Illuminate\Routing\Middleware\ThrottleRequestsWithRedis; use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull; class Kernel extends HttpKernel diff --git a/app/Http/Middleware/ValidateSignature.php b/app/Http/Middleware/ValidateSignature.php new file mode 100644 index 0000000000..6308b30862 --- /dev/null +++ b/app/Http/Middleware/ValidateSignature.php @@ -0,0 +1,49 @@ + + */ + protected $ignore = [ + 'q' + ]; + + /** + * Handle an incoming request. + * + * @param \Illuminate\Http\Request $request + * @param \Closure $next + * @param string|null $relative + * @return \Illuminate\Http\Response + * + * @throws \Illuminate\Routing\Exceptions\InvalidSignatureException + */ + public function handle($request, Closure $next, $relative = null) + { + $ignore = property_exists($this, 'except') ? $this->except : $this->ignore; + + if ($request->hasValidSignatureWhileIgnoring($ignore, $relative !== 'relative')) { + return $next($request); + } + + throw new InvalidSignatureException; + } +} diff --git a/app/Jobs/Company/CompanyExport.php b/app/Jobs/Company/CompanyExport.php index 1b289f344b..2b693dbabb 100644 --- a/app/Jobs/Company/CompanyExport.php +++ b/app/Jobs/Company/CompanyExport.php @@ -11,39 +11,39 @@ namespace App\Jobs\Company; -use App\Jobs\Mail\NinjaMailerJob; -use App\Jobs\Mail\NinjaMailerObject; -use App\Libraries\MultiDB; -use App\Mail\DownloadBackup; -use App\Models\Company; -use App\Models\CreditInvitation; -use App\Models\InvoiceInvitation; -use App\Models\PurchaseOrderInvitation; -use App\Models\QuoteInvitation; -use App\Models\RecurringInvoiceInvitation; use App\Models\User; -use App\Models\VendorContact; use App\Utils\Ninja; -use App\Utils\Traits\MakesHash; +use App\Models\Company; +use App\Libraries\MultiDB; +use Illuminate\Support\Str; +use App\Mail\DownloadBackup; +use App\Jobs\Util\UnlinkFile; +use App\Models\VendorContact; use Illuminate\Bus\Queueable; +use App\Models\QuoteInvitation; +use App\Utils\Traits\MakesHash; +use App\Models\CreditInvitation; +use App\Jobs\Mail\NinjaMailerJob; +use App\Models\InvoiceInvitation; +use Illuminate\Support\Facades\App; +use App\Jobs\Mail\NinjaMailerObject; +use Illuminate\Support\Facades\Cache; +use Illuminate\Queue\SerializesModels; +use App\Models\PurchaseOrderInvitation; +use Illuminate\Support\Facades\Storage; +use Illuminate\Queue\InteractsWithQueue; +use App\Models\RecurringInvoiceInvitation; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; -use Illuminate\Queue\InteractsWithQueue; -use Illuminate\Queue\SerializesModels; -use Illuminate\Support\Facades\App; -use Illuminate\Support\Facades\Storage; class CompanyExport implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, MakesHash; - public $company; - - private $export_format; + private $export_format = 'json'; private $export_data = []; - public $user; /** * Create a new job instance. @@ -52,11 +52,8 @@ class CompanyExport implements ShouldQueue * @param User $user * @param string $custom_token_name */ - public function __construct(Company $company, User $user, $export_format = 'json') + public function __construct(public Company $company, private User $user, public string $hash) { - $this->company = $company; - $this->user = $user; - $this->export_format = $export_format; } /** @@ -467,6 +464,10 @@ class CompanyExport implements ShouldQueue } $storage_file_path = Storage::disk(config('filesystems.default'))->url('backups/'.$file_name); + $storage_path = Storage::disk(config('filesystems.default'))->path('backups/'.$file_name); + + $url = Cache::get($this->hash); + Cache::put($this->hash, $storage_path, now()->addHour()); App::forgetInstance('translator'); $t = app('translator'); @@ -475,12 +476,14 @@ class CompanyExport implements ShouldQueue $company_reference = Company::find($this->company->id); $nmo = new NinjaMailerObject; - $nmo->mailable = new DownloadBackup($storage_file_path, $company_reference); + $nmo->mailable = new DownloadBackup($url, $company_reference); $nmo->to_user = $this->user; $nmo->company = $company_reference; $nmo->settings = $this->company->settings; NinjaMailerJob::dispatch($nmo, true); + + UnlinkFile::dispatch(config('filesystems.default'), $storage_path)->delay(now()->addHours(1)); if (Ninja::isHosted()) { sleep(3); diff --git a/app/Jobs/Report/SendToAdmin.php b/app/Jobs/Report/SendToAdmin.php index 29caccd7bb..ca7e5c8812 100644 --- a/app/Jobs/Report/SendToAdmin.php +++ b/app/Jobs/Report/SendToAdmin.php @@ -21,6 +21,7 @@ use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; +use Illuminate\Queue\Middleware\WithoutOverlapping; class SendToAdmin implements ShouldQueue { @@ -59,4 +60,9 @@ class SendToAdmin implements ShouldQueue NinjaMailerJob::dispatch($nmo); } + + public function middleware() + { + return [new WithoutOverlapping("report-{$this->company->company_key}")]; + } } diff --git a/app/PaymentDrivers/Square/CreditCard.php b/app/PaymentDrivers/Square/CreditCard.php index a8b75426ca..923d47eb44 100644 --- a/app/PaymentDrivers/Square/CreditCard.php +++ b/app/PaymentDrivers/Square/CreditCard.php @@ -12,6 +12,7 @@ namespace App\PaymentDrivers\Square; +use App\Exceptions\PaymentFailed; use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest; use App\Models\ClientGatewayToken; use App\Models\GatewayType; @@ -113,18 +114,23 @@ class CreditCard implements MethodInterface $body->setLocationId($this->square_driver->company_gateway->getConfigField('locationId')); $body->setReferenceId(Str::random(16)); - if ($request->has('verificationToken') && $request->input('verificationToken')) { - $body->setVerificationToken($request->input('verificationToken')); - } - if ($request->shouldUseToken()) { $body->setCustomerId($cgt->gateway_customer_reference); + }elseif ($request->has('verificationToken') && $request->input('verificationToken')) { + $body->setVerificationToken($request->input('verificationToken')); } /** @var ApiResponse */ $response = $this->square_driver->square->getPaymentsApi()->createPayment($body); if ($response->isSuccess()) { + + $body = json_decode($response->getBody()); + + if($request->store_card){ + $this->createCard($body->payment->id); + } + return $this->processSuccessfulPayment($response); } @@ -161,6 +167,52 @@ class CreditCard implements MethodInterface return $this->square_driver->processUnsuccessfulTransaction($data); } + private function createCard($source_id) + { + + $square_card = new \Square\Models\Card(); + $square_card->setCustomerId($this->findOrCreateClient()); + + $body = new \Square\Models\CreateCardRequest(uniqid("st", true), $source_id, $square_card); + + $api_response = $this->square_driver + ->init() + ->square + ->getCardsApi() + ->createCard($body); + + $body = json_decode($api_response->getBody()); + + if ($api_response->isSuccess()) { + + try { + $payment_meta = new \stdClass; + $payment_meta->exp_month = (string) $body->card->exp_month; + $payment_meta->exp_year = (string) $body->card->exp_year; + $payment_meta->brand = (string) $body->card->card_brand; + $payment_meta->last4 = (string) $body->card->last_4; + $payment_meta->type = GatewayType::CREDIT_CARD; + + $data = [ + 'payment_meta' => $payment_meta, + 'token' => $body->card->id, + 'payment_method_id' => GatewayType::CREDIT_CARD, + ]; + + $this->square_driver->storeGatewayToken($data, ['gateway_customer_reference' => $body->card->customer_id]); + + } catch (\Exception $e) { + return $this->square_driver->processInternallyFailedPayment($this->square_driver, $e); + } + + } + else { + throw new PaymentFailed($body->errors[0]->detail, 500); + } + + return false; + } + private function findOrCreateClient() { $email_address = new \Square\Models\CustomerTextFilter(); diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 40fb55b800..6d5e145af8 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -113,13 +113,6 @@ class AppServiceProvider extends ServiceProvider return $this; }); - /* Extension for custom mailers */ - - /* Convenience helper for testing s*/ - ParallelTesting::setUpTestDatabase(function ($database, $token) { - Artisan::call('db:seed'); - }); - } public function register(): void diff --git a/app/Providers/ClientPortalServiceProvider.php b/app/Providers/ClientPortalServiceProvider.php index 6a8708fc23..a4ac3c02d9 100644 --- a/app/Providers/ClientPortalServiceProvider.php +++ b/app/Providers/ClientPortalServiceProvider.php @@ -14,9 +14,10 @@ class ClientPortalServiceProvider extends ServiceProvider */ public function register() { - app()->bind('customMessage', function () { + app()->bind('customMessage', function () { return new CustomMessage(); }); + } /** @@ -26,6 +27,6 @@ class ClientPortalServiceProvider extends ServiceProvider */ public function boot() { - // + } } diff --git a/app/Providers/MultiDatabaseUserProvider.php b/app/Providers/MultiDatabaseUserProvider.php deleted file mode 100644 index 6a6aef0de7..0000000000 --- a/app/Providers/MultiDatabaseUserProvider.php +++ /dev/null @@ -1,277 +0,0 @@ -model = $model; - $this->hasher = $hasher; - } - - /** - * Retrieve a user by their unique identifier. - * - * @param mixed $identifier - * @return UserContract|null - */ - public function retrieveById($identifier) - { - $this->setDefaultDatabase($identifier); - - $model = $this->createModel(); - - return $model->newQuery() - ->where($model->getAuthIdentifierName(), $identifier) - ->first(); - } - - /** - * Retrieve a user by their unique identifier and "remember me" token. - * - * @param mixed $identifier - * @param string $token - * @return UserContract|null - */ - public function retrieveByToken($identifier, $token) - { - $this->setDefaultDatabase($identifier, $token); - - $model = $this->createModel(); - - $model = $model->where($model->getAuthIdentifierName(), $identifier)->first(); - - if (! $model) { - return null; - } - - $rememberToken = $model->getRememberToken(); - - return $rememberToken && hash_equals($rememberToken, $token) ? $model : null; - } - - /** - * Update the "remember me" token for the given user in storage. - * - * @param UserContract|Model $user - * @param string $token - * @return void - */ - public function updateRememberToken(UserContract $user, $token) - { - $user->setRememberToken($token); - - $timestamps = $user->timestamps; - - $user->timestamps = false; - - $user->save(); - - $user->timestamps = $timestamps; - } - - /** - * Retrieve a user by the given credentials. - * - * @param array $credentials - * @return UserContract|null - */ - public function retrieveByCredentials(array $credentials) - { - if (empty($credentials) || - (count($credentials) === 1 && - array_key_exists('password', $credentials))) { - return; - } - - $this->setDefaultDatabase(false, $credentials['email'], false); - - // First we will add each credential element to the query as a where clause. - // Then we can execute the query and, if we found a user, return it in a - // Eloquent User "model" that will be utilized by the Guard instances. - $query = $this->createModel()->newQuery(); - - foreach ($credentials as $key => $value) { - if (Str::contains($key, 'password')) { - continue; - } - - if (is_array($value) || $value instanceof Arrayable) { - $query->whereIn($key, $value); - } else { - $query->where($key, $value); - } - } - - return $query->first(); - } - - /** - * Validate a user against the given credentials. - * - * @param UserContract $user - * @param array $credentials - * @return bool - */ - public function validateCredentials(UserContract $user, array $credentials) - { - $plain = $credentials['password']; - - return $this->hasher->check($plain, $user->getAuthPassword()); - } - - /** - * Create a new instance of the model. - * - * @return Model - */ - public function createModel() - { - $class = '\\'.ltrim($this->model, '\\'); - - return new $class; - } - - /** - * Gets the hasher implementation. - * - * @return HasherContract - */ - public function getHasher() - { - return $this->hasher; - } - - /** - * Sets the hasher implementation. - * - * @param HasherContract $hasher - * @return $this - */ - public function setHasher(HasherContract $hasher) - { - $this->hasher = $hasher; - - return $this; - } - - /** - * Gets the name of the Eloquent user model. - * - * @return string - */ - public function getModel() - { - return $this->model; - } - - /** - * Sets the name of the Eloquent user model. - * - * @param string $model - * @return $this - */ - public function setModel($model) - { - $this->model = $model; - - return $this; - } - - /** - * Sets correct database by variable. - * @param bool $id - * @param bool $email - * @param bool $token - */ - private function setDefaultDatabase($id = false, $email = false, $token = false) : void - { - foreach (MultiDB::getDbs() as $database) { - $this->setDB($database); - - /** Make sure we hook into the correct guard class */ - $query = $this->conn->table((new $this->model)->getTable()); - - if ($id) { - $query->where('id', '=', $id); - } - - if ($email) { - $query->where('email', '=', $email); - } - - $user = $query->get(); - - if (count($user) >= 1) { - break; - } - - $query = $this->conn->table('company_tokens'); - - if ($token) { - $query->whereRaw('BINARY `token`= ?', $token); - - $token = $query->get(); - - if (count($token) >= 1) { - break; - } - } - } - } - - /** - * Sets the database at runtime. - * @param $database - */ - private function setDB($database) - { - /** Get the database name we want to switch to*/ - $db_name = config('database.connections.'.$database.'.database'); - - /* This will set the default configuration for the request / session?*/ - config(['database.default' => $database]); - - /* Set the connection to complete the user authentication */ - $this->conn = app('db')->connection(config('database.connections.database.'.$database)); - } -} diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 3a7364eda1..d8a11fba07 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -20,7 +20,6 @@ use Illuminate\Cache\RateLimiting\Limit; use Illuminate\Support\Facades\RateLimiter; use App\Http\Middleware\ThrottleRequestsWithPredis; use Illuminate\Routing\Middleware\ThrottleRequests; -use Illuminate\Routing\Middleware\ThrottleRequestsWithRedis; use Illuminate\Database\Eloquent\ModelNotFoundException as ModelNotFoundException; use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider; diff --git a/composer.json b/composer.json index 9a36ea6f34..6bc4453617 100644 --- a/composer.json +++ b/composer.json @@ -101,7 +101,6 @@ "php": "^8.1", "barryvdh/laravel-debugbar": "^3.6", "barryvdh/laravel-ide-helper": "^2.13", - "beyondcode/laravel-query-detector": "^1.6", "brianium/paratest": "^6.1", "fakerphp/faker": "^1.14", "filp/whoops": "^2.7", @@ -136,7 +135,7 @@ }, "extra": { "laravel": { - "dont-discover": ["invoiceninja/inspector"] + "dont-discover": [] } }, "scripts": { diff --git a/composer.lock b/composer.lock index c66e33aa81..3f353f7a47 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "5119232ad274b24801da947fcbd4f884", + "content-hash": "135eec9ab7a1e8c0ab3820ff27cf1488", "packages": [ { "name": "adrienrn/php-mimetyper", @@ -14410,16 +14410,16 @@ }, { "name": "barryvdh/reflection-docblock", - "version": "v2.1.0", + "version": "v2.1.1", "source": { "type": "git", "url": "https://github.com/barryvdh/ReflectionDocBlock.git", - "reference": "bf44b757feb8ba1734659029357646466ded673e" + "reference": "e6811e927f0ecc37cc4deaa6627033150343e597" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/barryvdh/ReflectionDocBlock/zipball/bf44b757feb8ba1734659029357646466ded673e", - "reference": "bf44b757feb8ba1734659029357646466ded673e", + "url": "https://api.github.com/repos/barryvdh/ReflectionDocBlock/zipball/e6811e927f0ecc37cc4deaa6627033150343e597", + "reference": "e6811e927f0ecc37cc4deaa6627033150343e597", "shasum": "" }, "require": { @@ -14456,69 +14456,9 @@ } ], "support": { - "source": "https://github.com/barryvdh/ReflectionDocBlock/tree/v2.1.0" + "source": "https://github.com/barryvdh/ReflectionDocBlock/tree/v2.1.1" }, - "time": "2022-10-31T15:35:43+00:00" - }, - { - "name": "beyondcode/laravel-query-detector", - "version": "1.7.0", - "source": { - "type": "git", - "url": "https://github.com/beyondcode/laravel-query-detector.git", - "reference": "40c7e168fcf7eeb80d8e96f7922e05ab194269c8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/beyondcode/laravel-query-detector/zipball/40c7e168fcf7eeb80d8e96f7922e05ab194269c8", - "reference": "40c7e168fcf7eeb80d8e96f7922e05ab194269c8", - "shasum": "" - }, - "require": { - "illuminate/support": "^5.5 || ^6.0 || ^7.0 || ^8.0 || ^9.0|^10.0", - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "laravel/legacy-factories": "^1.0", - "orchestra/testbench": "^3.0 || ^4.0 || ^5.0 || ^6.0|^8.0", - "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" - }, - "type": "library", - "extra": { - "laravel": { - "providers": [ - "BeyondCode\\QueryDetector\\QueryDetectorServiceProvider" - ] - } - }, - "autoload": { - "psr-4": { - "BeyondCode\\QueryDetector\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marcel Pociot", - "email": "marcel@beyondco.de", - "homepage": "https://beyondcode.de", - "role": "Developer" - } - ], - "description": "Laravel N+1 Query Detector", - "homepage": "https://github.com/beyondcode/laravel-query-detector", - "keywords": [ - "beyondcode", - "laravel-query-detector" - ], - "support": { - "issues": "https://github.com/beyondcode/laravel-query-detector/issues", - "source": "https://github.com/beyondcode/laravel-query-detector/tree/1.7.0" - }, - "time": "2023-02-15T10:37:22+00:00" + "time": "2023-06-14T05:06:27+00:00" }, { "name": "brianium/paratest", @@ -16339,16 +16279,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.10.24", + "version": "1.10.25", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "360ecc90569e9a60c2954ee209ec04fa0d958e14" + "reference": "578f4e70d117f9a90699324c555922800ac38d8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/360ecc90569e9a60c2954ee209ec04fa0d958e14", - "reference": "360ecc90569e9a60c2954ee209ec04fa0d958e14", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/578f4e70d117f9a90699324c555922800ac38d8c", + "reference": "578f4e70d117f9a90699324c555922800ac38d8c", "shasum": "" }, "require": { @@ -16397,7 +16337,7 @@ "type": "tidelift" } ], - "time": "2023-07-05T12:32:13+00:00" + "time": "2023-07-06T12:11:37+00:00" }, { "name": "phpunit/php-code-coverage", diff --git a/config/ninja.php b/config/ninja.php index 710297f2fe..5a55379db1 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -15,8 +15,8 @@ return [ 'require_https' => env('REQUIRE_HTTPS', true), 'app_url' => rtrim(env('APP_URL', ''), '/'), 'app_domain' => env('APP_DOMAIN', 'invoicing.co'), - 'app_version' => '5.6.13', - 'app_tag' => '5.6.13', + 'app_version' => '5.6.14', + 'app_tag' => '5.6.14', 'minimum_client_version' => '5.0.16', 'terms_version' => '1.0.1', 'api_secret' => env('API_SECRET', ''), diff --git a/public/js/clients/payments/square-credit-card.js b/public/js/clients/payments/square-credit-card.js index 55bdaf6677..e03b80cd29 100644 --- a/public/js/clients/payments/square-credit-card.js +++ b/public/js/clients/payments/square-credit-card.js @@ -176,62 +176,79 @@ var SquareCreditCard = /*#__PURE__*/function () { }, { key: "handle", value: function () { - var _handle = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee6() { - var _document$getElementB, - _this = this, - _document$getElementB2, - _document$getElementB3; - var toggleWithToken, _document$getElementB4; - return _regeneratorRuntime().wrap(function _callee6$(_context6) { - while (1) switch (_context6.prev = _context6.next) { + var _handle = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee7() { + var _this = this; + return _regeneratorRuntime().wrap(function _callee7$(_context7) { + while (1) switch (_context7.prev = _context7.next) { case 0: - _context6.next = 2; - return this.init(); - case 2: - (_document$getElementB = document.getElementById('authorize-card')) === null || _document$getElementB === void 0 ? void 0 : _document$getElementB.addEventListener('click', function (e) { - return _this.completePaymentWithoutToken(e); - }); - (_document$getElementB2 = document.getElementById('pay-now')) === null || _document$getElementB2 === void 0 ? void 0 : _document$getElementB2.addEventListener('click', function (e) { - var tokenInput = document.querySelector('input[name=token]'); - if (tokenInput.value) { - return _this.completePaymentUsingToken(e); - } - return _this.completePaymentWithoutToken(e); - }); - Array.from(document.getElementsByClassName('toggle-payment-with-token')).forEach(function (element) { - return element.addEventListener('click', function (element) { - document.getElementById('card-container').classList.add('hidden'); - document.getElementById('save-card--container').style.display = 'none'; - document.querySelector('input[name=token]').value = element.target.dataset.token; + document.getElementById('payment-list').classList.add('hidden'); + _context7.next = 3; + return this.init().then(function () { + var _document$getElementB, _document$getElementB2, _document$getElementB3, _document$getElementB4; + (_document$getElementB = document.getElementById('authorize-card')) === null || _document$getElementB === void 0 ? void 0 : _document$getElementB.addEventListener('click', function (e) { + return _this.completePaymentWithoutToken(e); }); - }); - (_document$getElementB3 = document.getElementById('toggle-payment-with-credit-card')) === null || _document$getElementB3 === void 0 ? void 0 : _document$getElementB3.addEventListener('click', /*#__PURE__*/function () { - var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5(element) { - return _regeneratorRuntime().wrap(function _callee5$(_context5) { - while (1) switch (_context5.prev = _context5.next) { - case 0: - document.getElementById('card-container').classList.remove('hidden'); - document.getElementById('save-card--container').style.display = 'grid'; - document.querySelector('input[name=token]').value = ''; - case 3: - case "end": - return _context5.stop(); - } - }, _callee5); - })); - return function (_x4) { - return _ref.apply(this, arguments); - }; - }()); - toggleWithToken = document.querySelector('.toggle-payment-with-token'); - if (!toggleWithToken) { + (_document$getElementB2 = document.getElementById('pay-now')) === null || _document$getElementB2 === void 0 ? void 0 : _document$getElementB2.addEventListener('click', function (e) { + var tokenInput = document.querySelector('input[name=token]'); + if (tokenInput.value) { + return _this.completePaymentUsingToken(e); + } + return _this.completePaymentWithoutToken(e); + }); + Array.from(document.getElementsByClassName('toggle-payment-with-token')).forEach(function (element) { + return element.addEventListener('click', /*#__PURE__*/function () { + var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5(element) { + return _regeneratorRuntime().wrap(function _callee5$(_context5) { + while (1) switch (_context5.prev = _context5.next) { + case 0: + document.getElementById('card-container').classList.add('hidden'); + document.getElementById('save-card--container').style.display = 'none'; + document.querySelector('input[name=token]').value = element.target.dataset.token; + case 3: + case "end": + return _context5.stop(); + } + }, _callee5); + })); + return function (_x4) { + return _ref.apply(this, arguments); + }; + }()); + }); + (_document$getElementB3 = document.getElementById('toggle-payment-with-credit-card')) === null || _document$getElementB3 === void 0 ? void 0 : _document$getElementB3.addEventListener('click', /*#__PURE__*/function () { + var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee6(element) { + return _regeneratorRuntime().wrap(function _callee6$(_context6) { + while (1) switch (_context6.prev = _context6.next) { + case 0: + document.getElementById('card-container').classList.remove('hidden'); + document.getElementById('save-card--container').style.display = 'grid'; + document.querySelector('input[name=token]').value = ''; + case 3: + case "end": + return _context6.stop(); + } + }, _callee6); + })); + return function (_x5) { + return _ref2.apply(this, arguments); + }; + }()); + + // let toggleWithToken = document.querySelector( + // '.toggle-payment-with-token' + // ); + + // if (!toggleWithToken) { + document.getElementById('loader').classList.add('hidden'); + document.getElementById('payment-list').classList.remove('hidden'); (_document$getElementB4 = document.getElementById('toggle-payment-with-credit-card')) === null || _document$getElementB4 === void 0 ? void 0 : _document$getElementB4.click(); - } - case 8: + // } + }); + case 3: case "end": - return _context6.stop(); + return _context7.stop(); } - }, _callee6, this); + }, _callee7, this); })); function handle() { return _handle.apply(this, arguments); diff --git a/public/js/clients/payments/stripe-credit-card.js b/public/js/clients/payments/stripe-credit-card.js index b5587ade88..2488cd580a 100644 --- a/public/js/clients/payments/stripe-credit-card.js +++ b/public/js/clients/payments/stripe-credit-card.js @@ -31,8 +31,6 @@ var StripeCreditCard = /*#__PURE__*/function () { key: "setupStripe", value: function setupStripe() { if (this.stripeConnect) { - // this.stripe.stripeAccount = this.stripeConnect; - this.stripe = Stripe(this.key, { stripeAccount: this.stripeConnect }); diff --git a/public/mix-manifest.json b/public/mix-manifest.json index b5975fbf89..5d7f7371c1 100644 --- a/public/mix-manifest.json +++ b/public/mix-manifest.json @@ -16,7 +16,7 @@ "/js/clients/payments/checkout-credit-card.js": "/js/clients/payments/checkout-credit-card.js?id=a2168c43060a7de40da20b5fc599bcab", "/js/clients/quotes/action-selectors.js": "/js/clients/quotes/action-selectors.js?id=4158693089b29ee8e13cb7d9ce4480a9", "/js/clients/quotes/approve.js": "/js/clients/quotes/approve.js?id=4e596cec23cdd6487534e6ed5499d791", - "/js/clients/payments/stripe-credit-card.js": "/js/clients/payments/stripe-credit-card.js?id=b483e14d15000c04edfe4c9c80fb97c9", + "/js/clients/payments/stripe-credit-card.js": "/js/clients/payments/stripe-credit-card.js?id=bfa116c1df42c641bc7a3ff4fa8d50dd", "/js/setup/setup.js": "/js/setup/setup.js?id=086b9e114b0b9ee01f909d686f489162", "/js/clients/payments/card-js.min.js": "/js/clients/payments/card-js.min.js?id=cf50b5ba1fcd1d184bf0c10d710672c8", "/js/clients/shared/pdf.js": "/js/clients/shared/pdf.js?id=c9593b44d66f89874d13f99bc3e6ff33", @@ -30,7 +30,7 @@ "/js/clients/payments/mollie-credit-card.js": "/js/clients/payments/mollie-credit-card.js?id=2f72b969507e6135b5c52a65522ab3ae", "/js/clients/payments/eway-credit-card.js": "/js/clients/payments/eway-credit-card.js?id=0d1c8957b02c5601b7d57c39740bff75", "/js/clients/payment_methods/braintree-ach.js": "/js/clients/payment_methods/braintree-ach.js?id=2f8e5af9ba5ce266d2ee49b084fbe291", - "/js/clients/payments/square-credit-card.js": "/js/clients/payments/square-credit-card.js?id=dbd7a15777def575562153c984dee08a", + "/js/clients/payments/square-credit-card.js": "/js/clients/payments/square-credit-card.js?id=a5e1407a161c3c72545d125dd1100571", "/js/clients/statements/view.js": "/js/clients/statements/view.js?id=bd92ab50acabf1cc5232912d53edc5e1", "/js/clients/payments/razorpay-aio.js": "/js/clients/payments/razorpay-aio.js?id=46e14d31acaf3adf58444a5de4b4122c", "/js/clients/payments/stripe-sepa.js": "/js/clients/payments/stripe-sepa.js?id=ef15c0865a29c3c17f2ad185cad0d28e", diff --git a/resources/js/clients/payments/square-credit-card.js b/resources/js/clients/payments/square-credit-card.js index cceaacc5a7..ca8a153e93 100644 --- a/resources/js/clients/payments/square-credit-card.js +++ b/resources/js/clients/payments/square-credit-card.js @@ -125,7 +125,10 @@ class SquareCreditCard { } async handle() { - await this.init(); + + document.getElementById('payment-list').classList.add('hidden'); + + await this.init().then(() => { document .getElementById('authorize-card') @@ -146,7 +149,7 @@ class SquareCreditCard { Array.from( document.getElementsByClassName('toggle-payment-with-token') ).forEach((element) => - element.addEventListener('click', (element) => { + element.addEventListener('click', async (element) => { document .getElementById('card-container') .classList.add('hidden'); @@ -168,13 +171,17 @@ class SquareCreditCard { document.querySelector('input[name=token]').value = ''; }); - let toggleWithToken = document.querySelector( - '.toggle-payment-with-token' - ); + // let toggleWithToken = document.querySelector( + // '.toggle-payment-with-token' + // ); - if (!toggleWithToken) { + // if (!toggleWithToken) { + document.getElementById('loader').classList.add('hidden'); + document.getElementById('payment-list').classList.remove('hidden'); document.getElementById('toggle-payment-with-credit-card')?.click(); - } + // } + }); + } } diff --git a/resources/js/clients/payments/stripe-credit-card.js b/resources/js/clients/payments/stripe-credit-card.js index 93001723a4..30cbfe13bd 100644 --- a/resources/js/clients/payments/stripe-credit-card.js +++ b/resources/js/clients/payments/stripe-credit-card.js @@ -19,7 +19,6 @@ class StripeCreditCard { setupStripe() { if (this.stripeConnect){ - // this.stripe.stripeAccount = this.stripeConnect; this.stripe = Stripe(this.key, { stripeAccount: this.stripeConnect, diff --git a/resources/views/errors/guest.blade.php b/resources/views/errors/guest.blade.php index f1cf00ec36..6e99c267b7 100644 --- a/resources/views/errors/guest.blade.php +++ b/resources/views/errors/guest.blade.php @@ -1,5 +1,5 @@ @extends('portal.ninja2020.layout.error') -@section('title', __($title) ?? 'Server Error') +@section('title', $title ?? 'Error') @section('code', __($code) ?? '500') @section('message', __($message) ?? 'System Error') diff --git a/resources/views/portal/ninja2020/gateways/square/credit_card/pay.blade.php b/resources/views/portal/ninja2020/gateways/square/credit_card/pay.blade.php index 79b2627db1..5c9e852cdc 100644 --- a/resources/views/portal/ninja2020/gateways/square/credit_card/pay.blade.php +++ b/resources/views/portal/ninja2020/gateways/square/credit_card/pay.blade.php @@ -7,7 +7,32 @@ + @endsection @section('gateway_content') @@ -33,23 +58,41 @@ @include('portal.ninja2020.gateways.includes.payment_details') - @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.pay_with')]) +
+
+
+ + + @endcomponent @include('portal.ninja2020.gateways.includes.save_card') diff --git a/routes/api.php b/routes/api.php index 42fdfb8109..9d1e339db1 100644 --- a/routes/api.php +++ b/routes/api.php @@ -101,6 +101,7 @@ use App\Http\Controllers\Support\Messages\SendingController; use App\Http\Controllers\Reports\ClientSalesReportController; use App\Http\Controllers\Reports\InvoiceItemReportController; use App\Http\Controllers\PaymentNotificationWebhookController; +use App\Http\Controllers\ProtectedDownloadController; use App\Http\Controllers\Reports\ProductSalesReportController; use App\Http\Controllers\Reports\ClientBalanceReportController; use App\Http\Controllers\Reports\ClientContactReportController; @@ -141,7 +142,6 @@ Route::group(['middleware' => ['throttle:api', 'api_db', 'token_auth', 'locale'] Route::get('activities', [ActivityController::class, 'index']); Route::get('activities/download_entity/{activity}', [ActivityController::class, 'downloadHistoricalEntity']); - Route::post('charts/totals', [ChartController::class, 'totals'])->name('chart.totals'); Route::post('charts/chart_summary', [ChartController::class, 'chart_summary'])->name('chart.chart_summary'); @@ -280,26 +280,26 @@ Route::group(['middleware' => ['throttle:api', 'api_db', 'token_auth', 'locale'] Route::post('recurring_quotes/bulk', [RecurringQuoteController::class, 'bulk'])->name('recurring_quotes.bulk'); Route::put('recurring_quotes/{recurring_quote}/upload', [RecurringQuoteController::class, 'upload']); - Route::post('refresh', [LoginController::class, 'refresh'])->middleware('throttle:refresh'); + Route::post('refresh', [LoginController::class, 'refresh'])->middleware('throttle:refr2sh'); + + Route::post('reports/clients', ClientReportController::class)->middleware('throttle:20,1'); + Route::post('reports/activities', ActivityReportController::class)->middleware('throttle:20,1'); + Route::post('reports/client_contacts', ClientContactReportController::class)->middleware('throttle:20,1'); + Route::post('reports/contacts', ClientContactReportController::class)->middleware('throttle:20,1'); + Route::post('reports/credits', CreditReportController::class)->middleware('throttle:20,1'); + Route::post('reports/documents', DocumentReportController::class)->middleware('throttle:20,1'); + Route::post('reports/expenses', ExpenseReportController::class)->middleware('throttle:20,1'); + Route::post('reports/invoices', InvoiceReportController::class)->middleware('throttle:20,1'); + Route::post('reports/invoice_items', InvoiceItemReportController::class)->middleware('throttle:20,1'); + Route::post('reports/quotes', QuoteReportController::class)->middleware('throttle:20,1'); + Route::post('reports/quote_items', QuoteItemReportController::class)->middleware('throttle:20,1'); + Route::post('reports/recurring_invoices', RecurringInvoiceReportController::class)->middleware('throttle:20,1'); + Route::post('reports/payments', PaymentReportController::class)->middleware('throttle:20,1'); + Route::post('reports/products', ProductReportController::class)->middleware('throttle:20,1'); + Route::post('reports/product_sales', ProductSalesReportController::class)->middleware('throttle:20,1'); + Route::post('reports/tasks', TaskReportController::class)->middleware('throttle:20,1'); - Route::post('reports/clients', ClientReportController::class); - Route::post('reports/activities', ActivityReportController::class); - Route::post('reports/client_contacts', ClientContactReportController::class); - Route::post('reports/contacts', ClientContactReportController::class); - Route::post('reports/credits', CreditReportController::class); - Route::post('reports/documents', DocumentReportController::class); - Route::post('reports/expenses', ExpenseReportController::class); - Route::post('reports/invoices', InvoiceReportController::class); - Route::post('reports/invoice_items', InvoiceItemReportController::class); - Route::post('reports/quotes', QuoteReportController::class); - Route::post('reports/quote_items', QuoteItemReportController::class); - Route::post('reports/recurring_invoices', RecurringInvoiceReportController::class); - Route::post('reports/payments', PaymentReportController::class); - Route::post('reports/products', ProductReportController::class); - Route::post('reports/product_sales', ProductSalesReportController::class); - Route::post('reports/tasks', TaskReportController::class); Route::post('reports/profitloss', ProfitAndLossController::class); - Route::post('reports/ar_detail_report', ARDetailReportController::class); Route::post('reports/ar_summary_report', ARSummaryReportController::class); Route::post('reports/client_balance_report', ClientBalanceReportController::class); @@ -402,4 +402,6 @@ Route::post('api/v1/yodlee/data_updates', [YodleeController::class, 'dataUpdates Route::post('api/v1/yodlee/refresh_updates', [YodleeController::class, 'refreshUpdatesWebhook'])->middleware('throttle:100,1'); Route::post('api/v1/yodlee/balance', [YodleeController::class, 'balanceWebhook'])->middleware('throttle:100,1'); +Route::get('api/v1/protected_download/{hash}', [ProtectedDownloadController::class, 'index'])->name('protected_download')->middleware('signed')->middleware('throttle:300,1'); + Route::fallback([BaseController::class, 'notFound'])->middleware('throttle:404'); \ No newline at end of file diff --git a/routes/console.php b/routes/console.php index 75dd0cdedb..41e4c31bb1 100644 --- a/routes/console.php +++ b/routes/console.php @@ -11,8 +11,4 @@ use Illuminate\Foundation\Inspiring; | commands. Each Closure is bound to a command instance allowing a | simple approach to interacting with each command's IO methods. | -*/ - -Artisan::command('inspire', function () { - $this->comment(Inspiring::quote()); -})->describe('Display an inspiring quote'); +*/ \ No newline at end of file