Compare commits
13 Commits
6244fd4072
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 444970718d | |||
| 89e9ccf458 | |||
| 8c661ecd12 | |||
| 190ac63ab8 | |||
| edee8c2b75 | |||
| 923c50bfac | |||
| d66df5ed43 | |||
| 865c0a7f8d | |||
| e325d990a7 | |||
| 87460cfb0f | |||
| 52ed483da4 | |||
| e36c39f581 | |||
| 048db7173d |
@@ -2,8 +2,12 @@ node_modules
|
|||||||
dist
|
dist
|
||||||
.git
|
.git
|
||||||
.gitignore
|
.gitignore
|
||||||
|
.env
|
||||||
.env.local
|
.env.local
|
||||||
.tmp
|
.tmp
|
||||||
*.log
|
*.log
|
||||||
docker-compose*.yml
|
docker-compose*.yml
|
||||||
Dockerfile*
|
Dockerfile*
|
||||||
|
strapi-cms
|
||||||
|
server/uploads
|
||||||
|
server/data
|
||||||
|
|||||||
+6
-9
@@ -4,14 +4,13 @@ services:
|
|||||||
# 1. PostgreSQL Database Service
|
# 1. PostgreSQL Database Service
|
||||||
postgres:
|
postgres:
|
||||||
image: postgres:16-alpine
|
image: postgres:16-alpine
|
||||||
container_name: citpl_postgres
|
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_DB: strapi
|
POSTGRES_DB: strapi
|
||||||
POSTGRES_USER: strapi
|
POSTGRES_USER: strapi
|
||||||
POSTGRES_PASSWORD: strapi_password_9000
|
POSTGRES_PASSWORD: strapi_password_9000
|
||||||
ports:
|
ports:
|
||||||
- "9543:5432" # Random port > 9000
|
- "9543:5432"
|
||||||
volumes:
|
volumes:
|
||||||
- postgres_data:/var/lib/postgresql/data
|
- postgres_data:/var/lib/postgresql/data
|
||||||
healthcheck:
|
healthcheck:
|
||||||
@@ -27,7 +26,6 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: ./strapi-cms
|
context: ./strapi-cms
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
container_name: citpl_strapi
|
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
DATABASE_CLIENT: postgres
|
DATABASE_CLIENT: postgres
|
||||||
@@ -45,7 +43,7 @@ services:
|
|||||||
TRANSFER_TOKEN_SALT: "tobemodifiedtransfertoken"
|
TRANSFER_TOKEN_SALT: "tobemodifiedtransfertoken"
|
||||||
JWT_SECRET: "tobemodifiedjwtsecret"
|
JWT_SECRET: "tobemodifiedjwtsecret"
|
||||||
ports:
|
ports:
|
||||||
- "9337:1337" # Random port > 9000
|
- "9337:1337"
|
||||||
volumes:
|
volumes:
|
||||||
- strapi_uploads:/app/public/uploads
|
- strapi_uploads:/app/public/uploads
|
||||||
depends_on:
|
depends_on:
|
||||||
@@ -59,7 +57,6 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile.backend
|
dockerfile: Dockerfile.backend
|
||||||
container_name: citpl_backend
|
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
PORT: 3005
|
PORT: 3005
|
||||||
@@ -70,10 +67,11 @@ services:
|
|||||||
ADMIN_PASSWORD: admin123
|
ADMIN_PASSWORD: admin123
|
||||||
CORS_ORIGIN: "*"
|
CORS_ORIGIN: "*"
|
||||||
ports:
|
ports:
|
||||||
- "9305:3005" # Random port > 9000
|
- "9305:3005"
|
||||||
volumes:
|
volumes:
|
||||||
- backend_uploads:/app/server/uploads
|
- backend_uploads:/app/server/uploads
|
||||||
- backend_data:/app/server/data
|
- backend_data:/app/server/data
|
||||||
|
- strapi_uploads:/app/strapi-cms/public/uploads
|
||||||
depends_on:
|
depends_on:
|
||||||
- strapi-cms
|
- strapi-cms
|
||||||
networks:
|
networks:
|
||||||
@@ -84,10 +82,9 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile.frontend
|
dockerfile: Dockerfile.frontend
|
||||||
container_name: citpl_frontend
|
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
expose:
|
||||||
- "9080:80" # Random port > 9000
|
- "80"
|
||||||
depends_on:
|
depends_on:
|
||||||
- backend
|
- backend
|
||||||
networks:
|
networks:
|
||||||
|
|||||||
+42
-21
@@ -2,6 +2,8 @@ server {
|
|||||||
listen 80;
|
listen 80;
|
||||||
server_name localhost;
|
server_name localhost;
|
||||||
|
|
||||||
|
client_max_body_size 100M;
|
||||||
|
|
||||||
root /usr/share/nginx/html;
|
root /usr/share/nginx/html;
|
||||||
index index.html;
|
index index.html;
|
||||||
|
|
||||||
@@ -11,7 +13,46 @@ server {
|
|||||||
gzip on;
|
gzip on;
|
||||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
|
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
|
||||||
|
|
||||||
# Explicit handling for static assets (JavaScript, CSS, images, fonts)
|
# Favicon handling
|
||||||
|
location = /favicon.ico {
|
||||||
|
try_files $uri /favicon.svg =200;
|
||||||
|
access_log off;
|
||||||
|
log_not_found off;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Priority prefix location for uploads - proxies to Express backend container
|
||||||
|
location ^~ /uploads/ {
|
||||||
|
proxy_pass http://backend:3005/uploads/;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
|
proxy_connect_timeout 60s;
|
||||||
|
proxy_send_timeout 60s;
|
||||||
|
proxy_read_timeout 60s;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Priority prefix location for backend API
|
||||||
|
location ^~ /api/ {
|
||||||
|
proxy_pass http://backend:3005/api/;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection 'upgrade';
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_cache_bypass $http_upgrade;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
|
# Prevent 504 Gateway Timeouts
|
||||||
|
proxy_connect_timeout 60s;
|
||||||
|
proxy_send_timeout 60s;
|
||||||
|
proxy_read_timeout 60s;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Explicit handling for static JS, CSS, images, and fonts
|
||||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|map)$ {
|
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|map)$ {
|
||||||
try_files $uri /citpl_website$uri =404;
|
try_files $uri /citpl_website$uri =404;
|
||||||
expires 30d;
|
expires 30d;
|
||||||
@@ -39,26 +80,6 @@ server {
|
|||||||
try_files $uri $uri/ /preview.html;
|
try_files $uri $uri/ /preview.html;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Proxy backend API requests to the Express backend container
|
|
||||||
location /api/ {
|
|
||||||
proxy_pass http://backend:3005/api/;
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header Connection 'upgrade';
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_cache_bypass $http_upgrade;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Proxy media upload requests to backend
|
|
||||||
location /uploads/ {
|
|
||||||
proxy_pass http://backend:3005/uploads/;
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
error_page 500 502 503 504 /50x.html;
|
error_page 500 502 503 504 /50x.html;
|
||||||
location = /50x.html {
|
location = /50x.html {
|
||||||
root /usr/share/nginx/html;
|
root /usr/share/nginx/html;
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 9.3 KiB |
+23
-2
@@ -81,9 +81,30 @@ export async function getStrapiBlogs() {
|
|||||||
date: dateStr,
|
date: dateStr,
|
||||||
image: coverUrl,
|
image: coverUrl,
|
||||||
slug: b.slug,
|
slug: b.slug,
|
||||||
author: typeof b.author === 'string' ? b.author : (b.author?.firstname ? `${b.author.firstname} ${b.author.lastname || ''}`.trim() : (b.author?.username || 'Dr. Arvindh Ramachandran')),
|
author: (() => {
|
||||||
|
if (typeof b.authorName === 'string' && b.authorName.trim()) return b.authorName.trim();
|
||||||
|
if (typeof b.author === 'string' && b.author.trim()) return b.author.trim();
|
||||||
|
const authorObj = b.author || b.createdBy;
|
||||||
|
if (authorObj && typeof authorObj === 'object') {
|
||||||
|
const full = `${authorObj.firstname || authorObj.firstName || ''} ${authorObj.lastname || authorObj.lastName || ''}`.trim();
|
||||||
|
if (full) return full;
|
||||||
|
if (authorObj.username) return authorObj.username;
|
||||||
|
}
|
||||||
|
const titleLower = (b.title || '').toLowerCase();
|
||||||
|
const catLower = (b.category || '').toLowerCase();
|
||||||
|
if (titleLower.includes('llm') || titleLower.includes('autonomous') || catLower.includes('ai')) return 'Dr. Arvindh Ramachandran';
|
||||||
|
if (titleLower.includes('scada') || titleLower.includes('zero-trust') || catLower.includes('operation')) return 'Vikramaditya Sharma';
|
||||||
|
if (titleLower.includes('supply chain') || titleLower.includes('predictive')) return 'Siddharth Varma';
|
||||||
|
if (titleLower.includes('speed vs') || titleLower.includes('workplace') || titleLower.includes('retention') || titleLower.includes('training')) return 'Purushothaman Gopalan';
|
||||||
|
if (catLower.includes('vr') || catLower.includes('immersive')) return 'Priya Sundaram';
|
||||||
|
return 'Purushothaman Gopalan';
|
||||||
|
})(),
|
||||||
authorDesignation: b.authorDesignation || 'Chief AI Architect & Head of Data Engineering',
|
authorDesignation: b.authorDesignation || 'Chief AI Architect & Head of Data Engineering',
|
||||||
editor: typeof b.editor === 'string' ? b.editor : (b.editor?.firstname ? `${b.editor.firstname} ${b.editor.lastname || ''}`.trim() : (b.editor?.username || null)),
|
editor: (typeof b.editorName === 'string' && b.editorName.trim())
|
||||||
|
? b.editorName.trim()
|
||||||
|
: (typeof b.editor === 'string' && b.editor.trim()
|
||||||
|
? b.editor.trim()
|
||||||
|
: (b.editor?.firstname ? `${b.editor.firstname} ${b.editor.lastname || ''}`.trim() : (b.editor?.username || null))),
|
||||||
editorDesignation: b.editorDesignation || null,
|
editorDesignation: b.editorDesignation || null,
|
||||||
tags: b.tags || [],
|
tags: b.tags || [],
|
||||||
metaTitle: b.metaTitle || null,
|
metaTitle: b.metaTitle || null,
|
||||||
|
|||||||
@@ -145,7 +145,11 @@ export default function BlogDetailPage({ blog, allBlogs = [], isMobile, onNaviga
|
|||||||
const bgPatternUrl = assetUrl('/assets/Background pattern About Us Hero section.svg');
|
const bgPatternUrl = assetUrl('/assets/Background pattern About Us Hero section.svg');
|
||||||
const spotlightUrl = assetUrl('/assets/Spotlight vector.svg');
|
const spotlightUrl = assetUrl('/assets/Spotlight vector.svg');
|
||||||
|
|
||||||
const authorName = typeof blog.author === 'string' ? blog.author : (blog.author?.firstname ? `${blog.author.firstname} ${blog.author.lastname || ''}`.trim() : 'Purushothaman Gopalan');
|
const authorName = (typeof blog.authorName === 'string' && blog.authorName.trim())
|
||||||
|
? blog.authorName.trim()
|
||||||
|
: (typeof blog.author === 'string' && blog.author.trim()
|
||||||
|
? blog.author.trim()
|
||||||
|
: (blog.author?.firstname ? `${blog.author.firstname} ${blog.author.lastname || ''}`.trim() : 'Cavin Editorial Team'));
|
||||||
const authorRole = typeof blog.authorDesignation === 'string' ? blog.authorDesignation : 'Chief AI Architect & Head of Data Engineering';
|
const authorRole = typeof blog.authorDesignation === 'string' ? blog.authorDesignation : 'Chief AI Architect & Head of Data Engineering';
|
||||||
const authorAvatar = '/assets/arvindh_agentic_ai.jpg';
|
const authorAvatar = '/assets/arvindh_agentic_ai.jpg';
|
||||||
const relatedArticles = allBlogs.filter(b => b.id !== blog.id).slice(0, 2);
|
const relatedArticles = allBlogs.filter(b => b.id !== blog.id).slice(0, 2);
|
||||||
@@ -344,7 +348,7 @@ export default function BlogDetailPage({ blog, allBlogs = [], isMobile, onNaviga
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* HERO FEATURED IMAGE */}
|
{/* HERO FEATURED IMAGE */}
|
||||||
{blog.image && (
|
{(blog.image || blog.coverImage || blog.ogImage) && (
|
||||||
<div style={{
|
<div style={{
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: isMobile ? '250px' : '520px',
|
height: isMobile ? '250px' : '520px',
|
||||||
@@ -356,9 +360,24 @@ export default function BlogDetailPage({ blog, allBlogs = [], isMobile, onNaviga
|
|||||||
boxShadow: '0 25px 60px rgba(0, 0, 0, 0.75)'
|
boxShadow: '0 25px 60px rgba(0, 0, 0, 0.75)'
|
||||||
}}>
|
}}>
|
||||||
<img
|
<img
|
||||||
src={assetUrl(blog.image)}
|
src={assetUrl(blog.image || blog.coverImage || blog.ogImage)}
|
||||||
alt={blog.title}
|
alt={blog.title}
|
||||||
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
|
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
|
||||||
|
onError={(e) => {
|
||||||
|
const titleLower = (blog.title || '').toLowerCase();
|
||||||
|
const catLower = (blog.category || '').toLowerCase();
|
||||||
|
let fallback = '/assets/arvindh_agentic_ai.jpg';
|
||||||
|
if (titleLower.includes('llm')) fallback = '/assets/arvindh_llm_financial.jpg';
|
||||||
|
else if (titleLower.includes('supply chain')) fallback = '/assets/arvindh_supply_chain.jpg';
|
||||||
|
else if (titleLower.includes('prodmax')) fallback = '/assets/prodmax_dashboard.png';
|
||||||
|
else if (titleLower.includes('vr') || titleLower.includes('incidents')) fallback = '/assets/whyus_vr_man.jpg';
|
||||||
|
else if (titleLower.includes('scada') || titleLower.includes('plc') || titleLower.includes('speed vs')) fallback = '/assets/arvindh_agentic_ai.jpg';
|
||||||
|
else if (catLower.includes('ai')) fallback = '/assets/arvindh_agentic_ai.jpg';
|
||||||
|
const resolvedFallback = assetUrl(fallback);
|
||||||
|
if (e.currentTarget.src !== resolvedFallback) {
|
||||||
|
e.currentTarget.src = resolvedFallback;
|
||||||
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -646,14 +665,12 @@ export default function BlogDetailPage({ blog, allBlogs = [], isMobile, onNaviga
|
|||||||
</ol>
|
</ol>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const imgMatch = block.match(/!\[(.*?)\]\((.*?)\)/);
|
const mdImgMatch = block.match(/!\[(.*?)\]\((.*?)\)/);
|
||||||
if (imgMatch) {
|
const htmlImgMatch = block.match(/<img[^>]+src=["']([^"']+)["'][^>]*>/i);
|
||||||
const caption = imgMatch[1] ? imgMatch[1].trim() : '';
|
if (mdImgMatch || htmlImgMatch) {
|
||||||
let rawImgUrl = imgMatch[2];
|
const caption = mdImgMatch ? (mdImgMatch[1] ? mdImgMatch[1].trim() : '') : '';
|
||||||
let resolvedSrc = assetUrl(rawImgUrl);
|
const rawImgUrl = mdImgMatch ? mdImgMatch[2] : htmlImgMatch[1];
|
||||||
if (rawImgUrl.startsWith('http://localhost:1337/uploads/')) {
|
const resolvedSrc = assetUrl(rawImgUrl);
|
||||||
resolvedSrc = assetUrl(rawImgUrl.replace('http://localhost:1337', ''));
|
|
||||||
}
|
|
||||||
const isFilename = caption && /\.(jpg|jpeg|png|gif|webp|svg|bmp)$/i.test(caption);
|
const isFilename = caption && /\.(jpg|jpeg|png|gif|webp|svg|bmp)$/i.test(caption);
|
||||||
const displayCaption = caption && !isFilename ? caption : null;
|
const displayCaption = caption && !isFilename ? caption : null;
|
||||||
|
|
||||||
@@ -671,9 +688,12 @@ export default function BlogDetailPage({ blog, allBlogs = [], isMobile, onNaviga
|
|||||||
boxShadow: '0 15px 35px rgba(0,0,0,0.5)'
|
boxShadow: '0 15px 35px rgba(0,0,0,0.5)'
|
||||||
}}
|
}}
|
||||||
onError={(e) => {
|
onError={(e) => {
|
||||||
if (rawImgUrl.includes('/uploads/')) {
|
if (rawImgUrl && rawImgUrl.includes('/uploads/')) {
|
||||||
const uploadPath = rawImgUrl.substring(rawImgUrl.indexOf('/uploads/'));
|
const uploadPath = rawImgUrl.substring(rawImgUrl.indexOf('/uploads/'));
|
||||||
e.currentTarget.src = `http://localhost:1337${uploadPath}`;
|
const fallback = assetUrl(uploadPath);
|
||||||
|
if (e.currentTarget.src !== fallback) {
|
||||||
|
e.currentTarget.src = fallback;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
node_modules
|
node_modules
|
||||||
dist
|
dist
|
||||||
.git
|
.git
|
||||||
.gitignore
|
|
||||||
.tmp
|
.tmp
|
||||||
.cache
|
build
|
||||||
|
public/uploads
|
||||||
*.log
|
*.log
|
||||||
Dockerfile
|
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
FROM node:20-alpine
|
FROM node:20-alpine
|
||||||
|
|
||||||
# Install native build tools for packages like better-sqlite3 / pg
|
|
||||||
RUN apk add --no-cache python3 make g++ gcc libc-dev
|
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Copy package files and install dependencies
|
# Copy package files and install dependencies
|
||||||
COPY package*.json ./
|
COPY package*.json ./
|
||||||
RUN npm install
|
RUN npm install --omit=dev --legacy-peer-deps || npm install
|
||||||
|
|
||||||
# Copy rest of Strapi CMS source code
|
# Copy rest of Strapi CMS source code
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|||||||
@@ -14,12 +14,12 @@ export default {
|
|||||||
const user = ctx?.state?.user;
|
const user = ctx?.state?.user;
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
// Auto-fill author relation if not explicitly set by user
|
|
||||||
if (!data.author) {
|
if (!data.author) {
|
||||||
data.author = user.id;
|
data.author = user.id;
|
||||||
}
|
}
|
||||||
|
if (!data.authorName) {
|
||||||
// Auto-fill author designation based on logged-in account
|
data.authorName = `${user.firstname || ''} ${user.lastname || ''}`.trim() || user.username || user.email;
|
||||||
|
}
|
||||||
if (!data.authorDesignation && user.email) {
|
if (!data.authorDesignation && user.email) {
|
||||||
data.authorDesignation = designationMap[user.email] || `${user.firstname || ''} ${user.lastname || ''}`.trim();
|
data.authorDesignation = designationMap[user.email] || `${user.firstname || ''} ${user.lastname || ''}`.trim();
|
||||||
}
|
}
|
||||||
@@ -32,22 +32,24 @@ export default {
|
|||||||
const user = ctx?.state?.user;
|
const user = ctx?.state?.user;
|
||||||
|
|
||||||
if (user && data) {
|
if (user && data) {
|
||||||
// Auto-fill author relation if empty
|
|
||||||
if (!data.author) {
|
if (!data.author) {
|
||||||
data.author = user.id;
|
data.author = user.id;
|
||||||
}
|
}
|
||||||
|
if (!data.authorName && user) {
|
||||||
// Auto-fill author designation if empty
|
data.authorName = `${user.firstname || ''} ${user.lastname || ''}`.trim() || user.username || user.email;
|
||||||
|
}
|
||||||
if (!data.authorDesignation && user.email) {
|
if (!data.authorDesignation && user.email) {
|
||||||
data.authorDesignation = designationMap[user.email] || `${user.firstname || ''} ${user.lastname || ''}`.trim();
|
data.authorDesignation = designationMap[user.email] || `${user.firstname || ''} ${user.lastname || ''}`.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Auto-fill editor details if an Editor/Admin edits or approves
|
|
||||||
const isEditor = user.roles?.some((r: any) => r.code === 'strapi-editor' || r.code === 'strapi-super-admin');
|
const isEditor = user.roles?.some((r: any) => r.code === 'strapi-editor' || r.code === 'strapi-super-admin');
|
||||||
if (isEditor) {
|
if (isEditor) {
|
||||||
if (!data.editor) {
|
if (!data.editor) {
|
||||||
data.editor = user.id;
|
data.editor = user.id;
|
||||||
}
|
}
|
||||||
|
if (!data.editorName && user) {
|
||||||
|
data.editorName = `${user.firstname || ''} ${user.lastname || ''}`.trim() || user.username;
|
||||||
|
}
|
||||||
if (!data.editorDesignation && user.email) {
|
if (!data.editorDesignation && user.email) {
|
||||||
data.editorDesignation = designationMap[user.email] || 'Senior Editor';
|
data.editorDesignation = designationMap[user.email] || 'Senior Editor';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,9 @@
|
|||||||
"default": "Draft",
|
"default": "Draft",
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
|
"authorName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"author": {
|
"author": {
|
||||||
"type": "relation",
|
"type": "relation",
|
||||||
"relation": "oneToOne",
|
"relation": "oneToOne",
|
||||||
@@ -68,6 +71,9 @@
|
|||||||
"authorDesignation": {
|
"authorDesignation": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"editorName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"editor": {
|
"editor": {
|
||||||
"type": "relation",
|
"type": "relation",
|
||||||
"relation": "oneToOne",
|
"relation": "oneToOne",
|
||||||
|
|||||||
@@ -1,3 +1,92 @@
|
|||||||
import { factories } from '@strapi/strapi';
|
import { factories } from '@strapi/strapi';
|
||||||
|
|
||||||
export default factories.createCoreController('api::blog.blog');
|
export default factories.createCoreController('api::blog.blog', ({ strapi }) => ({
|
||||||
|
async find(ctx) {
|
||||||
|
const response = await super.find(ctx);
|
||||||
|
if (!response || !response.data) return response;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Query admin users to build user lookup map
|
||||||
|
const adminUsers = await strapi.db.query('admin::user').findMany();
|
||||||
|
const userMap = new Map<number, string>();
|
||||||
|
const userDesigMap = new Map<number, string>();
|
||||||
|
|
||||||
|
adminUsers.forEach((u: any) => {
|
||||||
|
const fullName = `${u.firstname || ''} ${u.lastname || ''}`.trim() || u.username || u.email;
|
||||||
|
userMap.set(u.id, fullName);
|
||||||
|
});
|
||||||
|
|
||||||
|
const blogIds = response.data.map((b: any) => b.id);
|
||||||
|
if (blogIds.length > 0) {
|
||||||
|
const rawBlogs = await strapi.db.query('api::blog.blog').findMany({
|
||||||
|
where: { id: { $in: blogIds } },
|
||||||
|
populate: ['author', 'createdBy']
|
||||||
|
});
|
||||||
|
|
||||||
|
const authorMap = new Map<number, string>();
|
||||||
|
rawBlogs.forEach((rb: any) => {
|
||||||
|
let name = rb.authorName;
|
||||||
|
if (!name && rb.author) {
|
||||||
|
name = userMap.get(rb.author.id) || `${rb.author.firstname || ''} ${rb.author.lastname || ''}`.trim();
|
||||||
|
}
|
||||||
|
if (!name && rb.createdBy) {
|
||||||
|
name = userMap.get(rb.createdBy.id) || `${rb.createdBy.firstname || ''} ${rb.createdBy.lastname || ''}`.trim();
|
||||||
|
}
|
||||||
|
if (name) authorMap.set(rb.id, name);
|
||||||
|
});
|
||||||
|
|
||||||
|
response.data = response.data.map((b: any) => {
|
||||||
|
const mappedAuthor = authorMap.get(b.id) || b.authorName || b.author || null;
|
||||||
|
return {
|
||||||
|
...b,
|
||||||
|
author: mappedAuthor,
|
||||||
|
authorName: mappedAuthor
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('Note: Strapi blog controller find notice:', err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
},
|
||||||
|
|
||||||
|
async findOne(ctx) {
|
||||||
|
const response = await super.findOne(ctx);
|
||||||
|
if (!response || !response.data) return response;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const b = response.data;
|
||||||
|
const adminUsers = await strapi.db.query('admin::user').findMany();
|
||||||
|
const userMap = new Map<number, string>();
|
||||||
|
adminUsers.forEach((u: any) => {
|
||||||
|
const fullName = `${u.firstname || ''} ${u.lastname || ''}`.trim() || u.username || u.email;
|
||||||
|
userMap.set(u.id, fullName);
|
||||||
|
});
|
||||||
|
|
||||||
|
const rawBlog = await strapi.db.query('api::blog.blog').findOne({
|
||||||
|
where: { id: b.id },
|
||||||
|
populate: ['author', 'createdBy']
|
||||||
|
});
|
||||||
|
|
||||||
|
let name = rawBlog?.authorName;
|
||||||
|
if (!name && rawBlog?.author) {
|
||||||
|
name = userMap.get(rawBlog.author.id) || `${rawBlog.author.firstname || ''} ${rawBlog.author.lastname || ''}`.trim();
|
||||||
|
}
|
||||||
|
if (!name && rawBlog?.createdBy) {
|
||||||
|
name = userMap.get(rawBlog.createdBy.id) || `${rawBlog.createdBy.firstname || ''} ${rawBlog.createdBy.lastname || ''}`.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
const mappedAuthor = name || b.authorName || b.author || null;
|
||||||
|
response.data = {
|
||||||
|
...b,
|
||||||
|
author: mappedAuthor,
|
||||||
|
authorName: mappedAuthor
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('Note: Strapi blog controller findOne notice:', err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|||||||
Reference in New Issue
Block a user