mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-13 15:13:07 +00:00
Board "Acompanhe de perto" (S1) ganha o feed automático do canal oficial: global SocialFeedSettings (admin-only, kill switch + toggle + maxItems + exclusões por item), loader src/utilities/youtubeFeed.ts (Data API v3 search→statistics, unstable_cache tag social-feed + revalidate 300, fail-closed com snapshot persistido via SQL direto — revalidateTag dentro de unstable_cache lança no Next 15.4), card generalizado (CampaignArticleCard → CampaignContentCard, external com noopener) e merge por recência com o grande = mais recente elegível. Stub HTTP do YouTube no webServer do Playwright (porta dev+1000) + 4 e2e novos no describe serial. Migration 20260818_111748_add_social_feed_settings (não destrutiva). Closes #18
183 lines
6.4 KiB
TypeScript
183 lines
6.4 KiB
TypeScript
import { postgresAdapter } from '@payloadcms/db-postgres'
|
|
import { lexicalEditor } from '@payloadcms/richtext-lexical'
|
|
import path from 'path'
|
|
import { buildConfig, type Access, type CollectionConfig } from 'payload'
|
|
import sharp from 'sharp'
|
|
import { fileURLToPath } from 'url'
|
|
|
|
import { resendAdapter } from '@payloadcms/email-resend'
|
|
import { importExportPlugin } from '@payloadcms/plugin-import-export'
|
|
import { s3Storage } from '@payloadcms/storage-s3'
|
|
import { pt } from 'payload/i18n/pt'
|
|
import { Activity } from './collections/Activity'
|
|
import { AllocationDecision } from './collections/AllocationDecision'
|
|
import { CalendarFeed } from './collections/CalendarFeed'
|
|
import { CampaignDemand } from './collections/CampaignDemand'
|
|
import { CampaignInvite } from './collections/CampaignInvite'
|
|
import { CampaignUser } from './collections/CampaignUser'
|
|
import { CampaignVoteSummarySnapshot } from './collections/CampaignVoteSummarySnapshot'
|
|
import { CampaignWebAuthnCredential } from './collections/CampaignWebAuthnCredential'
|
|
import { Consent } from './collections/Consent'
|
|
import { Contact } from './collections/Contact'
|
|
import { ElectionCandidate } from './collections/ElectionCandidate'
|
|
import { ElectionCandidateVote } from './collections/ElectionCandidateVote'
|
|
import { ElectionTally } from './collections/ElectionTally'
|
|
import { GoogleCalendarSync } from './collections/GoogleCalendarSync'
|
|
import { Leadership } from './collections/Leadership'
|
|
import { Media } from './collections/Media'
|
|
import { Municipality } from './collections/Municipality'
|
|
import { MunicipalityUpdate } from './collections/MunicipalityUpdate'
|
|
import { Notification } from './collections/Notification'
|
|
import { Organization } from './collections/Organization'
|
|
import { Petition } from './collections/Petition'
|
|
import { Post } from './collections/Post'
|
|
import { PushSubscription } from './collections/PushSubscription'
|
|
import { Signature } from './collections/Signature'
|
|
import { StateDeputy } from './collections/StateDeputy'
|
|
import { Subscription } from './collections/Subscription'
|
|
import { Supporter } from './collections/Supporter'
|
|
import { SupporterImportBatch } from './collections/SupporterImportBatch'
|
|
import { Tag } from './collections/Tag'
|
|
import { Users } from './collections/Users'
|
|
import { VotePledge } from './collections/VotePledge'
|
|
import { CampaignGoals } from './globals/CampaignGoals'
|
|
import { HomePage } from './globals/HomePage'
|
|
import { Metadata } from './globals/Metadata'
|
|
import { PrivacyPolicy } from './globals/PrivacyPolicy'
|
|
import { SiteSettings } from './globals/SiteSettings'
|
|
import { SocialFeedSettings } from './globals/SocialFeedSettings'
|
|
import { isPayloadAdmin } from './utilities/campaignAccess'
|
|
import { resolveS3StorageEnv } from './utilities/mediaStorage'
|
|
|
|
const filename = fileURLToPath(import.meta.url)
|
|
const dirname = path.dirname(filename)
|
|
|
|
const mediaStorage = resolveS3StorageEnv(process.env)
|
|
|
|
const campaignEmailFromAddress =
|
|
process.env.CAMPAIGN_EMAIL_FROM?.trim() || 'campanha@jorgesolla.com.br'
|
|
const campaignEmailFromName = process.env.CAMPAIGN_EMAIL_FROM_NAME?.trim() || 'Campanha Jorge Solla'
|
|
|
|
const importExportAdminOnly: Access = ({ req }) => isPayloadAdmin(req.user)
|
|
|
|
const withImportExportAdminAccess = ({ collection }: { collection: CollectionConfig }) => ({
|
|
...collection,
|
|
access: {
|
|
...collection.access,
|
|
read: importExportAdminOnly,
|
|
create: importExportAdminOnly,
|
|
update: importExportAdminOnly,
|
|
delete: importExportAdminOnly,
|
|
},
|
|
})
|
|
|
|
const adminCsvExportCollection = (slug: 'signature' | 'contact') => ({
|
|
slug,
|
|
import: false as const,
|
|
export: {
|
|
format: 'csv' as const,
|
|
disableJobsQueue: true,
|
|
disableSave: true,
|
|
},
|
|
})
|
|
|
|
export default buildConfig({
|
|
admin: {
|
|
user: Users.slug,
|
|
importMap: {
|
|
baseDir: path.resolve(dirname),
|
|
},
|
|
livePreview: {
|
|
url: 'http://localhost:3000',
|
|
globals: [SiteSettings.slug, HomePage.slug],
|
|
},
|
|
},
|
|
collections: [
|
|
Users,
|
|
CampaignUser,
|
|
CampaignWebAuthnCredential,
|
|
Notification,
|
|
PushSubscription,
|
|
CampaignInvite,
|
|
CampaignVoteSummarySnapshot,
|
|
Municipality,
|
|
Leadership,
|
|
Organization,
|
|
StateDeputy,
|
|
VotePledge,
|
|
AllocationDecision,
|
|
CampaignDemand,
|
|
Supporter,
|
|
SupporterImportBatch,
|
|
MunicipalityUpdate,
|
|
Activity,
|
|
CalendarFeed,
|
|
GoogleCalendarSync,
|
|
ElectionTally,
|
|
ElectionCandidateVote,
|
|
ElectionCandidate,
|
|
Media,
|
|
Petition,
|
|
Contact,
|
|
Consent,
|
|
Signature,
|
|
Subscription,
|
|
Post,
|
|
Tag,
|
|
],
|
|
globals: [SiteSettings, HomePage, Metadata, PrivacyPolicy, CampaignGoals, SocialFeedSettings],
|
|
editor: lexicalEditor(),
|
|
secret: process.env.PAYLOAD_SECRET || '',
|
|
typescript: {
|
|
outputFile: path.resolve(dirname, 'payload-types.ts'),
|
|
},
|
|
db: postgresAdapter({
|
|
pool: {
|
|
connectionString: process.env.DATABASE_URL || '',
|
|
},
|
|
// Schema changes are applied via committed migrations (pnpm migrate:create /
|
|
// pnpm migrate), never auto-pushed. `pnpm build` runs `payload migrate` before
|
|
// building, so migrations apply to prod on every Vercel deploy.
|
|
migrationDir: path.resolve(dirname, 'migrations'),
|
|
push: false,
|
|
}),
|
|
sharp,
|
|
email: resendAdapter({
|
|
defaultFromAddress: campaignEmailFromAddress,
|
|
defaultFromName: campaignEmailFromName,
|
|
apiKey: process.env.RESEND_API_KEY || '',
|
|
}),
|
|
plugins: [
|
|
// Media storage (OPS52): Garage S3 when the S3_* envs are set, local disk
|
|
// otherwise; a partial S3 config throws at boot (see mediaStorage.ts). The
|
|
// bucket stays private — Payload proxies files through /media/file.
|
|
...(mediaStorage.enabled
|
|
? [
|
|
s3Storage({
|
|
collections: {
|
|
media: true,
|
|
},
|
|
bucket: mediaStorage.bucket,
|
|
config: {
|
|
credentials: {
|
|
accessKeyId: mediaStorage.accessKeyId,
|
|
secretAccessKey: mediaStorage.secretAccessKey,
|
|
},
|
|
region: mediaStorage.region,
|
|
endpoint: mediaStorage.endpoint,
|
|
forcePathStyle: true,
|
|
},
|
|
}),
|
|
]
|
|
: []),
|
|
importExportPlugin({
|
|
collections: [adminCsvExportCollection('signature'), adminCsvExportCollection('contact')],
|
|
overrideExportCollection: withImportExportAdminAccess,
|
|
overrideImportCollection: withImportExportAdminAccess,
|
|
}),
|
|
],
|
|
i18n: {
|
|
fallbackLanguage: 'pt', // use 'pt' (not 'pt-BR') for Payload admin language code
|
|
supportedLanguages: { pt },
|
|
},
|
|
})
|