diff --git a/apps/backend/config/database.ts b/apps/backend/config/database.ts index a162e94..e838feb 100644 --- a/apps/backend/config/database.ts +++ b/apps/backend/config/database.ts @@ -8,9 +8,7 @@ export default ({env}) => ({ user: env('DATABASE_USERNAME', 'postgres'), password: env('DATABASE_PASSWORD', '0000'), schema: env('DATABASE_SCHEMA', 'public'), // Not required - ssl: { - rejectUnauthorized: env.bool('DATABASE_SSL_SELF', false), - }, + ssl: false, }, debug: false, }, diff --git a/apps/backend/package-lock.json b/apps/backend/package-lock.json index 8cd8e45..c7ed4ef 100644 --- a/apps/backend/package-lock.json +++ b/apps/backend/package-lock.json @@ -14,7 +14,9 @@ "@strapi/strapi": "4.5.4", "@strapi/utils": "^4.5.6", "better-sqlite3": "7.4.6", - "strapi-plugin-menus": "^1.2.1" + "pg": "^8.8.0", + "strapi-plugin-menus": "^1.2.1", + "strapi-plugin-populate-deep": "^1.1.2" }, "engines": { "node": ">=14.19.1 <=18.x.x", @@ -5926,6 +5928,14 @@ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, + "node_modules/buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==", + "engines": { + "node": ">=4" + } + }, "node_modules/buffer-xor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", @@ -12328,6 +12338,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, "node_modules/pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", @@ -12616,11 +12631,80 @@ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" }, + "node_modules/pg": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.8.0.tgz", + "integrity": "sha512-UXYN0ziKj+AeNNP7VDMwrehpACThH7LUl/p8TDFpEUuSejCUIwGSfxpHsPvtM6/WXFy6SU4E5RG4IJV/TZAGjw==", + "dependencies": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.5.0", + "pg-pool": "^3.5.2", + "pg-protocol": "^1.5.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, "node_modules/pg-connection-string": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.5.2.tgz", + "integrity": "sha512-His3Fh17Z4eg7oANLob6ZvH8xIVen3phEZh2QuyrIl4dQSDVEabNducv6ysROKpDNPSD+12tONZVWfSgMvDD9w==", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz", + "integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "dependencies": { + "split2": "^4.1.0" + } + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -13081,6 +13165,41 @@ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/prebuild-install": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", @@ -15110,6 +15229,14 @@ "node": ">=0.10.0" } }, + "node_modules/split2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz", + "integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==", + "engines": { + "node": ">= 10.x" + } + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -15362,6 +15489,15 @@ "react": ">=16.8" } }, + "node_modules/strapi-plugin-populate-deep": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/strapi-plugin-populate-deep/-/strapi-plugin-populate-deep-1.1.2.tgz", + "integrity": "sha512-fKw1BMRpdWbi1D+E0Yq08lZFxrTHgdPQ2P5jKEuXEE5YHvHiepSHVQtymDJGQ3WRWierem8ZBpnz2nl6iRx8Gw==", + "engines": { + "node": ">=12.x.x <=16.x.x", + "npm": ">=6.0.0" + } + }, "node_modules/stream-browserify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", diff --git a/apps/backend/package.json b/apps/backend/package.json index 6b151d6..748e862 100644 --- a/apps/backend/package.json +++ b/apps/backend/package.json @@ -18,7 +18,9 @@ "@strapi/strapi": "4.5.4", "@strapi/utils": "^4.5.6", "better-sqlite3": "7.4.6", - "strapi-plugin-menus": "^1.2.1" + "pg": "^8.8.0", + "strapi-plugin-menus": "^1.2.1", + "strapi-plugin-populate-deep": "^1.1.2" }, "author": { "name": "A Strapi developer" diff --git a/apps/backend/src/api/page/content-types/page/schema.json b/apps/backend/src/api/page/content-types/page/schema.json new file mode 100644 index 0000000..5100f7e --- /dev/null +++ b/apps/backend/src/api/page/content-types/page/schema.json @@ -0,0 +1,28 @@ +{ + "kind": "collectionType", + "collectionName": "pages", + "info": { + "singularName": "page", + "pluralName": "pages", + "displayName": "Pages", + "description": "" + }, + "options": { + "draftAndPublish": true + }, + "pluginOptions": {}, + "attributes": { + "label": { + "type": "string" + }, + "slug": { + "type": "uid", + "targetField": "label" + }, + "seo": { + "type": "component", + "repeatable": false, + "component": "shared.seo" + } + } +} diff --git a/apps/backend/src/api/page/controllers/page.ts b/apps/backend/src/api/page/controllers/page.ts new file mode 100644 index 0000000..f513618 --- /dev/null +++ b/apps/backend/src/api/page/controllers/page.ts @@ -0,0 +1,7 @@ +/** + * page controller + */ + +import { factories } from '@strapi/strapi' + +export default factories.createCoreController('api::page.page'); diff --git a/apps/backend/src/api/page/routes/page.ts b/apps/backend/src/api/page/routes/page.ts new file mode 100644 index 0000000..8e5ddfc --- /dev/null +++ b/apps/backend/src/api/page/routes/page.ts @@ -0,0 +1,7 @@ +/** + * page router + */ + +import { factories } from '@strapi/strapi'; + +export default factories.createCoreRouter('api::page.page'); diff --git a/apps/backend/src/api/page/services/page.ts b/apps/backend/src/api/page/services/page.ts new file mode 100644 index 0000000..eaf07ff --- /dev/null +++ b/apps/backend/src/api/page/services/page.ts @@ -0,0 +1,7 @@ +/** + * page service + */ + +import { factories } from '@strapi/strapi'; + +export default factories.createCoreService('api::page.page'); diff --git a/apps/backend/src/components/meta/meta.json b/apps/backend/src/components/meta/meta.json new file mode 100644 index 0000000..cb9ba70 --- /dev/null +++ b/apps/backend/src/components/meta/meta.json @@ -0,0 +1,16 @@ +{ + "collectionName": "components_meta_metas", + "info": { + "displayName": "meta", + "icon": "network-wired" + }, + "options": {}, + "attributes": { + "property": { + "type": "string" + }, + "content": { + "type": "string" + } + } +} diff --git a/apps/backend/src/components/shared/seo.json b/apps/backend/src/components/shared/seo.json new file mode 100644 index 0000000..c9f433e --- /dev/null +++ b/apps/backend/src/components/shared/seo.json @@ -0,0 +1,36 @@ +{ + "collectionName": "components_shared_seos", + "info": { + "displayName": "Seo", + "icon": "book", + "description": "" + }, + "options": {}, + "attributes": { + "metaTitle": { + "type": "string" + }, + "metaDescription": { + "type": "string" + }, + "SharedImage": { + "displayName": "SharedImage", + "type": "component", + "repeatable": false, + "component": "shared.shared-image" + }, + "Meta": { + "displayName": "meta", + "type": "component", + "repeatable": true, + "component": "meta.meta" + }, + "preventIndexing": { + "type": "boolean", + "default": false + }, + "structuredData": { + "type": "json" + } + } +} diff --git a/apps/backend/src/components/shared/shared-image.json b/apps/backend/src/components/shared/shared-image.json new file mode 100644 index 0000000..4424287 --- /dev/null +++ b/apps/backend/src/components/shared/shared-image.json @@ -0,0 +1,24 @@ +{ + "collectionName": "components_shared_shared_images", + "info": { + "displayName": "SharedImage", + "icon": "file-image", + "description": "" + }, + "options": {}, + "attributes": { + "alt": { + "type": "string" + }, + "media": { + "allowedTypes": [ + "images", + "files", + "videos", + "audios" + ], + "type": "media", + "multiple": false + } + } +} diff --git a/apps/client/.env b/apps/client/.env new file mode 100644 index 0000000..172e20c --- /dev/null +++ b/apps/client/.env @@ -0,0 +1 @@ +STRAPI_URL=http://127.0.0.1:1337/api diff --git a/apps/client/components/carousel/carousel.module.scss b/apps/client/components/carousel/carousel.module.scss new file mode 100644 index 0000000..45c2aa4 --- /dev/null +++ b/apps/client/components/carousel/carousel.module.scss @@ -0,0 +1,7 @@ +/* + * Replace this with your own classes + * + * e.g. + * .container { + * } +*/ diff --git a/apps/client/components/carousel/carousel.spec.tsx b/apps/client/components/carousel/carousel.spec.tsx new file mode 100644 index 0000000..4201b81 --- /dev/null +++ b/apps/client/components/carousel/carousel.spec.tsx @@ -0,0 +1,10 @@ +import { render } from '@testing-library/react'; + +import Carousel from './carousel'; + +describe('Carousel', () => { + it('should render successfully', () => { + const { baseElement } = render(); + expect(baseElement).toBeTruthy(); + }); +}); diff --git a/apps/client/components/carousel/carousel.tsx b/apps/client/components/carousel/carousel.tsx new file mode 100644 index 0000000..42fe9e1 --- /dev/null +++ b/apps/client/components/carousel/carousel.tsx @@ -0,0 +1,14 @@ +import styles from './carousel.module.scss'; + +/* eslint-disable-next-line */ +export interface CarouselProps {} + +export function Carousel(props: CarouselProps) { + return ( +
+

Welcome to Carousel!

+
+ ); +} + +export default Carousel; diff --git a/apps/client/components/footer/footer.module.scss b/apps/client/components/footer/footer.module.scss new file mode 100644 index 0000000..45c2aa4 --- /dev/null +++ b/apps/client/components/footer/footer.module.scss @@ -0,0 +1,7 @@ +/* + * Replace this with your own classes + * + * e.g. + * .container { + * } +*/ diff --git a/apps/client/components/footer/footer.spec.tsx b/apps/client/components/footer/footer.spec.tsx new file mode 100644 index 0000000..97c820b --- /dev/null +++ b/apps/client/components/footer/footer.spec.tsx @@ -0,0 +1,10 @@ +import { render } from '@testing-library/react'; + +import Footer from './footer'; + +describe('Footer', () => { + it('should render successfully', () => { + const { baseElement } = render(