Migrate front-end to Nuxt app (#284)
* wip * Managed to load a page * Stuck at changing routes * Fixed the router, and editable div * WIP * Fix app loader * WIP * Fix check-auth middleware * Started to refactor input components * WIP * Added select input, v-click-outside for vselect * update vselect & phone input * Fixed the mixin * input component updates * Fix signature input import * input component updates in vue3 * image input in vue3 * small fixes * fix useFormInput watcher * scale input in vue3 * Vue3: migrating from vuex to Pinia (#249) * Vue3: migrating from vuex to Pinia * toggle input fixes * update configureCompat --------- Co-authored-by: Forms Dev <chirag+new@notionforms.io> * support vue3 query builder * Refactor inpus * fix: Vue3 Query Builder - Logic Editor (#251) * support vue3 query builder * upgrade * remove local from middleware * Submission table pagination & migrate chart to vue3 (#254) * Submission table Pagination in background * migrate chart to vue3 * Form submissions pagination * Form submissions * Fix form starts * Fix openSelect key issue --------- Co-authored-by: Forms Dev <chirag+new@notionforms.io> Co-authored-by: Julien Nahum <julien@nahum.net> * Vue 3 better animation (#257) * vue-3-better-animation * Working on migration to vueuse/motion * Form sidebar animations * Clean code * Added animations for modal * Finished implementing better animations --------- Co-authored-by: Forms Dev <chirag+new@notionforms.io> * Work in progress * Migrating amplitude and crisp plugin/composable * Started to refactor pages * WIP * vue3-scroll-shadow-fixes (#260) * WIP * WIP * WIP * Figured out auth & middlewares * WI * Refactoring stores and templates pages to comp. api * Finishing the templates pages * fix collapsible * Finish reworking most templates pages * Reworked workspaces store * Working on home page and modal * Fix dropdown * Fix modal * Fixed form creation * Fixed most of the form/show pages * Updated cors dependency * fix custom domain warning * NuxtLink migration (#262) Co-authored-by: Forms Dev <chirag+new@notionforms.io> * Tiny fixes + start pre-rendering * migrate-to-nuxt-useappconfig (#263) * migrate-to-nuxt-useappconfig * defineAppConfig --------- Co-authored-by: Forms Dev <chirag+new@notionforms.io> * Working on form/show and editor * Globally import form inputs to fix resolve * Remove vform - working on form public page * Remove initform mixin * Work in progress for form create guess user * Nuxt Migration notifications (#265) * Nuxt Migration notifications * @input to @update:model-value * change field type fixes * @update:model-value * Enable form-block-logic-editor * vue-confetti migration * PR request changes * useAlert in setup * Migrate to nuxt settings page AND remove axios (#266) * Settings pages migration * remove axios and use opnFetch * Make created form reactive (#267) * Remove verify pages and axios lib --------- Co-authored-by: Julien Nahum <julien@nahum.net> * Fix alert styling + bug fixes and cleaning * Refactor notifications + add shadow * Fix vselect issue * Working on page pre-rendering * Created NotionPages store * Added sitemap on nuxt side * Sitemap done, working on aws amplify * Adding missing module * Remove axios and commit backend changes to sitemap * Fix notifications * fix guestpage editor (#269) Co-authored-by: Julien Nahum <julien@nahum.net> * Remove appconfig in favor of runtimeconfig * Fixed amplitude bugs, and added staging environment * Added amplify file * Change basdirectory amplify * Fix loading bar position * Fix custom redirect (#273) * Dirty form handling - nuxt migration (#272) * SEO meta nuxt migration (#274) * SEO meta nuxt migration * Polish seo metas, add defaults for OG and twitter --------- Co-authored-by: Julien Nahum <julien@nahum.net> * migrate to nuxt useClipboard (#268) * Set middleware on pages (#278) * Se middleware on pages * Se middleware on account page * add robots.txt (#276) * 404 page migration (#277) * Templates pages migration (#275) * NuxtImg Migration (#279) Co-authored-by: Julien Nahum <julien@nahum.net> * Update package json * Fix build script * Add loglevel param * Disable page pre-rendering * Attempt to allow svgs * Fix SVGs with NuxtImage * Add .env file at AWS build time * tRGIGGER deploy * Fix issue * ANother attrempt * Fix typo * Fix env? * Attempt to simplify build * Enable swr caching instead of prerenderign * Better image compression * Last attempt at nuxt images efficiency * Improve image optimization again * Remove NuxtImg for non asset files * Restore templates pages cache * Remove useless images + fix templates show page * image optimization caching + fix hydratation issue form template page * URL generation (front&back) + fixed authJWT for SSR * Fix composable issue * Fix form share page * Embeddable form as a nuxt middleware * Fix URL for embeddable middleware * Debugging embeddable on amplify * Add custom domain support * No follow for non-production env * Fix sentry nuxt and custom domain redirect * remove api prefix from routes (#280) * remove api prefix from routes * PR changes --------- Co-authored-by: Julien Nahum <julien@nahum.net> * nuxt migration -file upload - WIP (#271) Co-authored-by: Julien Nahum <julien@nahum.net> * Fix local file upload * Fix file submissions preview * API redirect to back-end from nuxt * API redirect to back-end from nuxt * Remove old JS app, update deploy script * Fix tests, added gh action nuxt step * Updated package-lock.json * Setup node in GH Nuxt action * Setup client directory for GH workflow --------- Co-authored-by: Forms Dev <chirag+new@notionforms.io> Co-authored-by: Chirag Chhatrala <60499540+chiragchhatrala@users.noreply.github.com> Co-authored-by: Rishi Raj Jain <rishi18304@iiitd.ac.in> Co-authored-by: formsdev <136701234+formsdev@users.noreply.github.com>
This commit is contained in:
@@ -28,10 +28,10 @@ class AppSumoAuthController extends Controller
|
||||
|
||||
// otherwise start login flow by passing the encrypted license key id
|
||||
if (is_null($license->user_id)) {
|
||||
return redirect(url('/register?appsumo_license='.encrypt($license->id)));
|
||||
return redirect(front_url('/register?appsumo_license='.encrypt($license->id)));
|
||||
}
|
||||
|
||||
return redirect(url('/register?appsumo_error=1'));
|
||||
return redirect(front_url('/register?appsumo_error=1'));
|
||||
}
|
||||
|
||||
private function retrieveAccessToken(string $requestCode): string
|
||||
@@ -82,11 +82,11 @@ class AppSumoAuthController extends Controller
|
||||
if (is_null($license->user_id)) {
|
||||
$license->user_id = Auth::id();
|
||||
$license->save();
|
||||
return redirect(url('/home?appsumo_connect=1'));
|
||||
return redirect(front_url('/home?appsumo_connect=1'));
|
||||
}
|
||||
|
||||
// Licensed already attached
|
||||
return redirect(url('/home?appsumo_error=1'));
|
||||
return redirect(front_url('/home?appsumo_error=1'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,6 +17,7 @@ class FileUploadController extends Controller
|
||||
*/
|
||||
public function upload(Request $request)
|
||||
{
|
||||
$request->validate(['file' => 'required|file']);
|
||||
$uuid = (string) Str::uuid();
|
||||
$path = $request->file('file')->storeAs(PublicFormController::TMP_FILE_UPLOAD_PATH, $uuid);
|
||||
|
||||
|
||||
@@ -15,7 +15,8 @@ class FormSubmissionController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth');
|
||||
$this->middleware('auth', ['except' => ['submissionFile']]);
|
||||
$this->middleware('signed', ['only' => ['submissionFile']]);
|
||||
}
|
||||
|
||||
public function submissions(string $id)
|
||||
@@ -51,9 +52,6 @@ class FormSubmissionController extends Controller
|
||||
|
||||
public function submissionFile($id, $fileName)
|
||||
{
|
||||
$form = Form::findOrFail((int) $id);
|
||||
$this->authorize('view', $form);
|
||||
|
||||
$fileName = Str::of(PublicFormController::FILE_UPLOAD_PATH)->replace('?', $id).'/'
|
||||
.urldecode($fileName);
|
||||
|
||||
@@ -63,8 +61,12 @@ class FormSubmissionController extends Controller
|
||||
], 404);
|
||||
}
|
||||
|
||||
if (config('filesystems.default') !== 's3') {
|
||||
return response()->file(Storage::path($fileName));
|
||||
}
|
||||
|
||||
return redirect(
|
||||
Storage::temporaryUrl($fileName, now()->addMinute())
|
||||
Storage::temporaryUrl($fileName, now()->addMinute())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,62 +9,24 @@ use App\Models\Template;
|
||||
|
||||
class SitemapController extends Controller
|
||||
{
|
||||
/**
|
||||
* Contains route name and the associated priority
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $urls = [
|
||||
['/', 1],
|
||||
['/pricing', 0.9],
|
||||
['/privacy-policy', 0.5],
|
||||
['/terms-conditions', 0.5],
|
||||
['/login', 0.4],
|
||||
['/register', 0.4],
|
||||
['/password/reset', 0.3],
|
||||
['/form-templates', 0.9],
|
||||
];
|
||||
|
||||
public function getSitemap(Request $request)
|
||||
public function index(Request $request)
|
||||
{
|
||||
$sitemap = Sitemap::create();
|
||||
foreach ($this->urls as $url) {
|
||||
$sitemap->add($this->createUrl($url[0], $url[1]));
|
||||
}
|
||||
$this->addTemplatesUrls($sitemap);
|
||||
$this->addTemplatesTypesUrls($sitemap);
|
||||
$this->addTemplatesIndustriesUrls($sitemap);
|
||||
|
||||
return $sitemap->toResponse($request);
|
||||
return [
|
||||
...$this->getTemplatesUrls()
|
||||
];
|
||||
}
|
||||
|
||||
private function createUrl($url, $priority, $frequency = 'daily')
|
||||
private function getTemplatesUrls()
|
||||
{
|
||||
return Url::create($url)->setPriority($priority)->setChangeFrequency($frequency);
|
||||
}
|
||||
|
||||
private function addTemplatesUrls(Sitemap $sitemap)
|
||||
{
|
||||
Template::where('publicly_listed', true)->chunk(100, function ($templates) use ($sitemap) {
|
||||
$urls = [];
|
||||
Template::where('publicly_listed', true)->chunk(100, function ($templates) use (&$urls) {
|
||||
foreach ($templates as $template) {
|
||||
$sitemap->add($this->createUrl('/form-templates/' . $template->slug, 0.8));
|
||||
$urls[] = [
|
||||
'loc' => '/templates/' . $template->slug
|
||||
];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private function addTemplatesTypesUrls(Sitemap $sitemap)
|
||||
{
|
||||
$types = json_decode(file_get_contents(resource_path('data/forms/templates/types.json')), true);
|
||||
foreach ($types as $type) {
|
||||
$sitemap->add($this->createUrl('/form-templates/types/' . $type['slug'], 0.7));
|
||||
}
|
||||
}
|
||||
|
||||
private function addTemplatesIndustriesUrls(Sitemap $sitemap)
|
||||
{
|
||||
$industries = json_decode(file_get_contents(resource_path('data/forms/templates/industries.json')), true);
|
||||
foreach ($industries as $industry) {
|
||||
$sitemap->add($this->createUrl('/form-templates/industries/' . $industry['slug'], 0.7));
|
||||
}
|
||||
return $urls;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Service\SeoMetaResolver;
|
||||
use Illuminate\Http\Request;
|
||||
class SpaController extends Controller
|
||||
{
|
||||
/**
|
||||
* Get the SPA view.
|
||||
*/
|
||||
public function __invoke(Request $request)
|
||||
{
|
||||
return view('spa',[
|
||||
'meta' => (new SeoMetaResolver($request))->getMetas(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -45,8 +45,8 @@ class SubscriptionController extends Controller
|
||||
$checkout = $checkoutBuilder
|
||||
->collectTaxIds()
|
||||
->checkout([
|
||||
'success_url' => url('/subscriptions/success'),
|
||||
'cancel_url' => url('/subscriptions/error'),
|
||||
'success_url' => front_url('/subscriptions/success'),
|
||||
'cancel_url' => front_url('/subscriptions/error'),
|
||||
'billing_address_collection' => 'required',
|
||||
'customer_update' => [
|
||||
'address' => 'auto',
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace App\Http;
|
||||
|
||||
use App\Http\Middleware\AuthenticateJWT;
|
||||
use App\Http\Middleware\CustomDomainRestriction;
|
||||
use App\Http\Middleware\EmbeddableForms;
|
||||
use App\Http\Middleware\IsAdmin;
|
||||
use App\Http\Middleware\IsNotSubscribed;
|
||||
use App\Http\Middleware\IsSubscribed;
|
||||
@@ -20,9 +19,9 @@ class Kernel extends HttpKernel
|
||||
* @var array
|
||||
*/
|
||||
protected $middleware = [
|
||||
// \App\Http\Middleware\TrustHosts::class,
|
||||
// \App\Http\Middleware\TrustHosts::class,
|
||||
\App\Http\Middleware\TrustProxies::class,
|
||||
\Fruitcake\Cors\HandleCors::class,
|
||||
\Illuminate\Http\Middleware\HandleCors::class,
|
||||
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
|
||||
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
||||
\App\Http\Middleware\TrimStrings::class,
|
||||
@@ -46,16 +45,14 @@ class Kernel extends HttpKernel
|
||||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||
\App\Http\Middleware\VerifyCsrfToken::class,
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
EmbeddableForms::class
|
||||
],
|
||||
|
||||
'spa' => [
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
EmbeddableForms::class
|
||||
],
|
||||
|
||||
'api' => [
|
||||
'throttle:60,1',
|
||||
'throttle:100,1',
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
\App\Http\Middleware\EncryptCookies::class,
|
||||
\Illuminate\Session\Middleware\StartSession::class,
|
||||
|
||||
@@ -15,7 +15,7 @@ class Authenticate extends Middleware
|
||||
protected function redirectTo($request)
|
||||
{
|
||||
if (! $request->expectsJson()) {
|
||||
return redirect('/login');
|
||||
return redirect(front_url('login'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ use Tymon\JWTAuth\Exceptions\JWTException;
|
||||
|
||||
class AuthenticateJWT
|
||||
{
|
||||
const API_SERVER_SECRET_HEADER_NAME = 'x-api-secret';
|
||||
|
||||
/**
|
||||
* Verifies the JWT token and validates the IP and User Agent
|
||||
@@ -24,6 +25,13 @@ class AuthenticateJWT
|
||||
|
||||
// Validate IP and User Agent
|
||||
if ($payload) {
|
||||
if ($frontApiSecret = $request->header(self::API_SERVER_SECRET_HEADER_NAME)) {
|
||||
// If it's a trusted SSR request, skip the rest
|
||||
if ($frontApiSecret === config('app.front_api_secret')) {
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
|
||||
$error = null;
|
||||
if (!\Hash::check($request->ip(), $payload->get('ip'))) {
|
||||
$error = 'Origin IP is invalid';
|
||||
|
||||
@@ -11,7 +11,7 @@ use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class CustomDomainRestriction
|
||||
{
|
||||
const CUSTOM_DOMAIN_HEADER = "User-Custom-Domain";
|
||||
const CUSTOM_DOMAIN_HEADER = "x-custom-domain";
|
||||
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
@@ -27,7 +27,8 @@ class CustomDomainRestriction
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Invalid domain',
|
||||
], 400);
|
||||
'error' => 'invalid_domain',
|
||||
], 420);
|
||||
}
|
||||
|
||||
// Check if domain is different from current domain
|
||||
@@ -41,7 +42,8 @@ class CustomDomainRestriction
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Unknown domain',
|
||||
], 400);
|
||||
'error' => 'invalid_domain',
|
||||
], 420);
|
||||
}
|
||||
|
||||
Workspace::addGlobalScope('domain-restricted', function (Builder $builder) use ($workspace) {
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
class EmbeddableForms
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
if ($request->expectsJson() || $request->wantsJson()) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
$response = $next($request);
|
||||
|
||||
if (!str_starts_with($request->url(), url('/forms/'))) {
|
||||
if ($response instanceof Response) {
|
||||
$response->header('X-Frame-Options', 'SAMEORIGIN');
|
||||
} elseif ($response instanceof \Symfony\Component\HttpFoundation\Response) {
|
||||
$response->headers->set('X-Frame-Options', 'SAMEORIGIN');
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,11 @@ class FormSubmissionResource extends JsonResource
|
||||
return $file !== null && $file;
|
||||
})->map(function ($file) {
|
||||
return [
|
||||
'file_url' => route('open.forms.submissions.file', [$this->form_id, $file]),
|
||||
'file_url' => \URL::signedRoute(
|
||||
'open.forms.submissions.file',
|
||||
[$this->form_id, $file],
|
||||
now()->addMinutes(10)
|
||||
),
|
||||
'file_name' => $file,
|
||||
];
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user