add SEO enhancements: OG images, meta robots, FAQ block, image sitemap
All checks were successful
deploy / deploy (push) Successful in 4m59s
All checks were successful
deploy / deploy (push) Successful in 4m59s
- Per-page SEO controls: meta robots directives, focus keyword, OG image - Site-wide default OG image in admin settings - FAQ block type with FAQPage JSON-LD schema - Enhanced Organization JSON-LD with business info, contact, address - Image sitemap with product images - SEO preview panel with Google/social card mockups - SEO checklist with real-time scoring - Business info section in site editor - GSC integration scaffolding (OAuth, client, cache) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
67
lib/berrypod_web/controllers/gsc_auth_controller.ex
Normal file
67
lib/berrypod_web/controllers/gsc_auth_controller.ex
Normal file
@@ -0,0 +1,67 @@
|
||||
defmodule BerrypodWeb.GSCAuthController do
|
||||
@moduledoc """
|
||||
Handles Google Search Console OAuth flow.
|
||||
"""
|
||||
|
||||
use BerrypodWeb, :controller
|
||||
|
||||
alias Berrypod.GSC.{Cache, OAuth}
|
||||
|
||||
@doc """
|
||||
Initiates the OAuth flow by redirecting to Google's consent screen.
|
||||
"""
|
||||
def connect(conn, _params) do
|
||||
case OAuth.authorize_url() do
|
||||
{:ok, url} ->
|
||||
redirect(conn, external: url)
|
||||
|
||||
{:error, :missing_client_id} ->
|
||||
conn
|
||||
|> put_flash(
|
||||
:error,
|
||||
"Google Search Console is not configured. Set GSC_CLIENT_ID and GSC_CLIENT_SECRET environment variables."
|
||||
)
|
||||
|> redirect(to: ~p"/admin/gsc")
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Handles the OAuth callback from Google.
|
||||
|
||||
Exchanges the authorization code for tokens and redirects to the dashboard.
|
||||
"""
|
||||
def callback(conn, %{"code" => code}) do
|
||||
case OAuth.exchange_code(code) do
|
||||
{:ok, _access_token} ->
|
||||
# Invalidate any stale cache when reconnecting
|
||||
Cache.invalidate()
|
||||
|
||||
conn
|
||||
|> put_flash(:info, "Connected to Google Search Console")
|
||||
|> redirect(to: ~p"/admin/gsc")
|
||||
|
||||
{:error, reason} ->
|
||||
conn
|
||||
|> put_flash(:error, "Failed to connect: #{inspect(reason)}")
|
||||
|> redirect(to: ~p"/admin/gsc")
|
||||
end
|
||||
end
|
||||
|
||||
def callback(conn, %{"error" => error}) do
|
||||
conn
|
||||
|> put_flash(:error, "Authorization denied: #{error}")
|
||||
|> redirect(to: ~p"/admin/gsc")
|
||||
end
|
||||
|
||||
@doc """
|
||||
Disconnects from Google Search Console by clearing stored tokens.
|
||||
"""
|
||||
def disconnect(conn, _params) do
|
||||
OAuth.disconnect()
|
||||
Cache.invalidate()
|
||||
|
||||
conn
|
||||
|> put_flash(:info, "Disconnected from Google Search Console")
|
||||
|> redirect(to: ~p"/admin/gsc")
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user