HEX
Server: LiteSpeed
System: Linux s1049.use1.mysecurecloudhost.com 4.18.0-477.27.2.lve.el8.x86_64 #1 SMP Wed Oct 11 12:32:56 UTC 2023 x86_64
User: xedaptot (3356)
PHP: 8.3.31
Disabled: NONE
Upload Files
File: /home/xedaptot/be.naniguide.com/app/Http/Controllers/Refactor/WebsiteController.php
<?php

namespace App\Http\Controllers\Refactor;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Model\Website;
use Gate;

class WebsiteController extends Controller
{
    public function index(Request $request)
    {
        if (Gate::denies('list', Website::class)) {
            return $this->notAuthorized();
        }

        $customer = $request->user()->customer;
        $total = $customer->local()->websites()->count();

        return view('refactor.pages.websites.index', [
            'customer' => $customer,
            'total' => $total,
        ]);
    }

    public function listing(Request $request)
    {
        if (Gate::denies('list', Website::class)) {
            return $this->notAuthorized();
        }

        $websites = $request->user()->customer->local()->websites()
            ->search($request->keyword)
            ->orderBy($request->sort_order ?? 'created_at', $request->sort_direction ?? 'desc')
            ->paginate($request->per_page ?? 25);

        return view('refactor.pages.websites._list', [
            'websites' => $websites,
        ]);
    }

    public function create(Request $request)
    {
        if (Gate::denies('create', Website::class)) {
            return $this->notAuthorized();
        }

        $website = Website::newDefault($request->user()->customer);

        return view('refactor.pages.websites.form', [
            'website' => $website,
            'mode' => 'create',
        ]);
    }

    public function store(Request $request)
    {
        if (Gate::denies('create', Website::class)) {
            return response()->json(['status' => 'error', 'message' => trans('messages.not_authorized')], 403);
        }

        $website = Website::newDefault($request->user()->customer);
        $validator = $website->createFromArray($request->all());

        if ($validator->fails()) {
            return response()->json([
                'status' => 'error',
                'errors' => $validator->errors(),
            ], 422);
        }

        return response()->json([
            'status' => 'success',
            'message' => trans('refactor/websites.flash.created'),
            'redirect' => route('refactor.websites.edit', $website->uid),
        ]);
    }

    public function edit(Request $request, $uid)
    {
        $website = Website::findByUid($uid);

        if (Gate::denies('read', $website)) {
            return $this->notAuthorized();
        }

        return view('refactor.pages.websites.form', [
            'website' => $website,
            'mode' => 'edit',
        ]);
    }

    public function update(Request $request, $uid)
    {
        $website = Website::findByUid($uid);

        if (Gate::denies('read', $website)) {
            return response()->json(['status' => 'error', 'message' => trans('messages.not_authorized')], 403);
        }

        $validator = \Validator::make($request->all(), [
            'url' => 'required|url|active_url',
        ], [
            'url.url'        => 'The URL format is invalid (e.g. https://www.example.com).',
            'url.active_url' => 'The URL could not be reached. Please check that the domain exists and is publicly accessible.',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'status' => 'error',
                'errors' => $validator->errors(),
            ], 422);
        }

        // Update title from URL
        try {
            $website->title = Website::getTitleFromUrl($request->url);
        } catch (\Exception $e) {
            return response()->json([
                'status' => 'error',
                'errors' => ['url' => [$e->getMessage()]],
            ], 422);
        }

        $website->url = $request->url;
        $website->save();

        return response()->json([
            'status' => 'success',
            'message' => trans('refactor/websites.flash.updated'),
        ]);
    }

    public function delete(Request $request)
    {
        $websites = Website::whereIn(
            'uid',
            is_array($request->uids) ? $request->uids : explode(',', $request->uids)
        );

        $total = $websites->count();
        $deleted = 0;
        foreach ($websites->get() as $website) {
            if ($request->user()->customer->can('delete', $website)) {
                $website->delete();
                $deleted += 1;
            }
        }

        return response()->json([
            'status' => 'success',
            'message' => trans('refactor/websites.flash.deleted'),
        ]);
    }

    public function connect(Request $request, $uid)
    {
        $website = Website::findByUid($uid);

        // Ownership / RBAC first — non-owner must get 403 regardless of state.
        // Use the `read` policy because `connect` additionally requires
        // status=inactive, which we want to handle separately as a no-op
        // (see idempotent short-circuit below).
        if (Gate::denies('read', $website)) {
            return response()->json(['status' => 'error', 'message' => trans('messages.not_authorized')], 403);
        }

        // Idempotent: the embed script's first GET to /check-js auto-flips
        // the website to "connected" before the user clicks the manual
        // Collega button on a stale tab. Returning 403 here would render as
        // "NOT AUTHORIZED" — confusing because it actually IS connected.
        // Past incident 2026-04-29 (Andrea/newsletter24).
        if ($website->status === Website::STATUS_CONNECTED) {
            return response()->json([
                'status' => 'success',
                'message' => trans('refactor/websites.flash.already_connected'),
            ]);
        }

        if (Gate::denies('connect', $website)) {
            return response()->json(['status' => 'error', 'message' => trans('messages.not_authorized')], 403);
        }

        try {
            $website->connect();

            return response()->json([
                'status' => 'success',
                'message' => trans('refactor/websites.flash.connected'),
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'status' => 'error',
                'message' => $e->getMessage(),
            ], 400);
        }
    }

    public function disconnect(Request $request, $uid)
    {
        $website = Website::findByUid($uid);

        if (Gate::denies('disconnect', $website)) {
            return response()->json(['status' => 'error', 'message' => trans('messages.not_authorized')], 403);
        }

        $website->disconnect();

        return response()->json([
            'status' => 'success',
            'message' => trans('refactor/websites.flash.disconnected'),
        ]);
    }

    /**
     * Customer-facing embed script — served when a third-party site loads
     * `<script src="/rui/websites/{uid}/connect-js">`. Branches by website
     * activation state:
     *   • inactive → checkJs view (pings back to mark the website
     *     connected; reload will return the active branch).
     *   • active   → connectJs view (loads AFormPopup helper + iterates
     *     every connected published form, instantiating a popup for each).
     *
     * Both branches use REFACTOR views (`refactor/websites/*` +
     * `refactor/forms/frontend/*`). No legacy controller delegation, no
     * legacy view chain — keeps the whole embed surface inside the
     * refactor namespace per the layering rule.
     */
    public function connectJs(Request $request, $uid)
    {
        $website = \App\Model\Website::findByUid($uid);

        if (is_null($website)) {
            return response('not available', 404);
        }

        if (!$website->isActive()) {
            $content = view('refactor.websites.checkJs', [
                'website' => $website,
            ]);

            return response($content)
                ->header('Access-Control-Allow-Origin', '*')
                ->header('Content-Type', 'application/javascript');
        }

        $content = view('refactor.websites.connectJs', [
            'website' => $website,
        ]);

        return response($content)
            ->header('Access-Control-Allow-Origin', '*')
            ->header('Content-Type', 'application/javascript');
    }

    /**
     * Inactive-website ping back endpoint. The checkJs view (returned by
     * connectJs when the website is still inactive) GET-fetches this
     * endpoint, which flips the website to connected. Mirrors the legacy
     * `WebsiteController::checkJs` behaviour but lives in the refactor
     * namespace so the embed chain has no legacy dependencies.
     */
    public function checkJs(Request $request, $uid)
    {
        $website = \App\Model\Website::findByUid($uid);
        if (is_null($website)) {
            return response('not available', 404);
        }
        $website->setConnected();

        return response('ok')
            ->header('Access-Control-Allow-Origin', '*')
            ->header('Content-Type', 'text/plain');
    }
}