Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ddac6197e3 |
@@ -0,0 +1,2 @@
|
||||
web: bin/buildpack_start.sh
|
||||
postdeploy: python manage.py migrate
|
||||
@@ -57,7 +57,7 @@ Available methods: Helm chart, Nix package
|
||||
|
||||
In the works: Docker Compose, YunoHost
|
||||
|
||||
⚠️ For some advanced features (ex: Export as PDF) Docs relies on XL packages from BlockNote. These are licenced under AGPL-3.0 and are not MIT compatible. You can perfectly use Docs without these packages by setting the environment variable `PUBLISH_AS_MIT` to true. That way you'll build an image of the application without the features that are not MIT compatible. Read the [environment variables documentation](/docs/env.md) for more information.
|
||||
⚠️ For some advanced features (ex: Export as PDF) Docs relies on XL packages from BlockNote. These are licenced under AGPL-3.0 and are not MIT compatible. You can perfectly use Docs without these packages by setting the environment variable `PUBLISH_AS_MIT` to true. That way you'll build an image of the application without the features that are not MIT compatible. Read the [environment variables documentation](/docs/docs/env.md) for more information.
|
||||
|
||||
## Getting started 🔧
|
||||
|
||||
|
||||
Executable
+15
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -o errexit # always exit on error
|
||||
set -o pipefail # don't ignore exit codes when piping output
|
||||
|
||||
echo "-----> Running post-compile script"
|
||||
|
||||
rm -rf docker docs env.d gitlint src/frontend/apps/e2e
|
||||
rm -rf src/frontend/apps
|
||||
rm -rf src/frontend/packages
|
||||
|
||||
# Remove some of the larger packages required by the frontend only
|
||||
rm -rf src/frontend/node_modules/@next src/frontend/node_modules/next src/frontend/node_modules/react-icons src/frontend/node_modules/@gouvfr-lasuite
|
||||
|
||||
# du -ch | sort -rh | head -n 100
|
||||
Executable
+15
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -o errexit # always exit on error
|
||||
set -o pipefail # don't ignore exit codes when piping output
|
||||
|
||||
echo "-----> Running post-frontend script"
|
||||
|
||||
# Move the frontend build to the nginx root and clean up
|
||||
mkdir -p build/
|
||||
mv src/frontend/apps/impress/out build/frontend-out
|
||||
|
||||
mv src/backend/* ./
|
||||
mv src/nginx/* ./
|
||||
|
||||
echo "3.13" > .python-version
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Start the Django backend server
|
||||
gunicorn -b :8000 impress.wsgi:application --log-file - &
|
||||
|
||||
# Start the Y provider service
|
||||
cd src/frontend/servers/y-provider && PORT=4444 ../../.scalingo/node/bin/node dist/start-server.js &
|
||||
|
||||
# Start the Nginx server
|
||||
bin/run &
|
||||
|
||||
# if the current shell is killed, also terminate all its children
|
||||
trap "pkill SIGTERM -P $$" SIGTERM
|
||||
|
||||
# wait for a single child to finish,
|
||||
wait -n
|
||||
# then kill all the other tasks
|
||||
pkill -P $$
|
||||
@@ -16,6 +16,7 @@ from socket import gethostbyname, gethostname
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
import dj_database_url
|
||||
import sentry_sdk
|
||||
from configurations import Configuration, values
|
||||
from sentry_sdk.integrations.django import DjangoIntegration
|
||||
@@ -74,7 +75,9 @@ class Base(Configuration):
|
||||
|
||||
# Database
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"default": dj_database_url.config()
|
||||
if os.environ.get("DATABASE_URL")
|
||||
else {
|
||||
"ENGINE": values.Value(
|
||||
"django.db.backends.postgresql_psycopg2",
|
||||
environ_name="DB_ENGINE",
|
||||
|
||||
+13
-12
@@ -26,9 +26,10 @@ readme = "README.md"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = [
|
||||
"beautifulsoup4==4.13.4",
|
||||
"boto3==1.38.27",
|
||||
"boto3==1.38.18",
|
||||
"Brotli==1.1.0",
|
||||
"celery[redis]==5.5.3",
|
||||
"celery[redis]==5.5.2",
|
||||
"dj-database-url==2.3.0",
|
||||
"django-configurations==2.5.1",
|
||||
"django-cors-headers==4.7.0",
|
||||
"django-countries==7.6.1",
|
||||
@@ -46,19 +47,19 @@ dependencies = [
|
||||
"easy_thumbnails==2.10",
|
||||
"factory_boy==3.3.3",
|
||||
"gunicorn==23.0.0",
|
||||
"jsonschema==4.24.0",
|
||||
"jsonschema==4.23.0",
|
||||
"lxml==5.4.0",
|
||||
"markdown==3.8",
|
||||
"mozilla-django-oidc==4.0.1",
|
||||
"nested-multipart-parser==1.5.0",
|
||||
"openai==1.82.1",
|
||||
"openai==1.79.0",
|
||||
"psycopg[binary]==3.2.9",
|
||||
"pycrdt==0.12.20",
|
||||
"pycrdt==0.12.19",
|
||||
"PyJWT==2.10.1",
|
||||
"python-magic==0.4.27",
|
||||
"redis<6.0.0",
|
||||
"requests==2.32.3",
|
||||
"sentry-sdk==2.29.1",
|
||||
"sentry-sdk==2.28.0",
|
||||
"whitenoise==6.9.0",
|
||||
]
|
||||
|
||||
@@ -72,10 +73,10 @@ dependencies = [
|
||||
dev = [
|
||||
"django-extensions==4.1",
|
||||
"django-test-migrations==1.5.0",
|
||||
"drf-spectacular-sidecar==2025.6.1",
|
||||
"freezegun==1.5.2",
|
||||
"drf-spectacular-sidecar==2025.5.1",
|
||||
"freezegun==1.5.1",
|
||||
"ipdb==0.13.13",
|
||||
"ipython==9.3.0",
|
||||
"ipython==9.2.0",
|
||||
"pyfakefs==5.8.0",
|
||||
"pylint-django==2.6.1",
|
||||
"pylint==3.3.7",
|
||||
@@ -83,10 +84,10 @@ dev = [
|
||||
"pytest-django==4.11.1",
|
||||
"pytest==8.3.5",
|
||||
"pytest-icdiff==0.9",
|
||||
"pytest-xdist==3.7.0",
|
||||
"pytest-xdist==3.6.1",
|
||||
"responses==0.25.7",
|
||||
"ruff==0.11.12",
|
||||
"types-requests==2.32.0.20250602",
|
||||
"ruff==0.11.10",
|
||||
"types-requests==2.32.0.20250515",
|
||||
]
|
||||
|
||||
[tool.setuptools]
|
||||
|
||||
@@ -16,56 +16,56 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@ag-media/react-pdf-table": "2.0.3",
|
||||
"@blocknote/code-block": "0.31.1",
|
||||
"@blocknote/core": "0.31.1",
|
||||
"@blocknote/mantine": "0.31.1",
|
||||
"@blocknote/react": "0.31.1",
|
||||
"@blocknote/xl-docx-exporter": "0.31.1",
|
||||
"@blocknote/xl-pdf-exporter": "0.31.1",
|
||||
"@blocknote/code-block": "0.30.1",
|
||||
"@blocknote/core": "0.30.1",
|
||||
"@blocknote/mantine": "0.30.1",
|
||||
"@blocknote/react": "0.30.1",
|
||||
"@blocknote/xl-docx-exporter": "0.30.1",
|
||||
"@blocknote/xl-pdf-exporter": "0.30.1",
|
||||
"@emoji-mart/data": "1.2.1",
|
||||
"@emoji-mart/react": "1.1.1",
|
||||
"@fontsource/material-icons": "5.2.5",
|
||||
"@gouvfr-lasuite/integration": "1.0.3",
|
||||
"@gouvfr-lasuite/ui-kit": "0.7.0",
|
||||
"@gouvfr-lasuite/ui-kit": "0.6.0",
|
||||
"@hocuspocus/provider": "2.15.2",
|
||||
"@openfun/cunningham-react": "3.1.0",
|
||||
"@react-pdf/renderer": "4.3.0",
|
||||
"@sentry/nextjs": "9.22.0",
|
||||
"@tanstack/react-query": "5.77.1",
|
||||
"@sentry/nextjs": "9.19.0",
|
||||
"@tanstack/react-query": "5.76.1",
|
||||
"canvg": "4.0.3",
|
||||
"clsx": "2.1.1",
|
||||
"cmdk": "1.1.1",
|
||||
"crisp-sdk-web": "1.0.25",
|
||||
"docx": "9.5.0",
|
||||
"emoji-mart": "5.6.0",
|
||||
"i18next": "25.2.1",
|
||||
"i18next": "25.1.3",
|
||||
"i18next-browser-languagedetector": "8.1.0",
|
||||
"idb": "8.0.3",
|
||||
"lodash": "4.17.21",
|
||||
"luxon": "3.6.1",
|
||||
"next": "15.3.2",
|
||||
"posthog-js": "1.246.0",
|
||||
"posthog-js": "1.242.2",
|
||||
"react": "*",
|
||||
"react-aria-components": "1.9.0",
|
||||
"react-aria-components": "1.8.0",
|
||||
"react-dom": "*",
|
||||
"react-i18next": "15.5.2",
|
||||
"react-i18next": "15.5.1",
|
||||
"react-intersection-observer": "9.16.0",
|
||||
"react-select": "5.10.1",
|
||||
"styled-components": "6.1.18",
|
||||
"use-debounce": "10.0.4",
|
||||
"y-protocols": "1.0.6",
|
||||
"yjs": "*",
|
||||
"zustand": "5.0.5"
|
||||
"zustand": "5.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@svgr/webpack": "8.1.0",
|
||||
"@tanstack/react-query-devtools": "5.77.1",
|
||||
"@tanstack/react-query-devtools": "5.76.1",
|
||||
"@testing-library/dom": "10.4.0",
|
||||
"@testing-library/jest-dom": "6.6.3",
|
||||
"@testing-library/react": "16.3.0",
|
||||
"@testing-library/user-event": "14.6.1",
|
||||
"@types/jest": "29.5.14",
|
||||
"@types/lodash": "4.17.17",
|
||||
"@types/lodash": "4.17.16",
|
||||
"@types/luxon": "3.6.2",
|
||||
"@types/node": "*",
|
||||
"@types/react": "*",
|
||||
@@ -82,7 +82,7 @@
|
||||
"stylelint-config-standard": "38.0.0",
|
||||
"stylelint-prettier": "5.0.3",
|
||||
"typescript": "*",
|
||||
"webpack": "5.99.9",
|
||||
"webpack": "5.99.8",
|
||||
"workbox-webpack-plugin": "7.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
"app:build": "yarn APP_IMPRESS run build",
|
||||
"app:test": "yarn APP_IMPRESS run test",
|
||||
"ci:build": "yarn APP_IMPRESS run build:ci",
|
||||
"build": "yarn APP_IMPRESS run build && yarn COLLABORATION_SERVER run build",
|
||||
"e2e:test": "yarn APP_E2E run test",
|
||||
"lint": "yarn APP_IMPRESS run lint && yarn APP_E2E run lint && yarn workspace eslint-config-impress run lint && yarn I18N run lint && yarn COLLABORATION_SERVER run lint",
|
||||
"i18n:extract": "yarn I18N run extract-translation",
|
||||
@@ -28,8 +29,8 @@
|
||||
"server:test": "yarn COLLABORATION_SERVER run test"
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/node": "22.15.21",
|
||||
"@types/react": "19.1.5",
|
||||
"@types/node": "22.15.19",
|
||||
"@types/react": "19.1.4",
|
||||
"@types/react-dom": "19.1.5",
|
||||
"@typescript-eslint/eslint-plugin": "8.32.1",
|
||||
"@typescript-eslint/parser": "8.32.1",
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
"node": ">=18"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blocknote/server-util": "0.31.1",
|
||||
"@blocknote/server-util": "0.30.1",
|
||||
"@hocuspocus/server": "2.15.2",
|
||||
"@sentry/node": "9.22.0",
|
||||
"@sentry/profiling-node": "9.22.0",
|
||||
"@sentry/node": "9.19.0",
|
||||
"@sentry/profiling-node": "9.19.0",
|
||||
"axios": "1.9.0",
|
||||
"cors": "2.8.5",
|
||||
"express": "5.1.0",
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
import {
|
||||
BlockNoteSchema,
|
||||
PartialBlock,
|
||||
defaultBlockSpecs,
|
||||
} from '@blocknote/core';
|
||||
import { ServerBlockNoteEditor } from '@blocknote/server-util';
|
||||
import { Request, Response } from 'express';
|
||||
import * as Y from 'yjs';
|
||||
|
||||
import { logger, toBase64 } from '@/utils';
|
||||
|
||||
import { CalloutBlock, DividerBlock } from './custom-blocks';
|
||||
|
||||
const blockNoteSchema = BlockNoteSchema.create({
|
||||
blockSpecs: {
|
||||
...defaultBlockSpecs,
|
||||
callout: CalloutBlock,
|
||||
divider: DividerBlock,
|
||||
},
|
||||
});
|
||||
|
||||
type DocsBlockSchema = typeof blockNoteSchema.blockSchema;
|
||||
type DocsInlineContentSchema = typeof blockNoteSchema.inlineContentSchema;
|
||||
type DocsStyleSchema = typeof blockNoteSchema.styleSchema;
|
||||
|
||||
interface ConversionRequest {
|
||||
blocks: PartialBlock<DocsBlockSchema>[];
|
||||
}
|
||||
|
||||
interface ConversionResponse {
|
||||
content: string;
|
||||
}
|
||||
|
||||
interface ErrorResponse {
|
||||
error: string;
|
||||
}
|
||||
|
||||
export const convertBlocksHandler = (
|
||||
req: Request<
|
||||
object,
|
||||
ConversionResponse | ErrorResponse,
|
||||
ConversionRequest,
|
||||
object
|
||||
>,
|
||||
res: Response<ConversionResponse | ErrorResponse>,
|
||||
) => {
|
||||
const blocks = req.body?.blocks;
|
||||
if (!blocks) {
|
||||
res.status(400).json({ error: 'Invalid request: missing content' });
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Create a server editor with custom block schema
|
||||
const editor = ServerBlockNoteEditor.create<
|
||||
DocsBlockSchema,
|
||||
DocsInlineContentSchema,
|
||||
DocsStyleSchema
|
||||
>({
|
||||
schema: blockNoteSchema,
|
||||
});
|
||||
|
||||
// Create a Yjs Document from blocks, and encode it as a base64 string
|
||||
const yDocument = editor.blocksToYDoc(blocks, 'document-store');
|
||||
const content = toBase64(Y.encodeStateAsUpdate(yDocument));
|
||||
|
||||
res.status(200).json({ content });
|
||||
} catch (e) {
|
||||
logger('conversion failed:', e);
|
||||
res.status(500).json({ error: String(e) });
|
||||
}
|
||||
};
|
||||
@@ -1,166 +0,0 @@
|
||||
/* eslint-disable react-hooks/rules-of-hooks */
|
||||
import { defaultProps, insertOrUpdateBlock } from '@blocknote/core';
|
||||
import { BlockTypeSelectItem, createReactBlockSpec } from '@blocknote/react';
|
||||
import { TFunction } from 'i18next';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { css } from 'styled-components';
|
||||
|
||||
import { Box, BoxButton, Icon } from '@/components';
|
||||
|
||||
import { DocsBlockNoteEditor } from '../../types';
|
||||
import { EmojiPicker } from '../EmojiPicker';
|
||||
|
||||
const calloutCustom = [
|
||||
{
|
||||
name: 'Callout',
|
||||
id: 'callout',
|
||||
emojis: [
|
||||
'bulb',
|
||||
'point_right',
|
||||
'point_up',
|
||||
'ok_hand',
|
||||
'key',
|
||||
'construction',
|
||||
'warning',
|
||||
'fire',
|
||||
'pushpin',
|
||||
'scissors',
|
||||
'question',
|
||||
'no_entry',
|
||||
'no_entry_sign',
|
||||
'alarm_clock',
|
||||
'phone',
|
||||
'rotating_light',
|
||||
'recycle',
|
||||
'white_check_mark',
|
||||
'lock',
|
||||
'paperclip',
|
||||
'book',
|
||||
'speaking_head_in_silhouette',
|
||||
'arrow_right',
|
||||
'loudspeaker',
|
||||
'hammer_and_wrench',
|
||||
'gear',
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const calloutCategories = [
|
||||
'callout',
|
||||
'people',
|
||||
'nature',
|
||||
'foods',
|
||||
'activity',
|
||||
'places',
|
||||
'flags',
|
||||
'objects',
|
||||
'symbols',
|
||||
];
|
||||
|
||||
export const CalloutBlock = createReactBlockSpec(
|
||||
{
|
||||
type: 'callout',
|
||||
propSchema: {
|
||||
textAlignment: defaultProps.textAlignment,
|
||||
backgroundColor: defaultProps.backgroundColor,
|
||||
emoji: { default: '💡' },
|
||||
},
|
||||
content: 'inline',
|
||||
},
|
||||
{
|
||||
render: ({ block, editor, contentRef }) => {
|
||||
const [openEmojiPicker, setOpenEmojiPicker] = useState(false);
|
||||
|
||||
const toggleEmojiPicker = (e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setOpenEmojiPicker(!openEmojiPicker);
|
||||
};
|
||||
|
||||
const onClickOutside = () => setOpenEmojiPicker(false);
|
||||
|
||||
const onEmojiSelect = ({ native }: { native: string }) => {
|
||||
editor.updateBlock(block, { props: { emoji: native } });
|
||||
setOpenEmojiPicker(false);
|
||||
};
|
||||
|
||||
// Temporary: sets a yellow background color to a callout block when added by
|
||||
// the user, while keeping the colors menu on the drag handler usable for
|
||||
// this custom block.
|
||||
useEffect(() => {
|
||||
if (
|
||||
!block.content.length &&
|
||||
block.props.backgroundColor === 'default'
|
||||
) {
|
||||
editor.updateBlock(block, { props: { backgroundColor: 'yellow' } });
|
||||
}
|
||||
}, [block, editor]);
|
||||
|
||||
return (
|
||||
<Box
|
||||
$padding="1rem"
|
||||
$gap="0.625rem"
|
||||
style={{
|
||||
flexGrow: 1,
|
||||
flexDirection: 'row',
|
||||
}}
|
||||
>
|
||||
<BoxButton
|
||||
contentEditable={false}
|
||||
onClick={toggleEmojiPicker}
|
||||
$css={css`
|
||||
font-size: 1.125rem;
|
||||
&:hover {
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
`}
|
||||
$align="center"
|
||||
$height="28px"
|
||||
$width="28px"
|
||||
$radius="4px"
|
||||
>
|
||||
{block.props.emoji}
|
||||
</BoxButton>
|
||||
|
||||
{openEmojiPicker && (
|
||||
<EmojiPicker
|
||||
categories={calloutCategories}
|
||||
custom={calloutCustom}
|
||||
onClickOutside={onClickOutside}
|
||||
onEmojiSelect={onEmojiSelect}
|
||||
/>
|
||||
)}
|
||||
<Box as="p" className="inline-content" ref={contentRef} />
|
||||
</Box>
|
||||
);
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
export const getCalloutReactSlashMenuItems = (
|
||||
editor: DocsBlockNoteEditor,
|
||||
t: TFunction<'translation', undefined>,
|
||||
group: string,
|
||||
) => [
|
||||
{
|
||||
title: t('Callout'),
|
||||
onItemClick: () => {
|
||||
insertOrUpdateBlock(editor, {
|
||||
type: 'callout',
|
||||
});
|
||||
},
|
||||
aliases: ['callout', 'encadré', 'hervorhebung', 'benadrukken'],
|
||||
group,
|
||||
icon: <Icon iconName="lightbulb" $size="18px" />,
|
||||
subtext: t('Add a callout block'),
|
||||
},
|
||||
];
|
||||
|
||||
export const getCalloutFormattingToolbarItems = (
|
||||
t: TFunction<'translation', undefined>,
|
||||
): BlockTypeSelectItem => ({
|
||||
name: t('Callout'),
|
||||
type: 'callout',
|
||||
icon: () => <Icon iconName="lightbulb" $size="16px" />,
|
||||
isSelected: (block) => block.type === 'callout',
|
||||
});
|
||||
@@ -1,51 +0,0 @@
|
||||
import { insertOrUpdateBlock } from '@blocknote/core';
|
||||
import { createReactBlockSpec } from '@blocknote/react';
|
||||
import { TFunction } from 'i18next';
|
||||
|
||||
import { Box, Icon } from '@/components';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
|
||||
import { DocsBlockNoteEditor } from '../../types';
|
||||
|
||||
export const DividerBlock = createReactBlockSpec(
|
||||
{
|
||||
type: 'divider',
|
||||
propSchema: {},
|
||||
content: 'none',
|
||||
},
|
||||
{
|
||||
render: () => {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
const { colorsTokens } = useCunninghamTheme();
|
||||
|
||||
return (
|
||||
<Box
|
||||
as="hr"
|
||||
$width="100%"
|
||||
$background={colorsTokens['greyscale-300']}
|
||||
$margin="1rem 0"
|
||||
$css={`border: 1px solid ${colorsTokens['greyscale-300']};`}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
export const getDividerReactSlashMenuItems = (
|
||||
editor: DocsBlockNoteEditor,
|
||||
t: TFunction<'translation', undefined>,
|
||||
group: string,
|
||||
) => [
|
||||
{
|
||||
title: t('Divider'),
|
||||
onItemClick: () => {
|
||||
insertOrUpdateBlock(editor, {
|
||||
type: 'divider',
|
||||
});
|
||||
},
|
||||
aliases: ['divider', 'hr', 'horizontal rule', 'line', 'separator'],
|
||||
group,
|
||||
icon: <Icon iconName="remove" $size="18px" />,
|
||||
subtext: t('Add a horizontal line'),
|
||||
},
|
||||
];
|
||||
@@ -1,2 +0,0 @@
|
||||
export * from './CalloutBlock';
|
||||
export * from './DividerBlock';
|
||||
+189
-1468
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,114 @@
|
||||
# ERB templated nginx configuration
|
||||
# see https://doc.scalingo.com/platform/deployment/buildpacks/nginx
|
||||
|
||||
upstream backend_server {
|
||||
server localhost:8000 fail_timeout=0;
|
||||
}
|
||||
|
||||
upstream collaboration_server {
|
||||
server localhost:4444 fail_timeout=0;
|
||||
}
|
||||
|
||||
server {
|
||||
|
||||
listen <%= ENV["PORT"] %>;
|
||||
server_name _;
|
||||
|
||||
root /app/build/frontend-out;
|
||||
|
||||
error_page 404 /404.html;
|
||||
|
||||
location /collaboration/api/ {
|
||||
proxy_set_header X-Forwarded-Proto https;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
||||
proxy_redirect off;
|
||||
proxy_pass http://collaboration_server;
|
||||
}
|
||||
|
||||
location /collaboration/ws/ {
|
||||
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "Upgrade";
|
||||
|
||||
# Set appropriate timeout for WebSocketAdd commentMore actions
|
||||
proxy_read_timeout 86400;
|
||||
proxy_send_timeout 86400;
|
||||
|
||||
proxy_set_header X-Forwarded-Proto https;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
||||
proxy_redirect off;
|
||||
proxy_pass http://collaboration_server;
|
||||
}
|
||||
|
||||
# Django rest framework
|
||||
location ^~ /api/ {
|
||||
proxy_set_header X-Forwarded-Proto https;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
||||
proxy_redirect off;
|
||||
proxy_pass http://backend_server;
|
||||
}
|
||||
|
||||
# Django admin
|
||||
location ^~ /admin/ {
|
||||
proxy_set_header X-Forwarded-Proto https;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
||||
proxy_redirect off;
|
||||
proxy_pass http://backend_server;
|
||||
}
|
||||
|
||||
# Proxy auth for media
|
||||
location /media/ {
|
||||
# Auth request configuration
|
||||
auth_request /media-auth;
|
||||
auth_request_set $authHeader $upstream_http_authorization;
|
||||
auth_request_set $authDate $upstream_http_x_amz_date;
|
||||
auth_request_set $authContentSha256 $upstream_http_x_amz_content_sha256;
|
||||
|
||||
# Pass specific headers from the auth response
|
||||
proxy_set_header Authorization $authHeader;
|
||||
proxy_set_header X-Amz-Date $authDate;
|
||||
proxy_set_header X-Amz-Content-SHA256 $authContentSha256;
|
||||
|
||||
# Get resource from Object Storage
|
||||
proxy_pass <%= ENV["AWS_S3_ENDPOINT_URL"] %>/<%= ENV["AWS_STORAGE_BUCKET_NAME"] %>/;
|
||||
proxy_set_header Host <%= ENV["AWS_S3_ENDPOINT_URL"].split("://")[1] %>;
|
||||
|
||||
add_header Content-Security-Policy "default-src 'none'" always;
|
||||
}
|
||||
|
||||
location /media-auth {
|
||||
proxy_pass http://backend_server/api/v1.0/documents/media-auth/;
|
||||
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-Original-URL $request_uri;
|
||||
|
||||
# Prevent the body from being passed
|
||||
proxy_pass_request_body off;
|
||||
proxy_set_header Content-Length "";
|
||||
proxy_set_header X-Original-Method $request_method;
|
||||
}
|
||||
|
||||
|
||||
location / {
|
||||
try_files $uri index.html $uri/ =404;
|
||||
}
|
||||
|
||||
location ~ "^/docs/[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/?$" {
|
||||
try_files $uri /docs/[id]/index.html;
|
||||
}
|
||||
|
||||
location = /404.html {
|
||||
internal;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user