Remove public api endpoint
This commit is contained in:
parent
534348b7a8
commit
4dc9149931
@ -158,8 +158,7 @@ Application behavior can be changed by configuring the following environment var
|
|||||||
#### Settings
|
#### Settings
|
||||||
- `NEXT_PUBLIC_GEO_PRIVACY = 1` disables collection/display of location-based data (⚠️ re-compresses uploaded images in order to remove GPS information)
|
- `NEXT_PUBLIC_GEO_PRIVACY = 1` disables collection/display of location-based data (⚠️ re-compresses uploaded images in order to remove GPS information)
|
||||||
- `NEXT_PUBLIC_ALLOW_PUBLIC_DOWNLOADS = 1` enables public photo downloads for all visitors (⚠️ may result in increased bandwidth usage)
|
- `NEXT_PUBLIC_ALLOW_PUBLIC_DOWNLOADS = 1` enables public photo downloads for all visitors (⚠️ may result in increased bandwidth usage)
|
||||||
- `NEXT_PUBLIC_PUBLIC_FEED = 1` enables public feed available at `/feed.json` and `/rss.xml`
|
- `NEXT_PUBLIC_SITE_FEEDS = 1` enables feeds at `/feed.json` and `/rss.xml`
|
||||||
- `NEXT_PUBLIC_PUBLIC_API = 1` enables public API available at `/api`
|
|
||||||
- `NEXT_PUBLIC_IGNORE_PRIORITY_ORDER = 1` prevents `priority_order` field affecting photo order
|
- `NEXT_PUBLIC_IGNORE_PRIORITY_ORDER = 1` prevents `priority_order` field affecting photo order
|
||||||
- `NEXT_PUBLIC_OG_TEXT_ALIGNMENT = BOTTOM` keeps OG image text bottom aligned (default is top)
|
- `NEXT_PUBLIC_OG_TEXT_ALIGNMENT = BOTTOM` keeps OG image text bottom aligned (default is top)
|
||||||
|
|
||||||
|
|||||||
@ -1,24 +0,0 @@
|
|||||||
import { getPhotosCached } from '@/photo/cache';
|
|
||||||
import { API_PHOTO_REQUEST_LIMIT, formatPhotoForApi } from '@/app/api';
|
|
||||||
import {
|
|
||||||
BASE_URL,
|
|
||||||
PUBLIC_API_ENABLED,
|
|
||||||
META_TITLE,
|
|
||||||
} from '@/app/config';
|
|
||||||
|
|
||||||
export const dynamic = 'force-dynamic';
|
|
||||||
|
|
||||||
export async function GET() {
|
|
||||||
if (PUBLIC_API_ENABLED) {
|
|
||||||
const photos = await getPhotosCached({ limit: API_PHOTO_REQUEST_LIMIT });
|
|
||||||
return Response.json({
|
|
||||||
meta: {
|
|
||||||
title: META_TITLE,
|
|
||||||
url: BASE_URL,
|
|
||||||
},
|
|
||||||
photos: photos.map(formatPhotoForApi),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return new Response('API access disabled', { status: 404 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,18 +1,17 @@
|
|||||||
import { getPhotosCached } from '@/photo/cache';
|
import { getPhotosCached } from '@/photo/cache';
|
||||||
import { INFINITE_SCROLL_FEED_INITIAL } from '@/photo';
|
|
||||||
import {
|
import {
|
||||||
BASE_URL,
|
BASE_URL,
|
||||||
PUBLIC_FEED_ENABLED,
|
SITE_FEEDS_ENABLED,
|
||||||
META_TITLE,
|
META_TITLE,
|
||||||
} from '@/app/config';
|
} from '@/app/config';
|
||||||
import { formatPhotoForFeedJson } from '@/app/feed';
|
import { FEED_PHOTO_REQUEST_LIMIT, formatPhotoForFeedJson } from '@/app/feed';
|
||||||
|
|
||||||
export const dynamic = 'force-static';
|
export const dynamic = 'force-static';
|
||||||
|
|
||||||
export async function GET() {
|
export async function GET() {
|
||||||
if (PUBLIC_FEED_ENABLED) {
|
if (SITE_FEEDS_ENABLED) {
|
||||||
const photos = await getPhotosCached({
|
const photos = await getPhotosCached({
|
||||||
limit: INFINITE_SCROLL_FEED_INITIAL,
|
limit: FEED_PHOTO_REQUEST_LIMIT,
|
||||||
sortBy: 'createdAt',
|
sortBy: 'createdAt',
|
||||||
});
|
});
|
||||||
return Response.json({
|
return Response.json({
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import {
|
|||||||
META_TITLE,
|
META_TITLE,
|
||||||
HTML_LANG,
|
HTML_LANG,
|
||||||
NAV_CAPTION,
|
NAV_CAPTION,
|
||||||
PUBLIC_FEED_ENABLED,
|
SITE_FEEDS_ENABLED,
|
||||||
} from '@/app/config';
|
} from '@/app/config';
|
||||||
import AppStateProvider from '@/state/AppStateProvider';
|
import AppStateProvider from '@/state/AppStateProvider';
|
||||||
import ToasterWithThemes from '@/toast/ToasterWithThemes';
|
import ToasterWithThemes from '@/toast/ToasterWithThemes';
|
||||||
@ -66,7 +66,7 @@ export const metadata: Metadata = {
|
|||||||
type: 'image/png',
|
type: 'image/png',
|
||||||
sizes: '180x180',
|
sizes: '180x180',
|
||||||
}],
|
}],
|
||||||
...PUBLIC_FEED_ENABLED && {
|
...SITE_FEEDS_ENABLED && {
|
||||||
alternates: {
|
alternates: {
|
||||||
types: {
|
types: {
|
||||||
'application/rss+xml': '/rss.xml',
|
'application/rss+xml': '/rss.xml',
|
||||||
|
|||||||
@ -4,14 +4,15 @@ import {
|
|||||||
BASE_URL,
|
BASE_URL,
|
||||||
META_DESCRIPTION,
|
META_DESCRIPTION,
|
||||||
META_TITLE,
|
META_TITLE,
|
||||||
PUBLIC_FEED_ENABLED,
|
SITE_FEEDS_ENABLED,
|
||||||
} from '@/app/config';
|
} from '@/app/config';
|
||||||
import { feedPhotoToXml, formatPhotoForFeedRss } from '@/app/feed';
|
import { feedPhotoToXml, formatPhotoForFeedRss } from '@/app/feed';
|
||||||
|
import { ABSOLUTE_PATH_FOR_FEED_JSON } from '@/app/paths';
|
||||||
|
|
||||||
export const dynamic = 'force-static';
|
export const dynamic = 'force-static';
|
||||||
|
|
||||||
export async function GET() {
|
export async function GET() {
|
||||||
if (PUBLIC_FEED_ENABLED) {
|
if (SITE_FEEDS_ENABLED) {
|
||||||
const photos = await getPhotosCached({
|
const photos = await getPhotosCached({
|
||||||
limit: INFINITE_SCROLL_FEED_INITIAL,
|
limit: INFINITE_SCROLL_FEED_INITIAL,
|
||||||
sortBy: 'createdAt',
|
sortBy: 'createdAt',
|
||||||
@ -26,13 +27,11 @@ export async function GET() {
|
|||||||
|
|
||||||
<channel>
|
<channel>
|
||||||
<title>${META_TITLE}</title>
|
<title>${META_TITLE}</title>
|
||||||
<atom:link href="${BASE_URL}/rss.xml"
|
<atom:link href="${ABSOLUTE_PATH_FOR_FEED_JSON}"
|
||||||
rel="self" type="application/rss+xml" />
|
rel="self" type="application/rss+xml" />
|
||||||
<link>${BASE_URL}</link>
|
<link>${BASE_URL}</link>
|
||||||
<description>${META_DESCRIPTION}</description>
|
<description>${META_DESCRIPTION}</description>
|
||||||
|
${items.join('\n')}
|
||||||
${items.join('\n\n ')}
|
|
||||||
|
|
||||||
</channel>
|
</channel>
|
||||||
|
|
||||||
</rss>`,
|
</rss>`,
|
||||||
|
|||||||
@ -31,6 +31,8 @@ import ScoreCardContainer from '@/components/ScoreCardContainer';
|
|||||||
import { DEFAULT_CATEGORY_KEYS, getHiddenCategories } from '@/category';
|
import { DEFAULT_CATEGORY_KEYS, getHiddenCategories } from '@/category';
|
||||||
import { AI_AUTO_GENERATED_FIELDS_ALL } from '@/photo/ai';
|
import { AI_AUTO_GENERATED_FIELDS_ALL } from '@/photo/ai';
|
||||||
import clsx from 'clsx/lite';
|
import clsx from 'clsx/lite';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import { PATH_FEED_JSON, PATH_RSS_XML } from '@/app/paths';
|
||||||
|
|
||||||
export default function AdminAppConfigurationClient({
|
export default function AdminAppConfigurationClient({
|
||||||
// Storage
|
// Storage
|
||||||
@ -103,8 +105,7 @@ export default function AdminAppConfigurationClient({
|
|||||||
// Settings
|
// Settings
|
||||||
isGeoPrivacyEnabled,
|
isGeoPrivacyEnabled,
|
||||||
arePublicDownloadsEnabled,
|
arePublicDownloadsEnabled,
|
||||||
isPublicApiEnabled,
|
areSiteFeedsEnabled,
|
||||||
isPublicFeedEnabled,
|
|
||||||
isPriorityOrderEnabled,
|
isPriorityOrderEnabled,
|
||||||
isOgTextBottomAligned,
|
isOgTextBottomAligned,
|
||||||
// Internal
|
// Internal
|
||||||
@ -178,6 +179,15 @@ export default function AdminAppConfigurationClient({
|
|||||||
{message}
|
{message}
|
||||||
</ErrorNote>;
|
</ErrorNote>;
|
||||||
|
|
||||||
|
const renderLink = (href: string, children?: ReactNode) =>
|
||||||
|
<Link
|
||||||
|
href={href}
|
||||||
|
className="underline underline-offset-3 hover:no-underline"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
{children || href}
|
||||||
|
</Link>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScoreCardContainer>
|
<ScoreCardContainer>
|
||||||
<ChecklistGroup
|
<ChecklistGroup
|
||||||
@ -735,23 +745,14 @@ export default function AdminAppConfigurationClient({
|
|||||||
{renderEnvVars(['NEXT_PUBLIC_ALLOW_PUBLIC_DOWNLOADS'])}
|
{renderEnvVars(['NEXT_PUBLIC_ALLOW_PUBLIC_DOWNLOADS'])}
|
||||||
</ChecklistRow>
|
</ChecklistRow>
|
||||||
<ChecklistRow
|
<ChecklistRow
|
||||||
title="Public Feed"
|
title="Site feeds (JSON/RSS)"
|
||||||
status={isPublicFeedEnabled}
|
status={areSiteFeedsEnabled}
|
||||||
optional
|
optional
|
||||||
>
|
>
|
||||||
Set environment variable to {'"1"'} to enable
|
Set environment variable to {'"1"'} to enable feeds at
|
||||||
a public feed available at <code>/feed.json</code>
|
{' '}
|
||||||
and <code>/rss.xml</code>:
|
{renderLink(PATH_FEED_JSON)} and {renderLink(PATH_RSS_XML)}:
|
||||||
{renderEnvVars(['NEXT_PUBLIC_PUBLIC_FEED'])}
|
{renderEnvVars(['NEXT_PUBLIC_SITE_FEEDS'])}
|
||||||
</ChecklistRow>
|
|
||||||
<ChecklistRow
|
|
||||||
title="Public API"
|
|
||||||
status={isPublicApiEnabled}
|
|
||||||
optional
|
|
||||||
>
|
|
||||||
Set environment variable to {'"1"'} to enable
|
|
||||||
a public API available at <code>/api</code>:
|
|
||||||
{renderEnvVars(['NEXT_PUBLIC_PUBLIC_API'])}
|
|
||||||
</ChecklistRow>
|
</ChecklistRow>
|
||||||
<ChecklistRow
|
<ChecklistRow
|
||||||
title="Priority order"
|
title="Priority order"
|
||||||
|
|||||||
@ -1,43 +0,0 @@
|
|||||||
import { Photo } from '@/photo';
|
|
||||||
import { absolutePathForPhoto } from './paths';
|
|
||||||
import { formatDateFromPostgresString } from '@/utility/date';
|
|
||||||
import { getNextImageUrlForRequest } from '@/platforms/next-image';
|
|
||||||
|
|
||||||
export const API_PHOTO_REQUEST_LIMIT = 40;
|
|
||||||
|
|
||||||
export interface PublicApi {
|
|
||||||
meta: {
|
|
||||||
title: string
|
|
||||||
url: string
|
|
||||||
}
|
|
||||||
photos: PublicApiPhoto[]
|
|
||||||
}
|
|
||||||
|
|
||||||
interface PublicApiPhoto {
|
|
||||||
id: string
|
|
||||||
title?: string
|
|
||||||
url: string
|
|
||||||
make?: string
|
|
||||||
model?: string
|
|
||||||
tags?: string[]
|
|
||||||
takenAtNaive: string
|
|
||||||
src: Record<
|
|
||||||
'small' | 'medium' | 'large',
|
|
||||||
string
|
|
||||||
>
|
|
||||||
}
|
|
||||||
|
|
||||||
export const formatPhotoForApi = (photo: Photo): PublicApiPhoto => ({
|
|
||||||
id: photo.id,
|
|
||||||
title: photo.title,
|
|
||||||
url: absolutePathForPhoto({ photo }),
|
|
||||||
...photo.make && { make: photo.make },
|
|
||||||
...photo.model && { model: photo.model },
|
|
||||||
...photo.tags.length > 0 && { tags: photo.tags },
|
|
||||||
takenAtNaive: formatDateFromPostgresString(photo.takenAtNaive),
|
|
||||||
src: {
|
|
||||||
small: getNextImageUrlForRequest({ imageUrl: photo.url, size: 200 }),
|
|
||||||
medium: getNextImageUrlForRequest({ imageUrl: photo.url, size: 640 }),
|
|
||||||
large: getNextImageUrlForRequest({ imageUrl: photo.url, size: 1200 }),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@ -307,10 +307,8 @@ export const GEO_PRIVACY_ENABLED =
|
|||||||
process.env.NEXT_PUBLIC_GEO_PRIVACY === '1';
|
process.env.NEXT_PUBLIC_GEO_PRIVACY === '1';
|
||||||
export const ALLOW_PUBLIC_DOWNLOADS =
|
export const ALLOW_PUBLIC_DOWNLOADS =
|
||||||
process.env.NEXT_PUBLIC_ALLOW_PUBLIC_DOWNLOADS === '1';
|
process.env.NEXT_PUBLIC_ALLOW_PUBLIC_DOWNLOADS === '1';
|
||||||
export const PUBLIC_FEED_ENABLED =
|
export const SITE_FEEDS_ENABLED =
|
||||||
process.env.NEXT_PUBLIC_PUBLIC_FEED === '1';
|
process.env.NEXT_PUBLIC_SITE_FEEDS === '1';
|
||||||
export const PUBLIC_API_ENABLED =
|
|
||||||
process.env.NEXT_PUBLIC_PUBLIC_API === '1';
|
|
||||||
export const PRIORITY_ORDER_ENABLED =
|
export const PRIORITY_ORDER_ENABLED =
|
||||||
process.env.NEXT_PUBLIC_IGNORE_PRIORITY_ORDER !== '1';
|
process.env.NEXT_PUBLIC_IGNORE_PRIORITY_ORDER !== '1';
|
||||||
export const OG_TEXT_BOTTOM_ALIGNMENT =
|
export const OG_TEXT_BOTTOM_ALIGNMENT =
|
||||||
@ -419,8 +417,7 @@ export const APP_CONFIGURATION = {
|
|||||||
// Settings
|
// Settings
|
||||||
isGeoPrivacyEnabled: GEO_PRIVACY_ENABLED,
|
isGeoPrivacyEnabled: GEO_PRIVACY_ENABLED,
|
||||||
arePublicDownloadsEnabled: ALLOW_PUBLIC_DOWNLOADS,
|
arePublicDownloadsEnabled: ALLOW_PUBLIC_DOWNLOADS,
|
||||||
isPublicApiEnabled: PUBLIC_API_ENABLED,
|
areSiteFeedsEnabled: SITE_FEEDS_ENABLED,
|
||||||
isPublicFeedEnabled: PUBLIC_FEED_ENABLED,
|
|
||||||
isPriorityOrderEnabled: PRIORITY_ORDER_ENABLED,
|
isPriorityOrderEnabled: PRIORITY_ORDER_ENABLED,
|
||||||
isOgTextBottomAligned: OG_TEXT_BOTTOM_ALIGNMENT,
|
isOgTextBottomAligned: OG_TEXT_BOTTOM_ALIGNMENT,
|
||||||
// Internal
|
// Internal
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import {
|
|||||||
} from '@/platforms/next-image';
|
} from '@/platforms/next-image';
|
||||||
import { formatDate, formatDateFromPostgresString } from '@/utility/date';
|
import { formatDate, formatDateFromPostgresString } from '@/utility/date';
|
||||||
|
|
||||||
export const API_PHOTO_REQUEST_LIMIT = 40;
|
export const FEED_PHOTO_REQUEST_LIMIT = 40;
|
||||||
|
|
||||||
export const FEED_PHOTO_WIDTH_SMALL = 200;
|
export const FEED_PHOTO_WIDTH_SMALL = 200;
|
||||||
export const FEED_PHOTO_WIDTH_MEDIUM = 640;
|
export const FEED_PHOTO_WIDTH_MEDIUM = 640;
|
||||||
|
|||||||
@ -15,6 +15,10 @@ export const PATH_API = '/api';
|
|||||||
export const PATH_SIGN_IN = '/sign-in';
|
export const PATH_SIGN_IN = '/sign-in';
|
||||||
export const PATH_OG = '/og';
|
export const PATH_OG = '/og';
|
||||||
|
|
||||||
|
// Feeds
|
||||||
|
export const PATH_FEED_JSON = '/feed.json';
|
||||||
|
export const PATH_RSS_XML = '/rss.xml';
|
||||||
|
|
||||||
export const PATH_GRID_INFERRED = GRID_HOMEPAGE_ENABLED
|
export const PATH_GRID_INFERRED = GRID_HOMEPAGE_ENABLED
|
||||||
? PATH_ROOT
|
? PATH_ROOT
|
||||||
: PATH_GRID;
|
: PATH_GRID;
|
||||||
@ -167,6 +171,12 @@ export const pathForRecipe = (recipe: string) =>
|
|||||||
`${PREFIX_RECIPE}/${recipe}`;
|
`${PREFIX_RECIPE}/${recipe}`;
|
||||||
|
|
||||||
// Absolute paths
|
// Absolute paths
|
||||||
|
export const ABSOLUTE_PATH_FOR_FEED_JSON =
|
||||||
|
`${getBaseUrl()}${PATH_FEED_JSON}`;
|
||||||
|
|
||||||
|
export const ABSOLUTE_PATH_FOR_RSS_XML =
|
||||||
|
`${getBaseUrl()}${PATH_RSS_XML}`;
|
||||||
|
|
||||||
export const ABSOLUTE_PATH_FOR_HOME_IMAGE =
|
export const ABSOLUTE_PATH_FOR_HOME_IMAGE =
|
||||||
`${getBaseUrl()}/home-image`;
|
`${getBaseUrl()}/home-image`;
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user