Compare commits

..

No commits in common. "main" and "backup-main" have entirely different histories.

14 changed files with 50 additions and 105 deletions

View File

@ -12,7 +12,7 @@ steps:
auto_tag: true
registry: git.autonomic.zone
dockerfile: ./Dockerfile
repo: git.autonomic.zone/autonomic-cooperative/nextload
repo: git.autonomic.zone/autonomic-cooperative/nextjs
- name: deploy stack
image: git.coopcloud.tech/coop-cloud/stack-ssh-deploy:latest
@ -29,4 +29,4 @@ steps:
SECRET_MONGO_PASSWORD_VERSION: v1
REPOSITORY: "autonomic-cooperative/nextload"
depends_on:
- publish nextjs container
- publish nextjs container

View File

@ -44,6 +44,5 @@ ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
COPY docker-entrypoint.sh /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["pnpm", "start:standalone"]

View File

@ -1,49 +0,0 @@
.PHONY: sync_db
# Define variables
REMOTE_USER=tma
REMOTE_SERVER=swarm-demo.autonomic.zone
REMOTE_PORT=222
REMOTE_CONTAINER_PATH=/data/db/mongodump
LOCAL_PATH=/tmp/mongodump
LOCAL_DB=test
LOCAL_CONTAINER_NAME=nextload-mongo-1
REMOTE_VOLUME_NAME = nextload-demo_autonomic_zone_payload_uploads
LOCAL_VOLUME_NAME = nextload_payload_uploads
ENV_FILE=.env
include $(ENV_FILE)
sync_db:
@echo "Step 1: Dump the database on production"
docker --context swarm-demo.autonomic.zone exec -it $$(docker --context swarm-demo.autonomic.zone ps -q -f name=nextload-demo_autonomic_zone_mongo) \
bash -c 'rm -rf $(REMOTE_CONTAINER_PATH) && mongodump -u mongo -p "$$(cat /run/secrets/mongo_password)" -o $(REMOTE_CONTAINER_PATH) && ls -l $(REMOTE_CONTAINER_PATH)'
@echo "Step 2: Copy the dump from the remote MongoDB container to the local machine"
rm -rf $(LOCAL_PATH)
mkdir -p $(LOCAL_PATH) # Create the target directory if it doesn't exist
ssh -p $(REMOTE_PORT) $(REMOTE_USER)@$(REMOTE_SERVER) \
"docker exec $$(docker --context swarm-demo.autonomic.zone ps -q -f name=nextload-demo_autonomic_zone_mongo) \
tar -cC $(REMOTE_CONTAINER_PATH) ." | tar -xC $(LOCAL_PATH)
@echo "Step 3: Copy the dump from local machine to MongoDB container"
docker cp $(LOCAL_PATH)/ $(LOCAL_CONTAINER_NAME):/tmp/mongodump
@echo "Step 4: Drop the existing local database and restore the dump"
docker exec -it $(LOCAL_CONTAINER_NAME) mongorestore --drop --username $(MONGO_USER) --password $(MONGO_PASSWORD) --authenticationDatabase admin --db $(LOCAL_DB) /tmp/mongodump/$(LOCAL_DB)
sync_media:
@echo "Step 1: Create a tar archive of the remote Docker volume"
rm -rf /tmp/$(REMOTE_VOLUME_NAME)
mkdir -p /tmp/$(REMOTE_VOLUME_NAME)
ssh -p $(REMOTE_PORT) $(REMOTE_USER)@$(REMOTE_SERVER) \
"docker run --rm -v $(REMOTE_VOLUME_NAME):/volume -v /tmp:/backup alpine tar -czf /backup/$(REMOTE_VOLUME_NAME).tar.gz -C /volume ."
@echo "Step 2: Copy the media from remote volume to local volume"
scp -P $(REMOTE_PORT) $(REMOTE_USER)@$(REMOTE_SERVER):/tmp/$(REMOTE_VOLUME_NAME).tar.gz /tmp/$(REMOTE_VOLUME_NAME).tar.gz
docker run --rm -v /tmp:/volume -v $(LOCAL_VOLUME_NAME):/backup alpine tar -xzf /volume/$(REMOTE_VOLUME_NAME).tar.gz -C /backup
@echo "Step 3: Cleanup temporary files"
rm /tmp/$(REMOTE_VOLUME_NAME).tar.gz
@echo "Media synchronization complete."

View File

@ -40,4 +40,4 @@ You'll see that Payload requires a few files to be present in your `/app` folder
You'll see in the Next.js config that we have a `withPayload` function installed. This function is required for Payload to operate, and it ensures compatibility with packages that Payload needs such as `drizzle-kit`, `sharp`, `pino`, and `mongodb`.
**Using a TypeScript alias to point to your Payload config**
In the `tsconfig.json` within this repo, you'll see that we have `paths` set up to point `@payload-config` to the Payload config, which is located in the root. You can put your config wherever you want. By default, the `page.tsx` files and `route.ts` files within the `/app` folder use this alias. In the future, we might make it optional to use `paths` - and by default, we might just hard-code relative path imports to the config. We would like to hear your feedback on this part. What do you prefer? Use `paths` or just use relative imports?
In the `tsconfig.json` within this repo, you'll see that we have `paths` set up to point `@payload-config` to the Payload config, which is located in the root. You can put your config wherever you want. By default, the `page.tsx` files and `route.ts` files within the `/app` folder use this alias. In the future, we might make it optional to use `paths` - and by default, we might just hard-code relative path imports to the config. We would like to hear your feedback on this part. What do you prefer? Use `paths` or just use relative imports?

View File

@ -4,7 +4,6 @@ version: "3.8"
services:
nextjs:
image: git.autonomic.zone/autonomic-cooperative/nextload:latest
restart: unless-stopped
environment:
- "NAME=${STACK_NAME}"
- "PAYLOAD_SECRET_FILE=/run/secrets/payload_secret"
@ -20,7 +19,7 @@ services:
- mongo_password
- payload_secret
volumes:
- payload_uploads:/prod/.next/standalone/media
- payload_uploads:/runner/.next/standalone/.next/media
networks:
- proxy
- internal

View File

@ -18,7 +18,7 @@ services:
- "HOSTNAME=0.0.0.0"
- "MONGODB_URI=mongodb://${MONGO_USER}:${MONGO_PASSWORD}@mongo:27017"
volumes:
- payload_uploads:/base/media
- /base/media
- ./:/base
networks:
- internal

View File

@ -11,7 +11,7 @@ const nextConfig = {
HOSTNAME: process.env.HOSTNAME,
},
// Disable minification & chunking for debugging
webpack(config, { dev }) {
/* webpack(config, { dev }) {
config.optimization.minimize = false
config.optimization.splitChunks = {
cacheGroups: {
@ -20,7 +20,7 @@ const nextConfig = {
}
config.optimization.runtimeChunk = false
return config
},
}, */
}
export default withPayload(nextConfig)

View File

@ -37,7 +37,7 @@ export default buildConfig({
collections: [Users, Posts, Authors, Media, Pages],
admin: {
autoLogin: {
email: 'admin@nextload.test',
email: 'dev@payloadcms.com',
password: 'test',
prefillOnly: true,
},
@ -60,14 +60,14 @@ export default buildConfig({
async onInit(payload) {
const existingUsers = await payload.find({
collection: 'users',
limit: 2,
limit: 1,
})
if (existingUsers.docs.length === 0 || existingUsers.docs.length === 1) {
if (existingUsers.docs.length === 0) {
await payload.create({
collection: 'users',
data: {
email: 'admin@nextload.test',
email: 'dev@payloadcms.com',
password: 'test',
roles: ['admin'],
},

View File

@ -7,7 +7,8 @@ import { notFound } from 'next/navigation'
const PreviewCatchAllPage = async ({ params }: { params: { path: string[] } }) => {
noStore()
const [page] = await Promise.all([
const [user, page] = await Promise.all([
getCurrentUser(),
getDocument({
collection: COLLECTION_SLUG_PAGE,
path: params.path,
@ -15,8 +16,7 @@ const PreviewCatchAllPage = async ({ params }: { params: { path: string[] } }) =
cache: false,
}),
])
if (!page) notFound()
if (!user || !page) notFound()
return <PreviewBlocks initialData={page} locale="" url={process.env.BASE_URL || ''} />
}

View File

@ -8,7 +8,8 @@ import PreviewPostPage from '@/components/PreviewPostPage'
const PreviewCatchAllPage = async ({ params }: { params: { path: string[] } }) => {
noStore()
const [page] = await Promise.all([
const [user, page] = await Promise.all([
getCurrentUser(),
getDocument({
collection: COLLECTION_SLUG_POST,
path: params.path,
@ -16,7 +17,7 @@ const PreviewCatchAllPage = async ({ params }: { params: { path: string[] } }) =
cache: false,
}),
])
if (!page) notFound()
if (!user || !page) notFound()
return <PreviewPostPage initialData={page} locale="" url={process.env.BASE_URL || ''} />
}

View File

@ -2,11 +2,7 @@ import { Access } from 'payload/types'
import type { User } from 'types/payload-types'
export const isAdmin = ({ req: { user } }: any) => {
if (!user || !user.roles) {
return false
}
if (user.roles?.includes('admin')) {
if (user && user.roles?.includes('admin')) {
return true
}
@ -14,11 +10,7 @@ export const isAdmin = ({ req: { user } }: any) => {
}
export const isAdminOrCreatedBy = ({ req: { user } }: any) => {
if (!user || !user.roles) {
return false
}
if (user.roles?.includes('admin')) {
if (user && user.role === 'admin') {
return true
}
@ -34,27 +26,24 @@ export const isAdminOrCreatedBy = ({ req: { user } }: any) => {
}
export const isAdminOrSelf = ({ req: { user } }: any) => {
if (!user || !user.roles) {
return false
}
if (user.roles?.includes('admin')) {
return true
}
// Non-admin: can only access themselves
return {
id: {
equals: user.id,
},
}
}
export const isAdminOrPublished = ({ req: { user } }: any) => {
if (user && user.roles) {
if (user) {
if (user.roles?.includes('admin')) {
return true
}
// Non-admin: can only access themselves
return {
id: {
equals: user.id,
},
}
}
return false
}
export const isAdminOrPublished = ({ req: { user } }: any) => {
if (user && user?.role === 'admin') {
return true
}
return {

View File

@ -2,11 +2,7 @@ import { Access, FieldAccess } from 'payload/types'
import type { User } from 'types/payload-types'
export const isEditor = ({ req: { user } }: any) => {
if (!user || !user.roles) {
return false
}
if (user?.roles?.some((role: string) => ['editor', 'admin'].includes(role))) {
if (user && user?.roles?.some((role: string) => ['editor', 'admin'].includes(role))) {
return true
}

View File

@ -2,11 +2,7 @@ import { Access, FieldAccess } from 'payload/types'
import type { User } from 'types/payload-types'
export const isUser = ({ req: { user } }: any) => {
if (!user || !user.roles) {
return false
}
if (user?.roles?.some((role: string) => ['user', 'editor', 'admin'].includes(role))) {
if (user && user?.roles?.some((role: string) => ['user', 'editor', 'admin'].includes(role))) {
return true
}

14
src/app/my-route/route.ts Normal file
View File

@ -0,0 +1,14 @@
import { getPayloadHMR } from '@payloadcms/next/utilities'
import configPromise from '@payload-config'
export const GET = async () => {
const payload = await getPayloadHMR({
config: configPromise,
})
const data = await payload.find({
collection: 'users',
})
return Response.json(data)
}