Lint PHP code psr-12, add GH action
This commit is contained in:
@@ -5,8 +5,6 @@ namespace App\Http\Controllers\Admin;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Forms\Form;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class ImpersonationController extends Controller
|
||||
{
|
||||
@@ -15,7 +13,8 @@ class ImpersonationController extends Controller
|
||||
$this->middleware('moderator');
|
||||
}
|
||||
|
||||
public function impersonate($identifier) {
|
||||
public function impersonate($identifier)
|
||||
{
|
||||
$user = null;
|
||||
if (is_numeric($identifier)) {
|
||||
$user = User::find($identifier);
|
||||
@@ -29,17 +28,17 @@ class ImpersonationController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
if (!$user) {
|
||||
if (! $user) {
|
||||
return $this->error([
|
||||
'message'=> 'User not found.'
|
||||
'message' => 'User not found.',
|
||||
]);
|
||||
} else if ($user->admin) {
|
||||
} elseif ($user->admin) {
|
||||
return $this->error([
|
||||
'message' => 'You cannot impersonate an admin.',
|
||||
]);
|
||||
}
|
||||
|
||||
\Log::warning('Impersonation started',[
|
||||
\Log::warning('Impersonation started', [
|
||||
'from_id' => auth()->id(),
|
||||
'from_email' => auth()->user()->email,
|
||||
'target_id' => $user->id,
|
||||
@@ -52,7 +51,7 @@ class ImpersonationController extends Controller
|
||||
])->login($user);
|
||||
|
||||
return $this->success([
|
||||
'token' => $token
|
||||
'token' => $token,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,14 +17,16 @@ class AppSumoAuthController extends Controller
|
||||
|
||||
public function handleCallback(Request $request)
|
||||
{
|
||||
if (!$code = $request->code) {
|
||||
if (! $code = $request->code) {
|
||||
return response()->json(['message' => 'Healthy'], 200);
|
||||
}
|
||||
$accessToken = $this->retrieveAccessToken($code);
|
||||
$license = $this->fetchOrCreateLicense($accessToken);
|
||||
|
||||
// If user connected, attach license
|
||||
if (Auth::check()) return $this->attachLicense($license);
|
||||
if (Auth::check()) {
|
||||
return $this->attachLicense($license);
|
||||
}
|
||||
|
||||
// otherwise start login flow by passing the encrypted license key id
|
||||
if (is_null($license->user_id)) {
|
||||
@@ -37,7 +39,7 @@ class AppSumoAuthController extends Controller
|
||||
private function retrieveAccessToken(string $requestCode): string
|
||||
{
|
||||
return Http::withHeaders([
|
||||
'Content-type' => 'application/json'
|
||||
'Content-type' => 'application/json',
|
||||
])->post('https://appsumo.com/openid/token/', [
|
||||
'grant_type' => 'authorization_code',
|
||||
'code' => $requestCode,
|
||||
@@ -50,13 +52,13 @@ class AppSumoAuthController extends Controller
|
||||
private function fetchOrCreateLicense(string $accessToken): License
|
||||
{
|
||||
// Fetch license from API
|
||||
$licenseKey = Http::get('https://appsumo.com/openid/license_key/?access_token=' . $accessToken)
|
||||
$licenseKey = Http::get('https://appsumo.com/openid/license_key/?access_token='.$accessToken)
|
||||
->throw()
|
||||
->json('license_key');
|
||||
|
||||
// Fetch or create license model
|
||||
$license = License::where('license_provider','appsumo')->where('license_key',$licenseKey)->first();
|
||||
if (!$license) {
|
||||
$license = License::where('license_provider', 'appsumo')->where('license_key', $licenseKey)->first();
|
||||
if (! $license) {
|
||||
$licenseData = Http::withHeaders([
|
||||
'X-AppSumo-Licensing-Key' => config('services.appsumo.api_key'),
|
||||
])->get('https://api.licensing.appsumo.com/v2/licenses/'.$licenseKey)->json();
|
||||
@@ -73,8 +75,9 @@ class AppSumoAuthController extends Controller
|
||||
return $license;
|
||||
}
|
||||
|
||||
private function attachLicense(License $license) {
|
||||
if (!Auth::check()) {
|
||||
private function attachLicense(License $license)
|
||||
{
|
||||
if (! Auth::check()) {
|
||||
throw new AuthenticationException('User not authenticated');
|
||||
}
|
||||
|
||||
@@ -82,6 +85,7 @@ class AppSumoAuthController extends Controller
|
||||
if (is_null($license->user_id)) {
|
||||
$license->user_id = Auth::id();
|
||||
$license->save();
|
||||
|
||||
return redirect(front_url('/home?appsumo_connect=1'));
|
||||
}
|
||||
|
||||
@@ -90,8 +94,6 @@ class AppSumoAuthController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @param string|null $licenseHash
|
||||
* @return string|null
|
||||
*
|
||||
* Returns null if no license found
|
||||
@@ -100,7 +102,7 @@ class AppSumoAuthController extends Controller
|
||||
*/
|
||||
public static function registerWithLicense(User $user, ?string $licenseHash): ?bool
|
||||
{
|
||||
if (!$licenseHash) {
|
||||
if (! $licenseHash) {
|
||||
return null;
|
||||
}
|
||||
$licenseId = decrypt($licenseHash);
|
||||
@@ -109,6 +111,7 @@ class AppSumoAuthController extends Controller
|
||||
if ($license && is_null($license->user_id)) {
|
||||
$license->user_id = $user->id;
|
||||
$license->save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ class ForgotPasswordController extends Controller
|
||||
/**
|
||||
* Get the response for a successful password reset link.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string $response
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
@@ -35,7 +34,6 @@ class ForgotPasswordController extends Controller
|
||||
/**
|
||||
* Get the response for a failed password reset link.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string $response
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
|
||||
@@ -26,7 +26,6 @@ class LoginController extends Controller
|
||||
/**
|
||||
* Attempt to log the user into the application.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return bool
|
||||
*/
|
||||
protected function attemptLogin(Request $request)
|
||||
@@ -50,7 +49,6 @@ class LoginController extends Controller
|
||||
/**
|
||||
* Get the needed authorization credentials from the request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
protected function credentials(Request $request)
|
||||
@@ -64,7 +62,6 @@ class LoginController extends Controller
|
||||
/**
|
||||
* Send the response after the user was authenticated.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
protected function sendLoginResponse(Request $request)
|
||||
@@ -84,7 +81,6 @@ class LoginController extends Controller
|
||||
/**
|
||||
* Get the failed login response instance.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
@@ -104,7 +100,6 @@ class LoginController extends Controller
|
||||
/**
|
||||
* Log the user out of the application.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function logout(Request $request)
|
||||
|
||||
@@ -28,7 +28,7 @@ class OAuthController extends Controller
|
||||
/**
|
||||
* Redirect the user to the provider authentication page.
|
||||
*
|
||||
* @param string $provider
|
||||
* @param string $provider
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function redirect($provider)
|
||||
@@ -41,7 +41,7 @@ class OAuthController extends Controller
|
||||
/**
|
||||
* Obtain the user information from the provider.
|
||||
*
|
||||
* @param string $driver
|
||||
* @param string $driver
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function handleCallback($provider)
|
||||
@@ -61,8 +61,8 @@ class OAuthController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $provider
|
||||
* @param \Laravel\Socialite\Contracts\User $sUser
|
||||
* @param string $provider
|
||||
* @param \Laravel\Socialite\Contracts\User $sUser
|
||||
* @return \App\Models\User
|
||||
*/
|
||||
protected function findOrCreateUser($provider, $user)
|
||||
@@ -81,15 +81,15 @@ class OAuthController extends Controller
|
||||
}
|
||||
|
||||
if (User::where('email', $user->getEmail())->exists()) {
|
||||
throw new EmailTakenException;
|
||||
throw new EmailTakenException();
|
||||
}
|
||||
|
||||
return $this->createUser($provider, $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $provider
|
||||
* @param \Laravel\Socialite\Contracts\User $sUser
|
||||
* @param string $provider
|
||||
* @param \Laravel\Socialite\Contracts\User $sUser
|
||||
* @return \App\Models\User
|
||||
*/
|
||||
protected function createUser($provider, $sUser)
|
||||
|
||||
@@ -4,8 +4,8 @@ namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Resources\UserResource;
|
||||
use App\Models\Workspace;
|
||||
use App\Models\User;
|
||||
use App\Models\Workspace;
|
||||
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use Illuminate\Foundation\Auth\RegistersUsers;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -31,8 +31,7 @@ class RegisterController extends Controller
|
||||
/**
|
||||
* The user has been registered.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \App\User $user
|
||||
* @param \App\User $user
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
protected function registered(Request $request, User $user)
|
||||
@@ -45,13 +44,13 @@ class RegisterController extends Controller
|
||||
(new UserResource($user))->toArray($request),
|
||||
[
|
||||
'appsumo_license' => $this->appsumoLicense,
|
||||
]));
|
||||
]
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a validator for an incoming registration request.
|
||||
*
|
||||
* @param array $data
|
||||
* @return \Illuminate\Contracts\Validation\Validator
|
||||
*/
|
||||
protected function validator(array $data)
|
||||
@@ -64,14 +63,13 @@ class RegisterController extends Controller
|
||||
'agree_terms' => ['required', Rule::in([true])],
|
||||
'appsumo_license' => ['nullable'],
|
||||
], [
|
||||
'agree_terms' => 'Please agree with the terms and conditions.'
|
||||
'agree_terms' => 'Please agree with the terms and conditions.',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new user instance after a valid registration.
|
||||
*
|
||||
* @param array $data
|
||||
* @return \App\User
|
||||
*/
|
||||
protected function create(array $data)
|
||||
@@ -85,14 +83,14 @@ class RegisterController extends Controller
|
||||
'name' => $data['name'],
|
||||
'email' => strtolower($data['email']),
|
||||
'password' => bcrypt($data['password']),
|
||||
'hear_about_us' => $data['hear_about_us']
|
||||
'hear_about_us' => $data['hear_about_us'],
|
||||
]);
|
||||
|
||||
// Add relation with user
|
||||
$user->workspaces()->sync([
|
||||
$workspace->id => [
|
||||
'role' => 'admin'
|
||||
]
|
||||
'role' => 'admin',
|
||||
],
|
||||
], false);
|
||||
|
||||
$this->appsumoLicense = AppSumoAuthController::registerWithLicense($user, $data['appsumo_license'] ?? null);
|
||||
|
||||
@@ -23,7 +23,6 @@ class ResetPasswordController extends Controller
|
||||
/**
|
||||
* Get the response for a successful password reset.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string $response
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
@@ -35,7 +34,6 @@ class ResetPasswordController extends Controller
|
||||
/**
|
||||
* Get the response for a failed password reset.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string $response
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
|
||||
@@ -11,23 +11,24 @@ class UserController extends Controller
|
||||
{
|
||||
/**
|
||||
* Get authenticated user.
|
||||
*
|
||||
*/
|
||||
public function current(Request $request)
|
||||
{
|
||||
return new UserResource($request->user());
|
||||
}
|
||||
|
||||
public function deleteAccount() {
|
||||
public function deleteAccount()
|
||||
{
|
||||
$this->middleware('auth');
|
||||
if (Auth::user()->admin) {
|
||||
return $this->error([
|
||||
'message' => 'Cannot delete an admin. Stay with us 🙏'
|
||||
'message' => 'Cannot delete an admin. Stay with us 🙏',
|
||||
]);
|
||||
}
|
||||
Auth::user()->delete();
|
||||
|
||||
return $this->success([
|
||||
'message' => 'User deleted.'
|
||||
'message' => 'User deleted.',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,7 @@ class VerificationController extends Controller
|
||||
/**
|
||||
* Mark the user's email address as verified.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \App\User $user
|
||||
* @param \App\User $user
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function verify(Request $request, User $user)
|
||||
@@ -54,7 +53,6 @@ class VerificationController extends Controller
|
||||
/**
|
||||
* Resend the email verification notification.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function resend(Request $request)
|
||||
|
||||
@@ -15,29 +15,30 @@ class CaddyController extends Controller
|
||||
]);
|
||||
// make sure domain is valid
|
||||
$domain = $request->input('domain');
|
||||
if (!preg_match(CustomDomainRequest::CUSTOM_DOMAINS_REGEX, $domain)) {
|
||||
if (! preg_match(CustomDomainRequest::CUSTOM_DOMAINS_REGEX, $domain)) {
|
||||
return $this->error([
|
||||
'success' => false,
|
||||
'message' => 'Invalid domain',
|
||||
]);
|
||||
}
|
||||
|
||||
\Log::info('Caddy request received',[
|
||||
\Log::info('Caddy request received', [
|
||||
'domain' => $domain,
|
||||
]);
|
||||
|
||||
if ($workspace = Workspace::whereJsonContains('custom_domains',$domain)->first()) {
|
||||
\Log::info('Caddy request successful',[
|
||||
if ($workspace = Workspace::whereJsonContains('custom_domains', $domain)->first()) {
|
||||
\Log::info('Caddy request successful', [
|
||||
'domain' => $domain,
|
||||
'workspace' => $workspace->id,
|
||||
]);
|
||||
|
||||
return $this->success([
|
||||
'success' => true,
|
||||
'message' => 'OK',
|
||||
]);
|
||||
}
|
||||
|
||||
\Log::info('Caddy request failed',[
|
||||
\Log::info('Caddy request failed', [
|
||||
'domain' => $domain,
|
||||
'workspace' => $workspace?->id,
|
||||
]);
|
||||
|
||||
@@ -3,19 +3,19 @@
|
||||
namespace App\Http\Controllers\Content;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ChangelogController extends Controller
|
||||
{
|
||||
const CANNY_ENDPOINT = 'https://canny.io/api/v1/';
|
||||
public const CANNY_ENDPOINT = 'https://canny.io/api/v1/';
|
||||
|
||||
public function index()
|
||||
{
|
||||
return \Cache::remember('changelog_entries', now()->addHour(), function () {
|
||||
$response = \Http:: post(self::CANNY_ENDPOINT.'entries/list',[
|
||||
$response = \Http::post(self::CANNY_ENDPOINT.'entries/list', [
|
||||
'apiKey' => config('services.canny.api_key'),
|
||||
'limit' => 3,
|
||||
]);
|
||||
|
||||
return $response->json('entries');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ class FileUploadController extends Controller
|
||||
/**
|
||||
* Upload file to local temp
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function upload(Request $request)
|
||||
@@ -23,7 +22,7 @@ class FileUploadController extends Controller
|
||||
|
||||
return response()->json([
|
||||
'uuid' => $uuid,
|
||||
'key' => $path
|
||||
'key' => $path,
|
||||
], 201);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,19 +2,15 @@
|
||||
|
||||
namespace App\Http\Controllers\Content;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
use Laravel\Vapor\Http\Controllers\SignedStorageUrlController as Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class SignedStorageUrlController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new signed URL.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(Request $request)
|
||||
|
||||
@@ -9,19 +9,21 @@ use Illuminate\Routing\Controller as BaseController;
|
||||
|
||||
class Controller extends BaseController
|
||||
{
|
||||
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
|
||||
use AuthorizesRequests;
|
||||
use DispatchesJobs;
|
||||
use ValidatesRequests;
|
||||
|
||||
public function success($data = [])
|
||||
{
|
||||
return response()->json(array_merge([
|
||||
'type' => 'success'
|
||||
'type' => 'success',
|
||||
], $data));
|
||||
}
|
||||
|
||||
public function error($data = [], $statusCode = 400)
|
||||
{
|
||||
return response()->json(array_merge([
|
||||
'type' => 'error'
|
||||
'type' => 'error',
|
||||
], $data), $statusCode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,6 @@ namespace App\Http\Controllers\Forms;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\AiGenerateFormRequest;
|
||||
use App\Models\Forms\AI\AiFormCompletion;
|
||||
use App\Service\OpenAi\GptCompleter;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class AiFormController extends Controller
|
||||
{
|
||||
@@ -18,8 +16,8 @@ class AiFormController extends Controller
|
||||
'message' => 'We\'re working on your form, please wait ~1 min.',
|
||||
'ai_form_completion_id' => AiFormCompletion::create([
|
||||
'form_prompt' => $request->input('form_prompt'),
|
||||
'ip' => $request->ip()
|
||||
])->id
|
||||
'ip' => $request->ip(),
|
||||
])->id,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -30,7 +28,7 @@ class AiFormController extends Controller
|
||||
}
|
||||
|
||||
return $this->success([
|
||||
'ai_form_completion' => $aiFormCompletion
|
||||
'ai_form_completion' => $aiFormCompletion,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ use Illuminate\Support\Str;
|
||||
|
||||
class FormController extends Controller
|
||||
{
|
||||
const ASSETS_UPLOAD_PATH = 'assets/forms';
|
||||
public const ASSETS_UPLOAD_PATH = 'assets/forms';
|
||||
|
||||
private FormCleaner $formCleaner;
|
||||
|
||||
@@ -36,26 +36,28 @@ class FormController extends Controller
|
||||
$workspaceIsPro = $workspace->is_pro;
|
||||
$forms = $workspace->forms()
|
||||
->orderByDesc('updated_at')
|
||||
->paginate(10)->through(function (Form $form) use ($workspace, $workspaceIsPro){
|
||||
->paginate(10)->through(function (Form $form) use ($workspace, $workspaceIsPro) {
|
||||
|
||||
// Add attributes for faster loading
|
||||
$form->extra = (object) [
|
||||
'loadedWorkspace' => $workspace,
|
||||
'workspaceIsPro' => $workspaceIsPro,
|
||||
'userIsOwner' => true,
|
||||
'cleanings' => $this->formCleaner
|
||||
->processForm(request(), $form)
|
||||
->simulateCleaning($workspace)
|
||||
->getPerformedCleanings()
|
||||
];
|
||||
// Add attributes for faster loading
|
||||
$form->extra = (object) [
|
||||
'loadedWorkspace' => $workspace,
|
||||
'workspaceIsPro' => $workspaceIsPro,
|
||||
'userIsOwner' => true,
|
||||
'cleanings' => $this->formCleaner
|
||||
->processForm(request(), $form)
|
||||
->simulateCleaning($workspace)
|
||||
->getPerformedCleanings(),
|
||||
];
|
||||
|
||||
return $form;
|
||||
});
|
||||
|
||||
return $form;
|
||||
});
|
||||
return FormResource::collection($forms);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all user forms, used for zapier
|
||||
*
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function indexAll()
|
||||
@@ -66,18 +68,20 @@ class FormController extends Controller
|
||||
$this->authorize('viewAny', Form::class);
|
||||
|
||||
$workspaceIsPro = $workspace->is_pro;
|
||||
$newForms = $workspace->forms()->get()->map(function (Form $form) use ($workspace, $workspaceIsPro){
|
||||
$newForms = $workspace->forms()->get()->map(function (Form $form) use ($workspace, $workspaceIsPro) {
|
||||
// Add attributes for faster loading
|
||||
$form->extra = (object) [
|
||||
'loadedWorkspace' => $workspace,
|
||||
'workspaceIsPro' => $workspaceIsPro,
|
||||
'userIsOwner' => true,
|
||||
];
|
||||
|
||||
return $form;
|
||||
});
|
||||
|
||||
$forms = $forms->merge($newForms);
|
||||
}
|
||||
|
||||
return FormResource::collection($forms);
|
||||
}
|
||||
|
||||
@@ -94,13 +98,13 @@ class FormController extends Controller
|
||||
->getData();
|
||||
|
||||
$form = Form::create(array_merge($formData, [
|
||||
'creator_id' => $request->user()->id
|
||||
'creator_id' => $request->user()->id,
|
||||
]));
|
||||
|
||||
return $this->success([
|
||||
'message' => $this->formCleaner->hasCleaned() ? 'Form successfully created, but the Pro features you used will be disabled when sharing your form:' : 'Form created.' . ($form->visibility == 'draft' ? ' But other people won\'t be able to see the form since it\'s currently in draft mode' : ''),
|
||||
'message' => $this->formCleaner->hasCleaned() ? 'Form successfully created, but the Pro features you used will be disabled when sharing your form:' : 'Form created.'.($form->visibility == 'draft' ? ' But other people won\'t be able to see the form since it\'s currently in draft mode' : ''),
|
||||
'form' => (new FormResource($form))->setCleanings($this->formCleaner->getPerformedCleanings()),
|
||||
'users_first_form' => $request->user()->forms()->count() == 1
|
||||
'users_first_form' => $request->user()->forms()->count() == 1,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -116,13 +120,13 @@ class FormController extends Controller
|
||||
|
||||
// Set Removed Properties
|
||||
$formData['removed_properties'] = array_merge($form->removed_properties, collect($form->properties)->filter(function ($field) use ($formData) {
|
||||
return (!Str::of($field['type'])->startsWith('nf-') && !in_array($field['id'], collect($formData['properties'])->pluck("id")->toArray()));
|
||||
return ! Str::of($field['type'])->startsWith('nf-') && ! in_array($field['id'], collect($formData['properties'])->pluck('id')->toArray());
|
||||
})->toArray());
|
||||
|
||||
$form->update($formData);
|
||||
|
||||
return $this->success([
|
||||
'message' => $this->formCleaner->hasCleaned() ? 'Form successfully updated, but the Pro features you used will be disabled when sharing your form:' : 'Form updated.' . ($form->visibility == 'draft' ? ' But other people won\'t be able to see the form since it\'s currently in draft mode' : ''),
|
||||
'message' => $this->formCleaner->hasCleaned() ? 'Form successfully updated, but the Pro features you used will be disabled when sharing your form:' : 'Form updated.'.($form->visibility == 'draft' ? ' But other people won\'t be able to see the form since it\'s currently in draft mode' : ''),
|
||||
'form' => (new FormResource($form))->setCleanings($this->formCleaner->getPerformedCleanings()),
|
||||
]);
|
||||
}
|
||||
@@ -133,8 +137,9 @@ class FormController extends Controller
|
||||
$this->authorize('delete', $form);
|
||||
|
||||
$form->delete();
|
||||
|
||||
return $this->success([
|
||||
'message' => 'Form was deleted.'
|
||||
'message' => 'Form was deleted.',
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -150,7 +155,7 @@ class FormController extends Controller
|
||||
|
||||
return $this->success([
|
||||
'message' => 'Form successfully duplicated.',
|
||||
'new_form' => new FormResource($formCopy)
|
||||
'new_form' => new FormResource($formCopy),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -159,7 +164,7 @@ class FormController extends Controller
|
||||
$form = Form::findOrFail($id);
|
||||
$this->authorize('update', $form);
|
||||
|
||||
if ( $option == 'slug') {
|
||||
if ($option == 'slug') {
|
||||
$form->generateSlug();
|
||||
} elseif ($option == 'uuid') {
|
||||
$form->slug = Str::uuid();
|
||||
@@ -168,7 +173,7 @@ class FormController extends Controller
|
||||
|
||||
return $this->success([
|
||||
'message' => 'Form url successfully updated. Your new form url now is: '.$form->share_url.'.',
|
||||
'form' => new FormResource($form)
|
||||
'form' => new FormResource($form),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -182,8 +187,8 @@ class FormController extends Controller
|
||||
$fileNameParser = StorageFileNameParser::parse($request->url);
|
||||
|
||||
// Make sure we retrieve the file in tmp storage, move it to persistent
|
||||
$fileName = PublicFormController::TMP_FILE_UPLOAD_PATH.'/'.$fileNameParser->uuid;;
|
||||
if (!Storage::exists($fileName)) {
|
||||
$fileName = PublicFormController::TMP_FILE_UPLOAD_PATH.'/'.$fileNameParser->uuid;
|
||||
if (! Storage::exists($fileName)) {
|
||||
// File not found, we skip
|
||||
return null;
|
||||
}
|
||||
@@ -192,7 +197,7 @@ class FormController extends Controller
|
||||
|
||||
return $this->success([
|
||||
'message' => 'File uploaded.',
|
||||
'url' => route("forms.assets.show", [$fileNameParser->getMovedFileName()])
|
||||
'url' => route('forms.assets.show', [$fileNameParser->getMovedFileName()]),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -205,9 +210,9 @@ class FormController extends Controller
|
||||
$this->authorize('view', $form);
|
||||
|
||||
$path = Str::of(PublicFormController::FILE_UPLOAD_PATH)->replace('?', $form->id).'/'.$fileName;
|
||||
if (!Storage::exists($path)) {
|
||||
if (! Storage::exists($path)) {
|
||||
return $this->error([
|
||||
'message' => 'File not found.'
|
||||
'message' => 'File not found.',
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,20 +19,21 @@ class FormStatsController extends Controller
|
||||
|
||||
$this->authorize('view', $form);
|
||||
|
||||
$formStats = $form->statistics()->where('date','>',now()->subDays(29)->startOfDay())->get();
|
||||
$periodStats = ["views" => [], "submissions" => []];
|
||||
$formStats = $form->statistics()->where('date', '>', now()->subDays(29)->startOfDay())->get();
|
||||
$periodStats = ['views' => [], 'submissions' => []];
|
||||
foreach (CarbonPeriod::create(now()->subDays(29), now()) as $dateObj) {
|
||||
$date = $dateObj->format('d-m-Y');
|
||||
|
||||
$statisticData = $formStats->where('date', $dateObj->format('Y-m-d'))->first();
|
||||
$periodStats["views"][$date] = $statisticData->data["views"] ?? 0;
|
||||
$periodStats["submissions"][$date] = $statisticData->data["submissions"] ?? 0;
|
||||
$periodStats['views'][$date] = $statisticData->data['views'] ?? 0;
|
||||
$periodStats['submissions'][$date] = $statisticData->data['submissions'] ?? 0;
|
||||
|
||||
if($dateObj->toDateString() === now()->toDateString()){
|
||||
$periodStats["views"][$date] += $form->views()->count();
|
||||
$periodStats["submissions"][$date] += $form->submissions()->whereDate('created_at', '>=', now()->startOfDay())->count();
|
||||
if ($dateObj->toDateString() === now()->toDateString()) {
|
||||
$periodStats['views'][$date] += $form->views()->count();
|
||||
$periodStats['submissions'][$date] += $form->submissions()->whereDate('created_at', '>=', now()->startOfDay())->count();
|
||||
}
|
||||
}
|
||||
|
||||
return $periodStats;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,14 @@
|
||||
|
||||
namespace App\Http\Controllers\Forms;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Resources\FormSubmissionResource;
|
||||
use App\Models\Forms\Form;
|
||||
use App\Exports\FormSubmissionExport;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\AnswerFormRequest;
|
||||
use App\Http\Resources\FormSubmissionResource;
|
||||
use App\Jobs\Form\StoreFormSubmissionJob;
|
||||
use App\Models\Forms\Form;
|
||||
use App\Models\Forms\FormSubmission;
|
||||
use App\Service\Forms\FormSubmissionFormatter;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
@@ -26,7 +25,7 @@ class FormSubmissionController extends Controller
|
||||
|
||||
public function submissions(string $id)
|
||||
{
|
||||
$form = Form::findOrFail((int)$id);
|
||||
$form = Form::findOrFail((int) $id);
|
||||
$this->authorize('view', $form);
|
||||
|
||||
return FormSubmissionResource::collection($form->submissions()->paginate(100));
|
||||
@@ -40,15 +39,16 @@ class FormSubmissionController extends Controller
|
||||
$job->setSubmissionId($submissionId)->handle();
|
||||
|
||||
$data = new FormSubmissionResource(FormSubmission::findOrFail($submissionId));
|
||||
|
||||
return $this->success([
|
||||
'message' => 'Record successfully updated.',
|
||||
'data' => $data
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
public function export(string $id)
|
||||
{
|
||||
$form = Form::findOrFail((int)$id);
|
||||
$form = Form::findOrFail((int) $id);
|
||||
$this->authorize('view', $form);
|
||||
|
||||
$allRows = [];
|
||||
@@ -61,24 +61,25 @@ class FormSubmissionController extends Controller
|
||||
->useSignedUrlForFiles();
|
||||
$allRows[] = [
|
||||
'id' => Hashids::encode($row['id']),
|
||||
'created_at' => date("Y-m-d H:i", strtotime($row['created_at'])),
|
||||
...$formatter->getCleanKeyValue()
|
||||
'created_at' => date('Y-m-d H:i', strtotime($row['created_at'])),
|
||||
...$formatter->getCleanKeyValue(),
|
||||
];
|
||||
}
|
||||
$csvExport = (new FormSubmissionExport($allRows));
|
||||
|
||||
return Excel::download(
|
||||
$csvExport,
|
||||
$form->slug . '-submission-data.csv',
|
||||
$form->slug.'-submission-data.csv',
|
||||
\Maatwebsite\Excel\Excel::CSV
|
||||
);
|
||||
}
|
||||
|
||||
public function submissionFile($id, $fileName)
|
||||
{
|
||||
$fileName = Str::of(PublicFormController::FILE_UPLOAD_PATH)->replace('?', $id) . '/'
|
||||
. urldecode($fileName);
|
||||
$fileName = Str::of(PublicFormController::FILE_UPLOAD_PATH)->replace('?', $id).'/'
|
||||
.urldecode($fileName);
|
||||
|
||||
if (!Storage::exists($fileName)) {
|
||||
if (! Storage::exists($fileName)) {
|
||||
return $this->error([
|
||||
'message' => 'File not found.',
|
||||
], 404);
|
||||
|
||||
@@ -5,35 +5,38 @@ namespace App\Http\Controllers\Forms\Integration;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Integration\StoreFormZapierWebhookRequest;
|
||||
use App\Models\Integration\FormZapierWebhook;
|
||||
use Illuminate\Http\Request;
|
||||
use Spatie\WebhookServer\WebhookCall;
|
||||
|
||||
class FormZapierWebhookController extends Controller
|
||||
{
|
||||
/**
|
||||
* Controller for Zappier webhook subscriptions.
|
||||
*/
|
||||
public function __construct() {
|
||||
// $this->middleware('subscribed');
|
||||
public function __construct()
|
||||
{
|
||||
// $this->middleware('subscribed');
|
||||
$this->middleware('auth');
|
||||
}
|
||||
|
||||
public function store(StoreFormZapierWebhookRequest $request) {
|
||||
public function store(StoreFormZapierWebhookRequest $request)
|
||||
{
|
||||
$hook = $request->instanciateHook();
|
||||
$this->authorize('store', $hook);
|
||||
|
||||
$hook->save();
|
||||
|
||||
return $this->success([
|
||||
'message' => 'Webhook created.',
|
||||
'hook' => $hook
|
||||
'hook' => $hook,
|
||||
]);
|
||||
}
|
||||
|
||||
public function delete($id) {
|
||||
public function delete($id)
|
||||
{
|
||||
$hook = FormZapierWebhook::findOrFail($id);
|
||||
$this->authorize('store', $hook);
|
||||
|
||||
$hook->delete();
|
||||
|
||||
return $this->success([
|
||||
'message' => 'Webhook deleted.',
|
||||
]);
|
||||
|
||||
@@ -11,15 +11,15 @@ use App\Models\Forms\FormSubmission;
|
||||
use App\Service\Forms\FormCleaner;
|
||||
use App\Service\WorkspaceHelper;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Vinkla\Hashids\Facades\Hashids;
|
||||
|
||||
class PublicFormController extends Controller
|
||||
{
|
||||
public const FILE_UPLOAD_PATH = 'forms/?/submissions';
|
||||
|
||||
const FILE_UPLOAD_PATH = 'forms/?/submissions';
|
||||
const TMP_FILE_UPLOAD_PATH = 'tmp/';
|
||||
public const TMP_FILE_UPLOAD_PATH = 'tmp/';
|
||||
|
||||
public function show(Request $request, string $slug)
|
||||
{
|
||||
@@ -27,21 +27,22 @@ class PublicFormController extends Controller
|
||||
if ($form->workspace == null) {
|
||||
// Workspace deleted
|
||||
return $this->error([
|
||||
'message' => 'Form not found.'
|
||||
'message' => 'Form not found.',
|
||||
], 404);
|
||||
}
|
||||
|
||||
$formCleaner = new FormCleaner();
|
||||
|
||||
// Disable pro features if needed
|
||||
$form->fill($formCleaner
|
||||
$form->fill(
|
||||
$formCleaner
|
||||
->processForm($request, $form)
|
||||
->performCleaning($form->workspace)
|
||||
->getData()
|
||||
);
|
||||
|
||||
// Increase form view counter if not login
|
||||
if(!Auth::check()){
|
||||
if (! Auth::check()) {
|
||||
$form->views()->create();
|
||||
}
|
||||
|
||||
@@ -53,25 +54,26 @@ class PublicFormController extends Controller
|
||||
{
|
||||
// Check that form has user field
|
||||
$form = $request->form;
|
||||
if (!$form->has_user_field) {
|
||||
if (! $form->has_user_field) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Use serializer
|
||||
$workspace = $form->workspace;
|
||||
|
||||
return (new WorkspaceHelper($workspace))->getAllUsers();
|
||||
}
|
||||
|
||||
public function showAsset($assetFileName)
|
||||
{
|
||||
$path = FormController::ASSETS_UPLOAD_PATH.'/'.$assetFileName;
|
||||
if (!Storage::exists($path)) {
|
||||
if (! Storage::exists($path)) {
|
||||
return $this->error([
|
||||
'message' => 'File not found.',
|
||||
'file_name' => $assetFileName
|
||||
'file_name' => $assetFileName,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
return redirect()->to(Storage::temporaryUrl($path, now()->addMinutes(5)));
|
||||
}
|
||||
|
||||
@@ -84,18 +86,18 @@ class PublicFormController extends Controller
|
||||
$job = new StoreFormSubmissionJob($form, $request->validated());
|
||||
$job->handle();
|
||||
$submissionId = Hashids::encode($job->getSubmissionId());
|
||||
}else{
|
||||
} else {
|
||||
StoreFormSubmissionJob::dispatch($form, $request->validated());
|
||||
}
|
||||
|
||||
return $this->success(array_merge([
|
||||
'message' => 'Form submission saved.',
|
||||
'submission_id' => $submissionId
|
||||
'submission_id' => $submissionId,
|
||||
], $request->form->is_pro && $request->form->redirect_url ? [
|
||||
'redirect' => true,
|
||||
'redirect_url' => $request->form->redirect_url
|
||||
'redirect_url' => $request->form->redirect_url,
|
||||
] : [
|
||||
'redirect' => false
|
||||
'redirect' => false,
|
||||
]));
|
||||
}
|
||||
|
||||
@@ -104,7 +106,7 @@ class PublicFormController extends Controller
|
||||
$submissionId = ($submissionId) ? Hashids::decode($submissionId) : false;
|
||||
$submissionId = isset($submissionId[0]) ? $submissionId[0] : false;
|
||||
$form = Form::whereSlug($slug)->whereVisibility('public')->firstOrFail();
|
||||
if ($form->workspace == null || !$form->editable_submissions || !$submissionId) {
|
||||
if ($form->workspace == null || ! $form->editable_submissions || ! $submissionId) {
|
||||
return $this->error([
|
||||
'message' => 'Not allowed.',
|
||||
]);
|
||||
@@ -120,5 +122,4 @@ class PublicFormController extends Controller
|
||||
|
||||
return $this->success(['data' => ($submission) ? $submission->data : []]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,8 +17,7 @@ class RecordController extends Controller
|
||||
$record->delete();
|
||||
|
||||
return $this->success([
|
||||
'message' => 'Record successfully removed.'
|
||||
'message' => 'Record successfully removed.',
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ class PasswordController extends Controller
|
||||
/**
|
||||
* Update the user's password.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(Request $request)
|
||||
|
||||
@@ -10,7 +10,6 @@ class ProfileController extends Controller
|
||||
/**
|
||||
* Update the user's profile information.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(Request $request)
|
||||
|
||||
@@ -2,18 +2,15 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Spatie\Sitemap\Sitemap;
|
||||
use Spatie\Sitemap\Tags\Url;
|
||||
use App\Models\Template;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class SitemapController extends Controller
|
||||
{
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
return [
|
||||
...$this->getTemplatesUrls()
|
||||
...$this->getTemplatesUrls(),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -23,10 +20,11 @@ class SitemapController extends Controller
|
||||
Template::where('publicly_listed', true)->chunk(100, function ($templates) use (&$urls) {
|
||||
foreach ($templates as $template) {
|
||||
$urls[] = [
|
||||
'loc' => '/templates/' . $template->slug
|
||||
'loc' => '/templates/'.$template->slug,
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
return $urls;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,11 @@ use Laravel\Cashier\Subscription;
|
||||
|
||||
class SubscriptionController extends Controller
|
||||
{
|
||||
const SUBSCRIPTION_PLANS = ['monthly', 'yearly'];
|
||||
public const SUBSCRIPTION_PLANS = ['monthly', 'yearly'];
|
||||
|
||||
const PRO_SUBSCRIPTION_NAME = 'default';
|
||||
const SUBSCRIPTION_NAMES = [
|
||||
public const PRO_SUBSCRIPTION_NAME = 'default';
|
||||
|
||||
public const SUBSCRIPTION_NAMES = [
|
||||
self::PRO_SUBSCRIPTION_NAME,
|
||||
];
|
||||
|
||||
@@ -30,7 +31,7 @@ class SubscriptionController extends Controller
|
||||
if ($user->subscriptions()->where('stripe_status', 'past_due')->first()) {
|
||||
return $this->error([
|
||||
'message' => 'You already have a past due subscription. Please verify your details in the billing page,
|
||||
and contact us if the issue persists.'
|
||||
and contact us if the issue persists.',
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -51,18 +52,18 @@ class SubscriptionController extends Controller
|
||||
'customer_update' => [
|
||||
'address' => 'auto',
|
||||
'name' => 'never',
|
||||
]
|
||||
],
|
||||
]);
|
||||
|
||||
return $this->success([
|
||||
'checkout_url' => $checkout->url
|
||||
'checkout_url' => $checkout->url,
|
||||
]);
|
||||
}
|
||||
|
||||
public function updateStripeDetails(UpdateStripeDetailsRequest $request)
|
||||
{
|
||||
$user = Auth::user();
|
||||
if (!$user->hasStripeId()) {
|
||||
if (! $user->hasStripeId()) {
|
||||
$user->createAsStripeCustomer();
|
||||
}
|
||||
$user->updateStripeCustomer([
|
||||
@@ -78,13 +79,14 @@ class SubscriptionController extends Controller
|
||||
public function billingPortal()
|
||||
{
|
||||
$this->middleware('auth');
|
||||
if (!Auth::user()->has_customer_id) {
|
||||
if (! Auth::user()->has_customer_id) {
|
||||
return $this->error([
|
||||
"message" => "Please subscribe before accessing your billing portal."
|
||||
'message' => 'Please subscribe before accessing your billing portal.',
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->success([
|
||||
'portal_url' => Auth::user()->billingPortalUrl(front_url('/home'))
|
||||
'portal_url' => Auth::user()->billingPortalUrl(front_url('/home')),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Templates\FormTemplateRequest;
|
||||
use App\Http\Resources\FormTemplateResource;
|
||||
use App\Models\Template;
|
||||
@@ -13,20 +12,20 @@ class TemplateController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$limit = (int)$request->get('limit', 0);
|
||||
$onlyMy = (bool)$request->get('onlymy', false);
|
||||
$limit = (int) $request->get('limit', 0);
|
||||
$onlyMy = (bool) $request->get('onlymy', false);
|
||||
|
||||
$templates = Template::when(Auth::check(), function ($query) use ($onlyMy) {
|
||||
if ($onlyMy) {
|
||||
$query->where('creator_id', Auth::id());
|
||||
} else {
|
||||
$query->where(function ($query) {
|
||||
$query->where('publicly_listed', true)
|
||||
->orWhere('creator_id', Auth::id());
|
||||
});
|
||||
}
|
||||
})
|
||||
->when(!Auth::check(), function ($query) {
|
||||
if ($onlyMy) {
|
||||
$query->where('creator_id', Auth::id());
|
||||
} else {
|
||||
$query->where(function ($query) {
|
||||
$query->where('publicly_listed', true)
|
||||
->orWhere('creator_id', Auth::id());
|
||||
});
|
||||
}
|
||||
})
|
||||
->when(! Auth::check(), function ($query) {
|
||||
$query->where('publicly_listed', true);
|
||||
})
|
||||
->when($limit > 0, function ($query) use ($limit) {
|
||||
@@ -49,7 +48,7 @@ class TemplateController extends Controller
|
||||
return $this->success([
|
||||
'message' => 'Template was created.',
|
||||
'template_id' => $template->id,
|
||||
'data' => new FormTemplateResource($template)
|
||||
'data' => new FormTemplateResource($template),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -63,7 +62,7 @@ class TemplateController extends Controller
|
||||
return $this->success([
|
||||
'message' => 'Template was updated.',
|
||||
'template_id' => $template->id,
|
||||
'data' => new FormTemplateResource($template)
|
||||
'data' => new FormTemplateResource($template),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ namespace App\Http\Controllers\Webhook;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\License;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Validation\UnauthorizedException;
|
||||
|
||||
class AppSumoController extends Controller
|
||||
@@ -16,6 +16,7 @@ class AppSumoController extends Controller
|
||||
|
||||
if ($request->test) {
|
||||
Log::info('[APPSUMO] test request received', $request->toArray());
|
||||
|
||||
return $this->success([
|
||||
'message' => 'Webhook received.',
|
||||
'event' => $request->event,
|
||||
@@ -69,11 +70,13 @@ class AppSumoController extends Controller
|
||||
$license->user_id = $licenseData['user_id'] ?? null;
|
||||
$license->save();
|
||||
|
||||
Log::info('[APPSUMO] creating new license',
|
||||
Log::info(
|
||||
'[APPSUMO] creating new license',
|
||||
[
|
||||
'license_key' => $license->license_key,
|
||||
'license_id' => $license->id,
|
||||
]);
|
||||
]
|
||||
);
|
||||
|
||||
return $license;
|
||||
}
|
||||
|
||||
@@ -5,13 +5,11 @@ namespace App\Http\Controllers\Webhook;
|
||||
use App\Notifications\Subscription\FailedPaymentNotification;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Laravel\Cashier\Http\Controllers\WebhookController;
|
||||
use Stripe\Subscription as StripeSubscription;
|
||||
|
||||
class StripeController extends WebhookController
|
||||
{
|
||||
|
||||
public function handleCustomerSubscriptionCreated(array $payload)
|
||||
{
|
||||
return parent::handleCustomerSubscriptionCreated($payload);
|
||||
@@ -19,7 +17,7 @@ class StripeController extends WebhookController
|
||||
|
||||
/**
|
||||
* Override to add a sleep, and to detect plan upgrades
|
||||
* @param array $payload
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response|void
|
||||
*/
|
||||
protected function handleCustomerSubscriptionUpdated(array $payload)
|
||||
@@ -59,7 +57,7 @@ class StripeController extends WebhookController
|
||||
if (isset($data['trial_end'])) {
|
||||
$trialEnd = Carbon::createFromTimestamp($data['trial_end']);
|
||||
|
||||
if (!$subscription->trial_ends_at || $subscription->trial_ends_at->ne($trialEnd)) {
|
||||
if (! $subscription->trial_ends_at || $subscription->trial_ends_at->ne($trialEnd)) {
|
||||
$subscription->trial_ends_at = $trialEnd;
|
||||
}
|
||||
}
|
||||
@@ -125,7 +123,7 @@ class StripeController extends WebhookController
|
||||
return $plan;
|
||||
}
|
||||
}
|
||||
|
||||
return 'default';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@ namespace App\Http\Controllers;
|
||||
use App\Http\Requests\Workspace\CustomDomainRequest;
|
||||
use App\Http\Resources\WorkspaceResource;
|
||||
use App\Models\Workspace;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Service\WorkspaceHelper;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class WorkspaceController extends Controller
|
||||
@@ -19,6 +19,7 @@ class WorkspaceController extends Controller
|
||||
public function index()
|
||||
{
|
||||
$this->authorize('viewAny', Workspace::class);
|
||||
|
||||
return WorkspaceResource::collection(Auth::user()->workspaces);
|
||||
}
|
||||
|
||||
@@ -34,6 +35,7 @@ class WorkspaceController extends Controller
|
||||
{
|
||||
$request->workspace->custom_domains = $request->customDomains;
|
||||
$request->workspace->save();
|
||||
|
||||
return new WorkspaceResource($request->workspace);
|
||||
}
|
||||
|
||||
@@ -44,9 +46,10 @@ class WorkspaceController extends Controller
|
||||
|
||||
$id = $workspace->id;
|
||||
$workspace->delete();
|
||||
|
||||
return $this->success([
|
||||
'message' => 'Workspace deleted.',
|
||||
'workspace_id' => $id
|
||||
'workspace_id' => $id,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -55,7 +58,7 @@ class WorkspaceController extends Controller
|
||||
$user = $request->user();
|
||||
|
||||
$this->validate($request, [
|
||||
'name' => 'required'
|
||||
'name' => 'required',
|
||||
]);
|
||||
|
||||
// Create workspace
|
||||
@@ -67,14 +70,14 @@ class WorkspaceController extends Controller
|
||||
// Add relation with user
|
||||
$user->workspaces()->sync([
|
||||
$workspace->id => [
|
||||
'role' => 'admin'
|
||||
]
|
||||
'role' => 'admin',
|
||||
],
|
||||
], false);
|
||||
|
||||
return $this->success([
|
||||
'message' => 'Workspace created.',
|
||||
'workspace_id' => $workspace->id,
|
||||
'workspace' => new WorkspaceResource($workspace)
|
||||
'workspace' => new WorkspaceResource($workspace),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ class Kernel extends HttpKernel
|
||||
* @var array
|
||||
*/
|
||||
protected $middleware = [
|
||||
// \App\Http\Middleware\TrustHosts::class,
|
||||
// \App\Http\Middleware\TrustHosts::class,
|
||||
\App\Http\Middleware\TrustProxies::class,
|
||||
\Illuminate\Http\Middleware\HandleCors::class,
|
||||
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
|
||||
@@ -32,7 +32,7 @@ class Kernel extends HttpKernel
|
||||
\App\Http\Middleware\SetLocale::class,
|
||||
AuthenticateJWT::class,
|
||||
CustomDomainRestriction::class,
|
||||
AcceptsJsonMiddleware::class
|
||||
AcceptsJsonMiddleware::class,
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,7 +10,6 @@ class AcceptsJsonMiddleware
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
|
||||
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
|
||||
@@ -8,7 +8,7 @@ use Tymon\JWTAuth\Exceptions\JWTException;
|
||||
|
||||
class AuthenticateJWT
|
||||
{
|
||||
const API_SERVER_SECRET_HEADER_NAME = 'x-api-secret';
|
||||
public const API_SERVER_SECRET_HEADER_NAME = 'x-api-secret';
|
||||
|
||||
/**
|
||||
* Verifies the JWT token and validates the IP and User Agent
|
||||
@@ -33,18 +33,19 @@ class AuthenticateJWT
|
||||
}
|
||||
|
||||
$error = null;
|
||||
if (!\Hash::check($request->ip(), $payload->get('ip'))) {
|
||||
if (! \Hash::check($request->ip(), $payload->get('ip'))) {
|
||||
$error = 'Origin IP is invalid';
|
||||
}
|
||||
|
||||
if (!\Hash::check($request->userAgent(), $payload->get('ua'))) {
|
||||
if (! \Hash::check($request->userAgent(), $payload->get('ua'))) {
|
||||
$error = 'Origin User Agent is invalid';
|
||||
}
|
||||
|
||||
if ($error) {
|
||||
auth()->invalidate();
|
||||
|
||||
return response()->json([
|
||||
'message' => $error
|
||||
'message' => $error,
|
||||
], 403);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,14 +12,14 @@ class CaddyRequestMiddleware
|
||||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if (!config('custom-domains.enabled')) {
|
||||
if (! config('custom-domains.enabled')) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Custom domains not enabled',
|
||||
], 401);
|
||||
}
|
||||
|
||||
if (config('custom-domains.enabled') && !in_array($request->ip(), config('custom-domains.authorized_ips'))) {
|
||||
if (config('custom-domains.enabled') && ! in_array($request->ip(), config('custom-domains.authorized_ips'))) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Unauthorized IP',
|
||||
@@ -27,7 +27,7 @@ class CaddyRequestMiddleware
|
||||
}
|
||||
|
||||
$secret = $request->route('secret');
|
||||
if (config('custom-domains.caddy_secret') && (!$secret || $secret !== config('custom-domains.caddy_secret'))) {
|
||||
if (config('custom-domains.caddy_secret') && (! $secret || $secret !== config('custom-domains.caddy_secret'))) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Unauthorized',
|
||||
|
||||
@@ -6,24 +6,24 @@ use App\Http\Requests\Workspace\CustomDomainRequest;
|
||||
use App\Models\Forms\Form;
|
||||
use App\Models\Workspace;
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class CustomDomainRestriction
|
||||
{
|
||||
const CUSTOM_DOMAIN_HEADER = "x-custom-domain";
|
||||
public const CUSTOM_DOMAIN_HEADER = 'x-custom-domain';
|
||||
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if (!$request->hasHeader(self::CUSTOM_DOMAIN_HEADER) || !config('custom-domains.enabled')) {
|
||||
if (! $request->hasHeader(self::CUSTOM_DOMAIN_HEADER) || ! config('custom-domains.enabled')) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
$customDomain = $request->header(self::CUSTOM_DOMAIN_HEADER);
|
||||
if (!preg_match(CustomDomainRequest::CUSTOM_DOMAINS_REGEX, $customDomain)) {
|
||||
if (! preg_match(CustomDomainRequest::CUSTOM_DOMAINS_REGEX, $customDomain)) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Invalid domain',
|
||||
@@ -38,7 +38,7 @@ class CustomDomainRestriction
|
||||
}
|
||||
|
||||
// Check if domain is known
|
||||
if (!$workspaces = Workspace::whereJsonContains('custom_domains',$customDomain)->get()) {
|
||||
if (! $workspaces = Workspace::whereJsonContains('custom_domains', $customDomain)->get()) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Unknown domain',
|
||||
|
||||
@@ -11,7 +11,6 @@ class ProForm
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
|
||||
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
@@ -22,6 +21,7 @@ class ProForm
|
||||
$request->merge([
|
||||
'form' => $form,
|
||||
]);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,27 +9,26 @@ use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class ProtectedForm
|
||||
{
|
||||
const PASSWORD_HEADER_NAME = 'form-password';
|
||||
public const PASSWORD_HEADER_NAME = 'form-password';
|
||||
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
|
||||
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if (!$request->route('slug')) {
|
||||
if (! $request->route('slug')) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
$form = Form::where('slug',$request->route('slug'))->firstOrFail();
|
||||
$form = Form::where('slug', $request->route('slug'))->firstOrFail();
|
||||
$request->merge([
|
||||
'form' => $form,
|
||||
]);
|
||||
$userIsFormOwner = Auth::check() && Auth::user()->ownsForm($form);
|
||||
if (!$userIsFormOwner && $this->isProtected($request, $form)) {
|
||||
if (! $userIsFormOwner && $this->isProtected($request, $form)) {
|
||||
return response([
|
||||
'status' => 'Unauthorized',
|
||||
'message' => 'Form is protected.',
|
||||
@@ -41,11 +40,11 @@ class ProtectedForm
|
||||
|
||||
public static function isProtected(Request $request, Form $form)
|
||||
{
|
||||
if (!$form->has_password) {
|
||||
if (! $form->has_password) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !self::hasCorrectPassword($request, $form);
|
||||
return ! self::hasCorrectPassword($request, $form);
|
||||
}
|
||||
|
||||
public static function hasCorrectPassword(Request $request, Form $form)
|
||||
|
||||
@@ -11,16 +11,16 @@ class ResolveFormMiddleware
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
|
||||
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function handle(Request $request, Closure $next, string $routeParamName = "id")
|
||||
{
|
||||
$form = Form::where($routeParamName,$request->route($routeParamName))->firstOrFail();
|
||||
public function handle(Request $request, Closure $next, string $routeParamName = 'id')
|
||||
{
|
||||
$form = Form::where($routeParamName, $request->route($routeParamName))->firstOrFail();
|
||||
$request->merge([
|
||||
'form' => $form,
|
||||
]);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,14 +9,15 @@ use Tymon\JWTAuth\Exceptions\JWTException;
|
||||
class ImpersonationMiddleware
|
||||
{
|
||||
public const ADMIN_LOG_PREFIX = '[admin_action] ';
|
||||
const LOG_ROUTES = [
|
||||
|
||||
public const LOG_ROUTES = [
|
||||
'open.forms.store',
|
||||
'open.forms.update',
|
||||
'open.forms.duplicate',
|
||||
'open.forms.regenerate-link',
|
||||
];
|
||||
|
||||
const ALLOWED_ROUTES = [
|
||||
public const ALLOWED_ROUTES = [
|
||||
'logout',
|
||||
|
||||
// Forms
|
||||
@@ -59,14 +60,13 @@ class ImpersonationMiddleware
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
|
||||
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
try {
|
||||
if (!auth()->check() || !auth()->payload()->get('impersonating')) {
|
||||
if (! auth()->check() || ! auth()->payload()->get('impersonating')) {
|
||||
return $next($request);
|
||||
}
|
||||
} catch (JWTException $e) {
|
||||
@@ -75,22 +75,22 @@ class ImpersonationMiddleware
|
||||
|
||||
// Check that route is allowed
|
||||
$routeName = $request->route()->getName();
|
||||
if (!in_array($routeName, self::ALLOWED_ROUTES)) {
|
||||
if (! in_array($routeName, self::ALLOWED_ROUTES)) {
|
||||
return response([
|
||||
'message' => 'Unauthorized when impersonating',
|
||||
'route' => $routeName,
|
||||
'impersonator' => auth()->payload()->get('impersonator_id'),
|
||||
'impersonated_account' => auth()->id(),
|
||||
'url' => $request->fullUrl(),
|
||||
'payload' => $request->all()
|
||||
'payload' => $request->all(),
|
||||
], 403);
|
||||
} else if (in_array($routeName, self::LOG_ROUTES)) {
|
||||
\Log::warning(self::ADMIN_LOG_PREFIX . 'Impersonator action', [
|
||||
} elseif (in_array($routeName, self::LOG_ROUTES)) {
|
||||
\Log::warning(self::ADMIN_LOG_PREFIX.'Impersonator action', [
|
||||
'route' => $routeName,
|
||||
'url' => $request->fullUrl(),
|
||||
'impersonated_account' => auth()->id(),
|
||||
'impersonator' => auth()->payload()->get('impersonator_id'),
|
||||
'payload' => $request->all()
|
||||
'payload' => $request->all(),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,13 +10,11 @@ class IsAdmin
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if ($request->user() && !$request->user()->admin) {
|
||||
if ($request->user() && ! $request->user()->admin) {
|
||||
// This user is not a paying customer...
|
||||
if ($request->expectsJson()) {
|
||||
return response([
|
||||
@@ -24,6 +22,7 @@ class IsAdmin
|
||||
'type' => 'error',
|
||||
], 403);
|
||||
}
|
||||
|
||||
return redirect('home');
|
||||
}
|
||||
|
||||
|
||||
@@ -10,13 +10,11 @@ class IsModerator
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if ($request->user() && !$request->user()->moderator) {
|
||||
if ($request->user() && ! $request->user()->moderator) {
|
||||
// This user is not a paying customer...
|
||||
if ($request->expectsJson()) {
|
||||
return response([
|
||||
@@ -24,6 +22,7 @@ class IsModerator
|
||||
'type' => 'error',
|
||||
], 403);
|
||||
}
|
||||
|
||||
return redirect('home');
|
||||
}
|
||||
|
||||
|
||||
@@ -10,8 +10,6 @@ class IsNotSubscribed
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
@@ -24,6 +22,7 @@ class IsNotSubscribed
|
||||
'type' => 'error',
|
||||
], 401);
|
||||
}
|
||||
|
||||
return redirect('billing');
|
||||
}
|
||||
|
||||
|
||||
@@ -10,13 +10,11 @@ class IsSubscribed
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if ($request->user() && !$request->user()->subscribed()) {
|
||||
if ($request->user() && ! $request->user()->subscribed()) {
|
||||
// This user is not a paying customer...
|
||||
if ($request->expectsJson()) {
|
||||
return response([
|
||||
@@ -24,6 +22,7 @@ class IsSubscribed
|
||||
'type' => 'error',
|
||||
], 401);
|
||||
}
|
||||
|
||||
return redirect('billing');
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,6 @@ class RedirectIfAuthenticated
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param string|null ...$guards
|
||||
* @return mixed
|
||||
*/
|
||||
|
||||
@@ -10,7 +10,6 @@ class SetLocale
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
@@ -23,7 +22,7 @@ class SetLocale
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return string|null
|
||||
*/
|
||||
protected function parseLocale($request)
|
||||
|
||||
@@ -18,10 +18,11 @@ class TrimStrings extends Middleware
|
||||
|
||||
/**
|
||||
* The route name where this shouldn't be applied
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $exceptUrls = [
|
||||
'/\/api\/forms\/(.*)\/answer/'
|
||||
'/\/api\/forms\/(.*)\/answer/',
|
||||
];
|
||||
|
||||
public function handle($request, \Closure $next)
|
||||
|
||||
@@ -14,6 +14,6 @@ class VerifyCsrfToken extends Middleware
|
||||
protected $except = [
|
||||
'stripe/webhook',
|
||||
'vapor/signed-storage-url',
|
||||
'upload-file'
|
||||
'upload-file',
|
||||
];
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ class AiGenerateFormRequest extends FormRequest
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'form_prompt' => 'required|string|max:1000'
|
||||
'form_prompt' => 'required|string|max:1000',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,22 +3,22 @@
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Forms\Form;
|
||||
|
||||
use App\Rules\StorageFile;
|
||||
use App\Service\Forms\FormLogicPropertyResolver;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Rules\ValidHCaptcha;
|
||||
use App\Rules\ValidPhoneInputRule;
|
||||
use App\Rules\ValidUrl;
|
||||
use App\Service\Forms\FormLogicPropertyResolver;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class AnswerFormRequest extends FormRequest
|
||||
{
|
||||
public Form $form;
|
||||
|
||||
protected array $requestRules = [];
|
||||
|
||||
protected int $maxFileSize;
|
||||
|
||||
public function __construct(Request $request)
|
||||
@@ -34,7 +34,7 @@ class AnswerFormRequest extends FormRequest
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return !$this->form->is_closed && !$this->form->max_number_of_submissions_reached && $this->form->visibility === 'public';
|
||||
return ! $this->form->is_closed && ! $this->form->max_number_of_submissions_reached && $this->form->visibility === 'public';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,23 +56,24 @@ class AnswerFormRequest extends FormRequest
|
||||
$selectionFields = collect($this->form->properties)->filter(function ($pro) {
|
||||
return in_array($pro['type'], ['select', 'multi_select']);
|
||||
});
|
||||
foreach ($selectionFields as $field){
|
||||
if(isset($data[$field['id']]) && is_array($data[$field['id']])){
|
||||
foreach ($selectionFields as $field) {
|
||||
if (isset($data[$field['id']]) && is_array($data[$field['id']])) {
|
||||
$data[$field['id']] = array_map(function ($val) use ($field) {
|
||||
$tmpop = collect($field[$field['type']]['options'])->first(function ($op) use ($val) {
|
||||
return ($op['id'] ?? $op['value'] === $val);
|
||||
return $op['id'] ?? $op['value'] === $val;
|
||||
});
|
||||
return isset($tmpop['name']) ? $tmpop['name'] : "";
|
||||
|
||||
return isset($tmpop['name']) ? $tmpop['name'] : '';
|
||||
}, $data[$field['id']]);
|
||||
}
|
||||
};
|
||||
}
|
||||
if (FormLogicPropertyResolver::isRequired($property, $data)) {
|
||||
$rules[] = 'required';
|
||||
|
||||
if ($property['type'] == 'checkbox') {
|
||||
// Required for checkboxes means true
|
||||
$rules[] = 'accepted';
|
||||
} else if ($property['type'] == 'number' && isset($property['is_rating']) && $property['is_rating']) {
|
||||
} elseif ($property['type'] == 'number' && isset($property['is_rating']) && $property['is_rating']) {
|
||||
// For star rating, needs a minimum of 1 star
|
||||
$rules[] = 'min:1';
|
||||
}
|
||||
@@ -107,6 +108,7 @@ class AnswerFormRequest extends FormRequest
|
||||
|
||||
/**
|
||||
* Renames validated fields (because field names are ids)
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function attributes()
|
||||
@@ -115,6 +117,7 @@ class AnswerFormRequest extends FormRequest
|
||||
foreach ($this->form->properties as $property) {
|
||||
$fields[$property['id']] = $property['name'];
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
@@ -127,21 +130,21 @@ class AnswerFormRequest extends FormRequest
|
||||
{
|
||||
$messages = [];
|
||||
foreach ($this->form->properties as $property) {
|
||||
if($property['type'] == 'date' && isset($property['date_range']) && $property['date_range']){
|
||||
$messages[$property['id'].'.0.required_with'] = "From date is required";
|
||||
$messages[$property['id'].'.1.required_with'] = "To date is required";
|
||||
$messages[$property['id'].'.0.before_or_equal'] = "From date must be before or equal To date";
|
||||
if ($property['type'] == 'date' && isset($property['date_range']) && $property['date_range']) {
|
||||
$messages[$property['id'].'.0.required_with'] = 'From date is required';
|
||||
$messages[$property['id'].'.1.required_with'] = 'To date is required';
|
||||
$messages[$property['id'].'.0.before_or_equal'] = 'From date must be before or equal To date';
|
||||
}
|
||||
if ($property['type'] == 'number' && isset($property['is_rating']) && $property['is_rating']) {
|
||||
$messages[$property['id'] . '.min'] = "A rating must be selected";
|
||||
$messages[$property['id'].'.min'] = 'A rating must be selected';
|
||||
}
|
||||
}
|
||||
|
||||
return $messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return validation rules for a given form property
|
||||
* @param $property
|
||||
*/
|
||||
private function getPropertyRules($property): array
|
||||
{
|
||||
@@ -153,27 +156,32 @@ class AnswerFormRequest extends FormRequest
|
||||
if ($property['is_rating'] ?? false) {
|
||||
return ['numeric'];
|
||||
}
|
||||
|
||||
return ['numeric'];
|
||||
case 'select':
|
||||
case 'multi_select':
|
||||
if (($property['allow_creation'] ?? false)) {
|
||||
return ['string'];
|
||||
}
|
||||
|
||||
return [Rule::in($this->getSelectPropertyOptions($property))];
|
||||
case 'checkbox':
|
||||
return ['boolean'];
|
||||
case 'url':
|
||||
if (isset($property['file_upload']) && $property['file_upload']) {
|
||||
$this->requestRules[$property['id'].'.*'] = [new StorageFile($this->maxFileSize, [], $this->form)];
|
||||
|
||||
return ['array'];
|
||||
}
|
||||
return [new ValidUrl];
|
||||
|
||||
return [new ValidUrl()];
|
||||
case 'files':
|
||||
$allowedFileTypes = [];
|
||||
if(!empty($property['allowed_file_types'])){
|
||||
$allowedFileTypes = explode(",", $property['allowed_file_types']);
|
||||
if (! empty($property['allowed_file_types'])) {
|
||||
$allowedFileTypes = explode(',', $property['allowed_file_types']);
|
||||
}
|
||||
$this->requestRules[$property['id'].'.*'] = [new StorageFile($this->maxFileSize, $allowedFileTypes, $this->form)];
|
||||
|
||||
return ['array'];
|
||||
case 'email':
|
||||
return ['email:filter'];
|
||||
@@ -182,14 +190,17 @@ class AnswerFormRequest extends FormRequest
|
||||
$this->requestRules[$property['id'].'.*'] = $this->getRulesForDate($property);
|
||||
$this->requestRules[$property['id'].'.0'] = ['required_with:'.$property['id'].'.1', 'before_or_equal:'.$property['id'].'.1'];
|
||||
$this->requestRules[$property['id'].'.1'] = ['required_with:'.$property['id'].'.0'];
|
||||
|
||||
return ['array', 'min:2'];
|
||||
}
|
||||
|
||||
return $this->getRulesForDate($property);
|
||||
case 'phone_number':
|
||||
if (isset($property['use_simple_text_input']) && $property['use_simple_text_input']) {
|
||||
return ['string'];
|
||||
}
|
||||
return ['string', 'min:6', new ValidPhoneInputRule];
|
||||
|
||||
return ['string', 'min:6', new ValidPhoneInputRule()];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
@@ -199,18 +210,20 @@ class AnswerFormRequest extends FormRequest
|
||||
{
|
||||
if (isset($property['disable_past_dates']) && $property['disable_past_dates']) {
|
||||
return ['date', 'after_or_equal:today'];
|
||||
}else if (isset($property['disable_future_dates']) && $property['disable_future_dates']) {
|
||||
} elseif (isset($property['disable_future_dates']) && $property['disable_future_dates']) {
|
||||
return ['date', 'before_or_equal:today'];
|
||||
}
|
||||
|
||||
return ['date'];
|
||||
}
|
||||
|
||||
private function getSelectPropertyOptions($property): array
|
||||
{
|
||||
$type = $property['type'];
|
||||
if (!isset($property[$type])) {
|
||||
if (! isset($property[$type])) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return array_column($property[$type]['options'], 'name');
|
||||
}
|
||||
|
||||
@@ -223,25 +236,26 @@ class AnswerFormRequest extends FormRequest
|
||||
$receivedValue = $receivedData[$property['id']] ?? null;
|
||||
|
||||
// Escape all '\' in select options
|
||||
if(in_array($property['type'], ['select', 'multi_select']) && !is_null($receivedValue)){
|
||||
if (in_array($property['type'], ['select', 'multi_select']) && ! is_null($receivedValue)) {
|
||||
if (is_array($receivedValue)) {
|
||||
$mergeData[$property['id']] = collect($receivedValue)->map(function ($value) {
|
||||
$value = Str::of($value);
|
||||
|
||||
return $value->replace(
|
||||
["\e", "\f", "\n", "\r", "\t", "\v", "\\"],
|
||||
["\\e", "\\f", "\\n", "\\r", "\\t", "\\v", "\\\\"]
|
||||
["\e", "\f", "\n", "\r", "\t", "\v", '\\'],
|
||||
['\\e', '\\f', '\\n', '\\r', '\\t', '\\v', '\\\\']
|
||||
)->toString();
|
||||
})->toArray();
|
||||
} else {
|
||||
$receivedValue = Str::of($receivedValue);
|
||||
$mergeData[$property['id']] = $receivedValue->replace(
|
||||
["\e", "\f", "\n", "\r", "\t", "\v", "\\"],
|
||||
["\\e", "\\f", "\\n", "\\r", "\\t", "\\v", "\\\\"]
|
||||
["\e", "\f", "\n", "\r", "\t", "\v", '\\'],
|
||||
['\\e', '\\f', '\\n', '\\r', '\\t', '\\v', '\\\\']
|
||||
)->toString();
|
||||
}
|
||||
}
|
||||
|
||||
if($property['type'] === 'phone_number' && (!isset($property['use_simple_text_input']) || !$property['use_simple_text_input']) && $receivedValue && in_array($receivedValue, $countryCodeMapper)){
|
||||
if ($property['type'] === 'phone_number' && (! isset($property['use_simple_text_input']) || ! $property['use_simple_text_input']) && $receivedValue && in_array($receivedValue, $countryCodeMapper)) {
|
||||
$mergeData[$property['id']] = null;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -17,12 +17,14 @@ class StoreFormZapierWebhookRequest extends FormRequest
|
||||
{
|
||||
return [
|
||||
'form_slug' => 'required|exists:forms,slug',
|
||||
'hook_url' => 'required|string|url'
|
||||
'hook_url' => 'required|string|url',
|
||||
];
|
||||
}
|
||||
|
||||
public function instanciateHook() {
|
||||
public function instanciateHook()
|
||||
{
|
||||
$form = Form::whereSlug($this->form_slug)->firstOrFail();
|
||||
|
||||
return new FormZapierWebhook([
|
||||
'form_id' => $form->id,
|
||||
'hook_url' => $this->hook_url,
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Forms\Form;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class StoreFormRequest extends UserFormRequest
|
||||
{
|
||||
/**
|
||||
|
||||
@@ -7,7 +7,7 @@ use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class FormTemplateRequest extends FormRequest
|
||||
{
|
||||
const IGNORED_KEYS = [
|
||||
public const IGNORED_KEYS = [
|
||||
'id',
|
||||
'creator',
|
||||
'cleanings',
|
||||
@@ -49,9 +49,10 @@ class FormTemplateRequest extends FormRequest
|
||||
public function rules()
|
||||
{
|
||||
$slugRule = '';
|
||||
if($this->id){
|
||||
if ($this->id) {
|
||||
$slugRule = ','.$this->id;
|
||||
}
|
||||
|
||||
return [
|
||||
'form' => 'required|array',
|
||||
'publicly_listed' => 'boolean',
|
||||
@@ -88,7 +89,7 @@ class FormTemplateRequest extends FormRequest
|
||||
'types' => $this->types ?? [],
|
||||
'industries' => $this->industries ?? [],
|
||||
'related_templates' => $this->related_templates ?? [],
|
||||
'questions' => $this->questions ?? []
|
||||
'questions' => $this->questions ?? [],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,5 +4,4 @@ namespace App\Http\Requests;
|
||||
|
||||
class UpdateFormRequest extends UserFormRequest
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class UploadAssetRequest extends FormRequest
|
||||
{
|
||||
const FORM_ASSET_MAX_SIZE = 5000000;
|
||||
public const FORM_ASSET_MAX_SIZE = 5000000;
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
@@ -22,7 +22,7 @@ class UploadAssetRequest extends FormRequest
|
||||
'jpg',
|
||||
'bmp',
|
||||
'gif',
|
||||
'svg'
|
||||
'svg',
|
||||
];
|
||||
if ($this->offsetExists('type') && $this->get('type') === 'files') {
|
||||
$fileTypes = [];
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
|
||||
use App\Http\Requests\Workspace\CustomDomainRequest;
|
||||
use App\Models\Forms\Form;
|
||||
use App\Rules\FormPropertyLogicRule;
|
||||
use App\Rules\OneEmailPerLine;
|
||||
use Illuminate\Validation\Rule;
|
||||
use App\Rules\FormPropertyLogicRule;
|
||||
|
||||
/**
|
||||
* Abstract class to validate create/update forms
|
||||
*
|
||||
* Class UserFormRequest
|
||||
* @package App\Http\Requests
|
||||
*/
|
||||
abstract class UserFormRequest extends \Illuminate\Foundation\Http\FormRequest
|
||||
{
|
||||
@@ -30,11 +27,11 @@ abstract class UserFormRequest extends \Illuminate\Foundation\Http\FormRequest
|
||||
'title' => 'required|string|max:60',
|
||||
'description' => 'nullable|string|max:2000',
|
||||
'tags' => 'nullable|array',
|
||||
'visibility' => ['required',Rule::in(Form::VISIBILITY)],
|
||||
'visibility' => ['required', Rule::in(Form::VISIBILITY)],
|
||||
|
||||
// Notifications
|
||||
'notifies' => 'boolean',
|
||||
'notification_emails' => ['required_if:notifies,1', new OneEmailPerLine ],
|
||||
'notification_emails' => ['required_if:notifies,1', new OneEmailPerLine()],
|
||||
'send_submission_confirmation' => 'boolean',
|
||||
'notification_sender' => 'string|max:64',
|
||||
'notification_subject' => 'string|max:200',
|
||||
@@ -47,11 +44,11 @@ abstract class UserFormRequest extends \Illuminate\Foundation\Http\FormRequest
|
||||
'notification_settings' => 'nullable',
|
||||
|
||||
// Customization
|
||||
'theme' => ['required',Rule::in(Form::THEMES)],
|
||||
'width' => ['required',Rule::in(Form::WIDTHS)],
|
||||
'theme' => ['required', Rule::in(Form::THEMES)],
|
||||
'width' => ['required', Rule::in(Form::WIDTHS)],
|
||||
'cover_picture' => 'url|nullable',
|
||||
'logo_picture' => 'url|nullable',
|
||||
'dark_mode' => ['required',Rule::in(Form::DARK_MODE_VALUES)],
|
||||
'dark_mode' => ['required', Rule::in(Form::DARK_MODE_VALUES)],
|
||||
'color' => 'required|string',
|
||||
'hide_title' => 'required|boolean',
|
||||
'uppercase_labels' => 'required|boolean',
|
||||
@@ -75,7 +72,7 @@ abstract class UserFormRequest extends \Illuminate\Foundation\Http\FormRequest
|
||||
'editable_submissions' => 'boolean|nullable',
|
||||
'editable_submissions_button_text' => 'string|min:1|max:50',
|
||||
'confetti_on_submission' => 'boolean',
|
||||
'auto_save'=> 'boolean',
|
||||
'auto_save' => 'boolean',
|
||||
|
||||
// Properties
|
||||
'properties' => 'required|array',
|
||||
@@ -90,7 +87,7 @@ abstract class UserFormRequest extends \Illuminate\Foundation\Http\FormRequest
|
||||
'properties.*.required' => 'boolean|nullable',
|
||||
'properties.*.multiple' => 'boolean|nullable',
|
||||
'properties.*.timezone' => 'sometimes|nullable',
|
||||
'properties.*.width' => ['sometimes', Rule::in(['full','1/2','1/3','2/3','1/3','3/4','1/4'])],
|
||||
'properties.*.width' => ['sometimes', Rule::in(['full', '1/2', '1/3', '2/3', '1/3', '3/4', '1/4'])],
|
||||
'properties.*.align' => ['sometimes', Rule::in(['left', 'center', 'right', 'justify'])],
|
||||
'properties.*.allowed_file_types' => 'sometimes|nullable',
|
||||
'properties.*.use_toggle_switch' => 'boolean|nullable',
|
||||
@@ -127,7 +124,7 @@ abstract class UserFormRequest extends \Illuminate\Foundation\Http\FormRequest
|
||||
|
||||
// Custom SEO
|
||||
'seo_meta' => 'nullable|array',
|
||||
'custom_domain' => 'sometimes|nullable|regex:'. CustomDomainRequest::CUSTOM_DOMAINS_REGEX,
|
||||
'custom_domain' => 'sometimes|nullable|regex:'.CustomDomainRequest::CUSTOM_DOMAINS_REGEX,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -8,10 +8,12 @@ use Illuminate\Http\Request;
|
||||
|
||||
class CustomDomainRequest extends FormRequest
|
||||
{
|
||||
const CUSTOM_DOMAINS_REGEX = '/^[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,20}$/';
|
||||
public const CUSTOM_DOMAINS_REGEX = '/^[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,20}$/';
|
||||
|
||||
public Workspace $workspace;
|
||||
|
||||
public array $customDomains = [];
|
||||
|
||||
public function __construct(Request $request, Workspace $workspace)
|
||||
{
|
||||
$this->workspace = Workspace::findOrFail($request->workspaceId);
|
||||
@@ -28,13 +30,13 @@ class CustomDomainRequest extends FormRequest
|
||||
'custom_domains' => [
|
||||
'present',
|
||||
'array',
|
||||
function($attribute, $value, $fail) {
|
||||
function ($attribute, $value, $fail) {
|
||||
$errors = [];
|
||||
$domains = collect($value)->filter(function ($domain) {
|
||||
return !empty( trim($domain) );
|
||||
})->each(function($domain) use (&$errors) {
|
||||
if (!preg_match(self::CUSTOM_DOMAINS_REGEX, $domain)) {
|
||||
$errors[] = 'Invalid domain: ' . $domain;
|
||||
return ! empty(trim($domain));
|
||||
})->each(function ($domain) use (&$errors) {
|
||||
if (! preg_match(self::CUSTOM_DOMAINS_REGEX, $domain)) {
|
||||
$errors[] = 'Invalid domain: '.$domain;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -44,16 +46,17 @@ class CustomDomainRequest extends FormRequest
|
||||
|
||||
$limit = $this->workspace->custom_domain_count_limit;
|
||||
if ($limit && $domains->count() > $limit) {
|
||||
$fail('You can only add ' . $limit . ' domain(s).');
|
||||
$fail('You can only add '.$limit.' domain(s).');
|
||||
}
|
||||
|
||||
$this->customDomains = $domains->toArray();
|
||||
}
|
||||
]
|
||||
},
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
protected function passedValidation(){
|
||||
protected function passedValidation()
|
||||
{
|
||||
$this->replace(['custom_domains' => $this->customDomains]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,8 @@
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use App\Http\Middleware\Form\ProtectedForm;
|
||||
use App\Http\Resources\UserResource;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class FormResource extends JsonResource
|
||||
{
|
||||
@@ -20,7 +18,7 @@ class FormResource extends JsonResource
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
if(!$this->userIsFormOwner() && ProtectedForm::isProtected($request, $this->resource)){
|
||||
if (! $this->userIsFormOwner() && ProtectedForm::isProtected($request, $this->resource)) {
|
||||
return $this->getProtectedForm();
|
||||
}
|
||||
|
||||
@@ -69,6 +67,7 @@ class FormResource extends JsonResource
|
||||
public function setCleanings(array $cleanings)
|
||||
{
|
||||
$this->cleanings = $cleanings;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -96,15 +95,18 @@ class FormResource extends JsonResource
|
||||
];
|
||||
}
|
||||
|
||||
private function getWorkspace() {
|
||||
private function getWorkspace()
|
||||
{
|
||||
return $this->extra?->loadedWorkspace ?? $this->workspace;
|
||||
}
|
||||
|
||||
private function workspaceIsPro() {
|
||||
private function workspaceIsPro()
|
||||
{
|
||||
return $this->extra?->workspaceIsPro ?? $this->getWorkspace()->is_pro ?? $this->is_pro;
|
||||
}
|
||||
|
||||
private function userIsFormOwner() {
|
||||
private function userIsFormOwner()
|
||||
{
|
||||
return $this->extra?->userIsOwner ??
|
||||
(
|
||||
Auth::check() && Auth::user()->ownsForm($this->resource)
|
||||
|
||||
@@ -6,7 +6,6 @@ use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class FormSubmissionResource extends JsonResource
|
||||
{
|
||||
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
@@ -28,13 +27,14 @@ class FormSubmissionResource extends JsonResource
|
||||
private function addExtraData()
|
||||
{
|
||||
$this->data = array_merge($this->data, [
|
||||
"created_at" => $this->created_at->toDateTimeString(),
|
||||
'id' => $this->id
|
||||
'created_at' => $this->created_at->toDateTimeString(),
|
||||
'id' => $this->id,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Link to the file (generating signed s3 URL)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function generateFileLinks()
|
||||
@@ -45,7 +45,7 @@ class FormSubmissionResource extends JsonResource
|
||||
return in_array($field['type'], ['files', 'signature']);
|
||||
});
|
||||
foreach ($fileFields as $field) {
|
||||
if (isset($data[$field['id']]) && !empty($data[$field['id']])) {
|
||||
if (isset($data[$field['id']]) && ! empty($data[$field['id']])) {
|
||||
$data[$field['id']] = collect($data[$field['id']])->filter(function ($file) {
|
||||
return $file !== null && $file;
|
||||
})->map(function ($file) {
|
||||
|
||||
@@ -15,7 +15,7 @@ class FormTemplateResource extends JsonResource
|
||||
public function toArray($request)
|
||||
{
|
||||
return array_merge(parent::toArray($request), [
|
||||
'is_new' => $this->created_at->isAfter(now()->subDays(7))
|
||||
'is_new' => $this->created_at->isAfter(now()->subDays(7)),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ class UserResource extends JsonResource
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
||||
*/
|
||||
public function toArray($request)
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class WorkspaceResource extends JsonResource
|
||||
{
|
||||
@@ -12,7 +11,7 @@ class WorkspaceResource extends JsonResource
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request)
|
||||
|
||||
Reference in New Issue
Block a user