Compare commits
32 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
fb6e03c1a2 | ||
![]() |
46c3345f45 | ||
![]() |
1156a32a88 | ||
d848af524f | |||
c9f88c36cd | |||
0ad44a944e | |||
fbd0e03a33 | |||
![]() |
076828f003 | ||
![]() |
4f6c459532 | ||
![]() |
11524c17ea | ||
168f845772 | |||
657146cdca | |||
![]() |
86111bc9f5 | ||
![]() |
a8018a0b2f | ||
![]() |
9d8bd629ab | ||
1eddf9cc0b | |||
6415f86286 | |||
5d1c4f0084 | |||
1dce947db6 | |||
4d9551a93c | |||
e6471280d5 | |||
3e062b4346 | |||
5b1a93c781 | |||
c30001547a | |||
025019b544 | |||
a862a11c91 | |||
f3d86daea7 | |||
296716397e | |||
22c42839c1 | |||
4fd90e305f | |||
6dfec6714a | |||
2c72189055 |
31
.gitea/workflows/main.yml
Normal file
31
.gitea/workflows/main.yml
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
name: 'Deploy to discoursio-api'
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Cloning repo
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Get Repo Name
|
||||||
|
id: repo_name
|
||||||
|
run: echo "::set-output name=repo::$(echo ${GITHUB_REPOSITORY##*/})"
|
||||||
|
|
||||||
|
- name: Get Branch Name
|
||||||
|
id: branch_name
|
||||||
|
run: echo "::set-output name=branch::$(echo ${GITHUB_REF##*/})"
|
||||||
|
|
||||||
|
- name: Push to dokku
|
||||||
|
uses: dokku/github-action@master
|
||||||
|
with:
|
||||||
|
branch: 'main'
|
||||||
|
git_remote_url: 'ssh://dokku@v2.discours.io:22/discoursio-api'
|
||||||
|
ssh_private_key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||||
|
|
||||||
|
|
8
.gitignore
vendored
8
.gitignore
vendored
|
@ -147,3 +147,11 @@ migration/content/**/*.md
|
||||||
*.csv
|
*.csv
|
||||||
dev-server.pid
|
dev-server.pid
|
||||||
backups/
|
backups/
|
||||||
|
.ruff_cache
|
||||||
|
.venv
|
||||||
|
poetry.lock
|
||||||
|
.devcontainer/devcontainer.json
|
||||||
|
localhost-key.pem
|
||||||
|
.gitignore
|
||||||
|
discoursio.db
|
||||||
|
localhost.pem
|
||||||
|
|
10
Dockerfile
10
Dockerfile
|
@ -1,9 +1,11 @@
|
||||||
FROM python:3.10
|
FROM python:3.11-slim
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
ADD nginx.conf.sigil ./
|
ADD nginx.conf.sigil ./
|
||||||
RUN /usr/local/bin/python -m pip install --upgrade pip
|
COPY requirements.txt .
|
||||||
WORKDIR /usr/src/app
|
RUN apt update && apt install -y git gcc curl postgresql
|
||||||
COPY requirements.txt ./
|
|
||||||
RUN pip install -r requirements.txt
|
RUN pip install -r requirements.txt
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
|
CMD python server.py
|
||||||
|
|
|
@ -33,8 +33,8 @@ class Password:
|
||||||
Verify that password hash is equal to specified hash. Hash format:
|
Verify that password hash is equal to specified hash. Hash format:
|
||||||
|
|
||||||
$2a$10$Ro0CUfOqk6cXEKf3dyaM7OhSCvnwM9s4wIX9JeLapehKK5YdLxKcm
|
$2a$10$Ro0CUfOqk6cXEKf3dyaM7OhSCvnwM9s4wIX9JeLapehKK5YdLxKcm
|
||||||
\__/\/ \____________________/\_____________________________/ # noqa: W605
|
__ __ ____________________________________________________ # noqa: W605
|
||||||
| | Salt Hash
|
| | | Salt (22) | Hash
|
||||||
| Cost
|
| Cost
|
||||||
Version
|
Version
|
||||||
|
|
||||||
|
|
|
@ -1,45 +1,61 @@
|
||||||
from asyncio import sleep
|
import redis.asyncio as aredis
|
||||||
|
|
||||||
from aioredis import from_url
|
|
||||||
|
|
||||||
from settings import REDIS_URL
|
from settings import REDIS_URL
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger("[services.redis] ")
|
||||||
|
logger.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
|
|
||||||
class RedisCache:
|
class RedisCache:
|
||||||
def __init__(self, uri=REDIS_URL):
|
def __init__(self, uri=REDIS_URL):
|
||||||
self._uri: str = uri
|
self._uri: str = uri
|
||||||
self._instance = None
|
self.pubsub_channels = []
|
||||||
|
self._client = None
|
||||||
|
|
||||||
async def connect(self):
|
async def connect(self):
|
||||||
if self._instance is not None:
|
self._client = aredis.Redis.from_url(self._uri, decode_responses=True)
|
||||||
return
|
|
||||||
self._instance = await from_url(self._uri, encoding="utf-8")
|
|
||||||
# print(self._instance)
|
|
||||||
|
|
||||||
async def disconnect(self):
|
async def disconnect(self):
|
||||||
if self._instance is None:
|
if self._client:
|
||||||
return
|
await self._client.close()
|
||||||
await self._instance.close()
|
|
||||||
# await self._instance.wait_closed() # deprecated
|
|
||||||
self._instance = None
|
|
||||||
|
|
||||||
async def execute(self, command, *args, **kwargs):
|
async def execute(self, command, *args, **kwargs):
|
||||||
while not self._instance:
|
if self._client:
|
||||||
await sleep(1)
|
try:
|
||||||
try:
|
logger.debug(f"{command} {args} {kwargs}")
|
||||||
# print("[redis] " + command + ' ' + ' '.join(args))
|
r = await self._client.execute_command(command, *args, **kwargs)
|
||||||
return await self._instance.execute_command(command, *args, **kwargs)
|
logger.debug(type(r))
|
||||||
except Exception:
|
logger.debug(r)
|
||||||
pass
|
return r
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
|
||||||
|
async def subscribe(self, *channels):
|
||||||
|
if self._client:
|
||||||
|
async with self._client.pubsub() as pubsub:
|
||||||
|
for channel in channels:
|
||||||
|
await pubsub.subscribe(channel)
|
||||||
|
self.pubsub_channels.append(channel)
|
||||||
|
|
||||||
|
async def unsubscribe(self, *channels):
|
||||||
|
if not self._client:
|
||||||
|
return
|
||||||
|
async with self._client.pubsub() as pubsub:
|
||||||
|
for channel in channels:
|
||||||
|
await pubsub.unsubscribe(channel)
|
||||||
|
self.pubsub_channels.remove(channel)
|
||||||
|
|
||||||
|
async def publish(self, channel, data):
|
||||||
|
if not self._client:
|
||||||
|
return
|
||||||
|
await self._client.publish(channel, data)
|
||||||
|
|
||||||
|
async def mget(self, *keys):
|
||||||
|
return await self.execute('MGET', *keys)
|
||||||
|
|
||||||
async def lrange(self, key, start, stop):
|
async def lrange(self, key, start, stop):
|
||||||
# print(f"[redis] LRANGE {key} {start} {stop}")
|
return await self.execute('LRANGE', key, start, stop)
|
||||||
return await self._instance.lrange(key, start, stop)
|
|
||||||
|
|
||||||
async def mget(self, key, *keys):
|
|
||||||
# print(f"[redis] MGET {key} {keys}")
|
|
||||||
return await self._instance.mget(key, *keys)
|
|
||||||
|
|
||||||
|
|
||||||
redis = RedisCache()
|
redis = RedisCache()
|
||||||
|
|
||||||
|
|
237
nginx.conf.sigil
237
nginx.conf.sigil
|
@ -1,226 +1,91 @@
|
||||||
|
{{ $proxy_settings := "proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $http_connection; proxy_set_header Host $http_host; proxy_set_header X-Request-Start $msec;" }}
|
||||||
|
{{ $gzip_settings := "gzip on; gzip_min_length 1100; gzip_buffers 4 32k; gzip_types text/css text/javascript text/xml text/plain text/x-component application/javascript application/x-javascript application/json application/xml application/rss+xml font/truetype application/x-font-ttf font/opentype application/vnd.ms-fontobject image/svg+xml; gzip_vary on; gzip_comp_level 6;" }}
|
||||||
|
|
||||||
|
{{ $cors_headers_options := "if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' '$allow_origin' always; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization'; add_header 'Access-Control-Allow-Credentials' 'true'; add_header 'Access-Control-Max-Age' 1728000; add_header 'Content-Type' 'text/plain; charset=utf-8'; add_header 'Content-Length' 0; return 204; }" }}
|
||||||
|
{{ $cors_headers_post := "if ($request_method = 'POST') { add_header 'Access-Control-Allow-Origin' '$allow_origin' always; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always; add_header 'Access-Control-Allow-Credentials' 'true' always; }" }}
|
||||||
|
{{ $cors_headers_get := "if ($request_method = 'GET') { add_header 'Access-Control-Allow-Origin' '$allow_origin' always; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always; add_header 'Access-Control-Allow-Credentials' 'true' always; }" }}
|
||||||
|
|
||||||
{{ range $port_map := .PROXY_PORT_MAP | split " " }}
|
{{ range $port_map := .PROXY_PORT_MAP | split " " }}
|
||||||
{{ $port_map_list := $port_map | split ":" }}
|
{{ $port_map_list := $port_map | split ":" }}
|
||||||
{{ $scheme := index $port_map_list 0 }}
|
{{ $scheme := index $port_map_list 0 }}
|
||||||
{{ $listen_port := index $port_map_list 1 }}
|
{{ $listen_port := index $port_map_list 1 }}
|
||||||
{{ $upstream_port := index $port_map_list 2 }}
|
{{ $upstream_port := index $port_map_list 2 }}
|
||||||
|
|
||||||
map $http_origin $allow_origin {
|
|
||||||
~^https?:\/\/((.*\.)?localhost(:\d+)?|discoursio-webapp(-(.*))?\.vercel\.app|(.*\.)?discours\.io)$ $http_origin;
|
|
||||||
default "";
|
|
||||||
}
|
|
||||||
|
|
||||||
{{ if eq $scheme "http" }}
|
|
||||||
server {
|
server {
|
||||||
listen [{{ $.NGINX_BIND_ADDRESS_IP6 }}]:{{ $listen_port }};
|
{{ if eq $scheme "http" }}
|
||||||
listen {{ if $.NGINX_BIND_ADDRESS_IP4 }}{{ $.NGINX_BIND_ADDRESS_IP4 }}:{{end}}{{ $listen_port }};
|
listen [::]:{{ $listen_port }};
|
||||||
{{ if $.NOSSL_SERVER_NAME }}server_name {{ $.NOSSL_SERVER_NAME }}; {{ end }}
|
listen {{ $listen_port }};
|
||||||
access_log {{ $.NGINX_ACCESS_LOG_PATH }}{{ if and ($.NGINX_ACCESS_LOG_FORMAT) (ne $.NGINX_ACCESS_LOG_PATH "off") }} {{ $.NGINX_ACCESS_LOG_FORMAT }}{{ end }};
|
server_name {{ $.NOSSL_SERVER_NAME }};
|
||||||
error_log {{ $.NGINX_ERROR_LOG_PATH }};
|
access_log /var/log/nginx/{{ $.APP }}-access.log;
|
||||||
{{ if (and (eq $listen_port "80") ($.SSL_INUSE)) }}
|
error_log /var/log/nginx/{{ $.APP }}-error.log;
|
||||||
include {{ $.DOKKU_ROOT }}/{{ $.APP }}/nginx.conf.d/*.conf;
|
|
||||||
location / {
|
|
||||||
return 301 https://$host:{{ $.PROXY_SSL_PORT }}$request_uri;
|
|
||||||
}
|
|
||||||
{{ else }}
|
|
||||||
location / {
|
|
||||||
|
|
||||||
gzip on;
|
{{ else if eq $scheme "https" }}
|
||||||
gzip_min_length 1100;
|
listen [::]:{{ $listen_port }} ssl http2;
|
||||||
gzip_buffers 4 32k;
|
listen {{ $listen_port }} ssl http2;
|
||||||
gzip_types text/css text/javascript text/xml text/plain text/x-component application/javascript application/x-javascript application/json application/xml application/rss+xml font/truetype application/x-font-ttf font/opentype application/vnd.ms-fontobject image/svg+xml;
|
server_name {{ $.NOSSL_SERVER_NAME }};
|
||||||
gzip_vary on;
|
access_log /var/log/nginx/{{ $.APP }}-access.log;
|
||||||
gzip_comp_level 6;
|
error_log /var/log/nginx/{{ $.APP }}-error.log;
|
||||||
|
ssl_certificate {{ $.APP_SSL_PATH }}/server.crt;
|
||||||
|
ssl_certificate_key {{ $.APP_SSL_PATH }}/server.key;
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
ssl_prefer_server_ciphers off;
|
||||||
|
|
||||||
proxy_pass http://{{ $.APP }}-{{ $upstream_port }};
|
keepalive_timeout 70;
|
||||||
proxy_http_version 1.1;
|
{{ end }}
|
||||||
proxy_read_timeout {{ $.PROXY_READ_TIMEOUT }};
|
|
||||||
proxy_buffer_size {{ $.PROXY_BUFFER_SIZE }};
|
|
||||||
proxy_buffering {{ $.PROXY_BUFFERING }};
|
|
||||||
proxy_buffers {{ $.PROXY_BUFFERS }};
|
|
||||||
proxy_busy_buffers_size {{ $.PROXY_BUSY_BUFFERS_SIZE }};
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header Connection $http_connection;
|
|
||||||
proxy_set_header Host $http_host;
|
|
||||||
proxy_set_header X-Forwarded-For {{ $.PROXY_X_FORWARDED_FOR }};
|
|
||||||
proxy_set_header X-Forwarded-Port {{ $.PROXY_X_FORWARDED_PORT }};
|
|
||||||
proxy_set_header X-Forwarded-Proto {{ $.PROXY_X_FORWARDED_PROTO }};
|
|
||||||
proxy_set_header X-Request-Start $msec;
|
|
||||||
{{ if $.PROXY_X_FORWARDED_SSL }}proxy_set_header X-Forwarded-Ssl {{ $.PROXY_X_FORWARDED_SSL }};{{ end }}
|
|
||||||
}
|
|
||||||
|
|
||||||
{{ if $.CLIENT_MAX_BODY_SIZE }}client_max_body_size {{ $.CLIENT_MAX_BODY_SIZE }};{{ end }}
|
|
||||||
include {{ $.DOKKU_ROOT }}/{{ $.APP }}/nginx.conf.d/*.conf;
|
|
||||||
|
|
||||||
error_page 400 401 402 403 405 406 407 408 409 410 411 412 413 414 415 416 417 418 420 422 423 424 426 428 429 431 444 449 450 451 /400-error.html;
|
location / {
|
||||||
|
proxy_pass http://{{ $.APP }}-{{ $upstream_port }};
|
||||||
|
{{ $proxy_settings }}
|
||||||
|
{{ $gzip_settings }}
|
||||||
|
{{ $cors_headers_options }}
|
||||||
|
{{ $cors_headers_post }}
|
||||||
|
{{ $cors_headers_get }}
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
|
||||||
|
expires 30d; # This means that the client can cache these resources for 30 days.
|
||||||
|
add_header Cache-Control "public, no-transform";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
error_page 400 401 402 403 405 406 407 408 409 410 411 412 413 414 415 416 417 418 420 422 423 424 426 428 429 431 444 449 450 451 /400-error.html;
|
||||||
location /400-error.html {
|
location /400-error.html {
|
||||||
root {{ $.DOKKU_LIB_ROOT }}/data/nginx-vhosts/dokku-errors;
|
root /var/lib/dokku/data/nginx-vhosts/dokku-errors;
|
||||||
internal;
|
internal;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_page 404 /404-error.html;
|
error_page 404 /404-error.html;
|
||||||
location /404-error.html {
|
location /404-error.html {
|
||||||
root {{ $.DOKKU_LIB_ROOT }}/data/nginx-vhosts/dokku-errors;
|
root /var/lib/dokku/data/nginx-vhosts/dokku-errors;
|
||||||
internal;
|
|
||||||
}
|
|
||||||
|
|
||||||
error_page 500 501 502 503 504 505 506 507 508 509 510 511 /500-error.html;
|
|
||||||
location /500-error.html {
|
|
||||||
root {{ $.DOKKU_LIB_ROOT }}/data/nginx-vhosts/dokku-errors;
|
|
||||||
internal;
|
|
||||||
}
|
|
||||||
{{ end }}
|
|
||||||
}
|
|
||||||
{{ else if eq $scheme "https"}}
|
|
||||||
server {
|
|
||||||
listen [{{ $.NGINX_BIND_ADDRESS_IP6 }}]:{{ $listen_port }} ssl {{ if eq $.HTTP2_SUPPORTED "true" }}http2{{ else if eq $.SPDY_SUPPORTED "true" }}spdy{{ end }};
|
|
||||||
listen {{ if $.NGINX_BIND_ADDRESS_IP4 }}{{ $.NGINX_BIND_ADDRESS_IP4 }}:{{end}}{{ $listen_port }} ssl {{ if eq $.HTTP2_SUPPORTED "true" }}http2{{ else if eq $.SPDY_SUPPORTED "true" }}spdy{{ end }};
|
|
||||||
{{ if $.SSL_SERVER_NAME }}server_name {{ $.SSL_SERVER_NAME }}; {{ end }}
|
|
||||||
{{ if $.NOSSL_SERVER_NAME }}server_name {{ $.NOSSL_SERVER_NAME }}; {{ end }}
|
|
||||||
access_log {{ $.NGINX_ACCESS_LOG_PATH }}{{ if and ($.NGINX_ACCESS_LOG_FORMAT) (ne $.NGINX_ACCESS_LOG_PATH "off") }} {{ $.NGINX_ACCESS_LOG_FORMAT }}{{ end }};
|
|
||||||
error_log {{ $.NGINX_ERROR_LOG_PATH }};
|
|
||||||
|
|
||||||
ssl_certificate {{ $.APP_SSL_PATH }}/server.crt;
|
|
||||||
ssl_certificate_key {{ $.APP_SSL_PATH }}/server.key;
|
|
||||||
ssl_protocols TLSv1.2 {{ if eq $.TLS13_SUPPORTED "true" }}TLSv1.3{{ end }};
|
|
||||||
ssl_prefer_server_ciphers off;
|
|
||||||
|
|
||||||
keepalive_timeout 70;
|
|
||||||
{{ if and (eq $.SPDY_SUPPORTED "true") (ne $.HTTP2_SUPPORTED "true") }}add_header Alternate-Protocol {{ $.PROXY_SSL_PORT }}:npn-spdy/2;{{ end }}
|
|
||||||
|
|
||||||
location / {
|
|
||||||
|
|
||||||
gzip on;
|
|
||||||
gzip_min_length 1100;
|
|
||||||
gzip_buffers 4 32k;
|
|
||||||
gzip_types text/css text/javascript text/xml text/plain text/x-component application/javascript application/x-javascript application/json application/xml application/rss+xml font/truetype application/x-font-ttf font/opentype application/vnd.ms-fontobject image/svg+xml;
|
|
||||||
gzip_vary on;
|
|
||||||
gzip_comp_level 6;
|
|
||||||
|
|
||||||
proxy_pass http://{{ $.APP }}-{{ $upstream_port }};
|
|
||||||
{{ if eq $.HTTP2_PUSH_SUPPORTED "true" }}http2_push_preload on; {{ end }}
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_read_timeout {{ $.PROXY_READ_TIMEOUT }};
|
|
||||||
proxy_buffer_size {{ $.PROXY_BUFFER_SIZE }};
|
|
||||||
proxy_buffering {{ $.PROXY_BUFFERING }};
|
|
||||||
proxy_buffers {{ $.PROXY_BUFFERS }};
|
|
||||||
proxy_busy_buffers_size {{ $.PROXY_BUSY_BUFFERS_SIZE }};
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header Connection $http_connection;
|
|
||||||
proxy_set_header Host $http_host;
|
|
||||||
proxy_set_header X-Forwarded-For {{ $.PROXY_X_FORWARDED_FOR }};
|
|
||||||
proxy_set_header X-Forwarded-Port {{ $.PROXY_X_FORWARDED_PORT }};
|
|
||||||
proxy_set_header X-Forwarded-Proto {{ $.PROXY_X_FORWARDED_PROTO }};
|
|
||||||
proxy_set_header X-Request-Start $msec;
|
|
||||||
{{ if $.PROXY_X_FORWARDED_SSL }}proxy_set_header X-Forwarded-Ssl {{ $.PROXY_X_FORWARDED_SSL }};{{ end }}
|
|
||||||
|
|
||||||
if ($request_method = 'OPTIONS') {
|
|
||||||
add_header 'Access-Control-Allow-Origin' '$allow_origin' always;
|
|
||||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
|
|
||||||
#
|
|
||||||
# Custom headers and headers various browsers *should* be OK with but aren't
|
|
||||||
#
|
|
||||||
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
|
|
||||||
add_header 'Access-Control-Allow-Credentials' 'true';
|
|
||||||
#
|
|
||||||
# Tell client that this pre-flight info is valid for 20 days
|
|
||||||
#
|
|
||||||
add_header 'Access-Control-Max-Age' 1728000;
|
|
||||||
add_header 'Content-Type' 'text/plain; charset=utf-8';
|
|
||||||
add_header 'Content-Length' 0;
|
|
||||||
return 204;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($request_method = 'POST') {
|
|
||||||
add_header 'Access-Control-Allow-Origin' '$allow_origin' always;
|
|
||||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
|
|
||||||
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always;
|
|
||||||
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
|
|
||||||
add_header 'Access-Control-Allow-Credentials' 'true' always;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($request_method = 'GET') {
|
|
||||||
add_header 'Access-Control-Allow-Origin' '$allow_origin' always;
|
|
||||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
|
|
||||||
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always;
|
|
||||||
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
|
|
||||||
add_header 'Access-Control-Allow-Credentials' 'true' always;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{{ if $.CLIENT_MAX_BODY_SIZE }}client_max_body_size {{ $.CLIENT_MAX_BODY_SIZE }};{{ end }}
|
|
||||||
include {{ $.DOKKU_ROOT }}/{{ $.APP }}/nginx.conf.d/*.conf;
|
|
||||||
|
|
||||||
error_page 400 401 402 403 405 406 407 408 409 410 411 412 413 414 415 416 417 418 420 422 423 424 426 428 429 431 444 449 450 451 /400-error.html;
|
|
||||||
location /400-error.html {
|
|
||||||
root {{ $.DOKKU_LIB_ROOT }}/data/nginx-vhosts/dokku-errors;
|
|
||||||
internal;
|
|
||||||
}
|
|
||||||
|
|
||||||
error_page 404 /404-error.html;
|
|
||||||
location /404-error.html {
|
|
||||||
root {{ $.DOKKU_LIB_ROOT }}/data/nginx-vhosts/dokku-errors;
|
|
||||||
internal;
|
internal;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_page 500 501 503 504 505 506 507 508 509 510 511 /500-error.html;
|
error_page 500 501 503 504 505 506 507 508 509 510 511 /500-error.html;
|
||||||
location /500-error.html {
|
location /500-error.html {
|
||||||
root {{ $.DOKKU_LIB_ROOT }}/data/nginx-vhosts/dokku-errors;
|
root /var/lib/dokku/data/nginx-vhosts/dokku-errors;
|
||||||
internal;
|
internal;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_page 502 /502-error.html;
|
error_page 502 /502-error.html;
|
||||||
location /502-error.html {
|
location /502-error.html {
|
||||||
root {{ $.DOKKU_LIB_ROOT }}/data/nginx-vhosts/dokku-errors;
|
root /var/lib/dokku/data/nginx-vhosts/dokku-errors;
|
||||||
internal;
|
internal;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
{{ else if eq $scheme "grpc"}}
|
|
||||||
{{ if eq $.GRPC_SUPPORTED "true"}}{{ if eq $.HTTP2_SUPPORTED "true"}}
|
|
||||||
server {
|
|
||||||
listen [{{ $.NGINX_BIND_ADDRESS_IP6 }}]:{{ $listen_port }} http2;
|
|
||||||
listen {{ if $.NGINX_BIND_ADDRESS_IP4 }}{{ $.NGINX_BIND_ADDRESS_IP4 }}:{{end}}{{ $listen_port }} http2;
|
|
||||||
{{ if $.NOSSL_SERVER_NAME }}server_name {{ $.NOSSL_SERVER_NAME }}; {{ end }}
|
|
||||||
access_log {{ $.NGINX_ACCESS_LOG_PATH }}{{ if and ($.NGINX_ACCESS_LOG_FORMAT) (ne $.NGINX_ACCESS_LOG_PATH "off") }} {{ $.NGINX_ACCESS_LOG_FORMAT }}{{ end }};
|
|
||||||
error_log {{ $.NGINX_ERROR_LOG_PATH }};
|
|
||||||
location / {
|
|
||||||
grpc_pass grpc://{{ $.APP }}-{{ $upstream_port }};
|
|
||||||
}
|
|
||||||
|
|
||||||
{{ if $.CLIENT_MAX_BODY_SIZE }}client_max_body_size {{ $.CLIENT_MAX_BODY_SIZE }};{{ end }}
|
# include /home/dokku/gateway/nginx.conf.d/*.conf;
|
||||||
include {{ $.DOKKU_ROOT }}/{{ $.APP }}/nginx.conf.d/*.conf;
|
include {{ $.DOKKU_ROOT }}/{{ $.APP }}/nginx.conf.d/*.conf;
|
||||||
}
|
}
|
||||||
{{ end }}{{ end }}
|
|
||||||
{{ else if eq $scheme "grpcs"}}
|
|
||||||
{{ if eq $.GRPC_SUPPORTED "true"}}{{ if eq $.HTTP2_SUPPORTED "true"}}
|
|
||||||
server {
|
|
||||||
listen [{{ $.NGINX_BIND_ADDRESS_IP6 }}]:{{ $listen_port }} ssl http2;
|
|
||||||
listen {{ if $.NGINX_BIND_ADDRESS_IP4 }}{{ $.NGINX_BIND_ADDRESS_IP4 }}:{{end}}{{ $listen_port }} ssl http2;
|
|
||||||
{{ if $.NOSSL_SERVER_NAME }}server_name {{ $.NOSSL_SERVER_NAME }}; {{ end }}
|
|
||||||
access_log {{ $.NGINX_ACCESS_LOG_PATH }}{{ if and ($.NGINX_ACCESS_LOG_FORMAT) (ne $.NGINX_ACCESS_LOG_PATH "off") }} {{ $.NGINX_ACCESS_LOG_FORMAT }}{{ end }};
|
|
||||||
error_log {{ $.NGINX_ERROR_LOG_PATH }};
|
|
||||||
|
|
||||||
ssl_certificate {{ $.APP_SSL_PATH }}/server.crt;
|
|
||||||
ssl_certificate_key {{ $.APP_SSL_PATH }}/server.key;
|
|
||||||
ssl_protocols TLSv1.2 {{ if eq $.TLS13_SUPPORTED "true" }}TLSv1.3{{ end }};
|
|
||||||
ssl_prefer_server_ciphers off;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
grpc_pass grpc://{{ $.APP }}-{{ $upstream_port }};
|
|
||||||
}
|
|
||||||
|
|
||||||
{{ if $.CLIENT_MAX_BODY_SIZE }}client_max_body_size {{ $.CLIENT_MAX_BODY_SIZE }};{{ end }}
|
|
||||||
include {{ $.DOKKU_ROOT }}/{{ $.APP }}/nginx.conf.d/*.conf;
|
|
||||||
}
|
|
||||||
{{ end }}{{ end }}
|
|
||||||
{{ end }}
|
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
{{ if $.DOKKU_APP_WEB_LISTENERS }}
|
|
||||||
{{ range $upstream_port := $.PROXY_UPSTREAM_PORTS | split " " }}
|
{{ range $upstream_port := $.PROXY_UPSTREAM_PORTS | split " " }}
|
||||||
upstream {{ $.APP }}-{{ $upstream_port }} {
|
upstream {{ $.APP }}-{{ $upstream_port }} {
|
||||||
{{ range $listeners := $.DOKKU_APP_WEB_LISTENERS | split " " }}
|
{{ range $listeners := $.DOKKU_APP_WEB_LISTENERS | split " " }}
|
||||||
{{ $listener_list := $listeners | split ":" }}
|
{{ $listener_list := $listeners | split ":" }}
|
||||||
{{ $listener_ip := index $listener_list 0 }}
|
{{ $listener_ip := index $listener_list 0 }}
|
||||||
server {{ $listener_ip }}:{{ $upstream_port }};{{ end }}
|
{{ $listener_port := index $listener_list 1 }}
|
||||||
|
server {{ $listener_ip }}:{{ $upstream_port }};
|
||||||
|
{{ end }}
|
||||||
}
|
}
|
||||||
{{ end }}{{ end }}
|
{{ end }}
|
||||||
|
|
1802
poetry.lock
generated
Normal file
1802
poetry.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -1,2 +0,0 @@
|
||||||
[tool.black]
|
|
||||||
line-length = 100
|
|
|
@ -1,5 +1,4 @@
|
||||||
aiohttp
|
aiohttp==3.8.6
|
||||||
aioredis~=2.0.1
|
|
||||||
alembic==1.11.3
|
alembic==1.11.3
|
||||||
ariadne>=0.17.0
|
ariadne>=0.17.0
|
||||||
asyncio~=3.4.3
|
asyncio~=3.4.3
|
||||||
|
@ -32,6 +31,7 @@ sentry-sdk>=1.14.0
|
||||||
sqlalchemy>=1.4.41
|
sqlalchemy>=1.4.41
|
||||||
sse-starlette==1.6.5
|
sse-starlette==1.6.5
|
||||||
starlette~=0.23.1
|
starlette~=0.23.1
|
||||||
transformers~=4.28.1
|
|
||||||
transliterate~=1.10.2
|
transliterate~=1.10.2
|
||||||
uvicorn>=0.18.3
|
uvicorn>=0.18.3
|
||||||
|
|
||||||
|
redis
|
||||||
|
|
|
@ -84,7 +84,8 @@ async def get_topic(_, _info, slug):
|
||||||
q = add_topic_stat_columns(q)
|
q = add_topic_stat_columns(q)
|
||||||
|
|
||||||
topics = get_topics_from_query(q)
|
topics = get_topics_from_query(q)
|
||||||
return topics[0]
|
if topics:
|
||||||
|
return topics[0]
|
||||||
|
|
||||||
|
|
||||||
@mutation.field("createTopic")
|
@mutation.field("createTopic")
|
||||||
|
@ -155,8 +156,9 @@ def get_random_topic():
|
||||||
q = q.order_by(func.random()).limit(1)
|
q = q.order_by(func.random()).limit(1)
|
||||||
|
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
[topic] = session.execute(q).first()
|
topics = session.execute(q).first()
|
||||||
return topic
|
if topics:
|
||||||
|
return topics[0]
|
||||||
|
|
||||||
|
|
||||||
@query.field("topicsRandom")
|
@query.field("topicsRandom")
|
||||||
|
|
1
runtime.txt
Normal file
1
runtime.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
python-3.11.7
|
|
@ -6,7 +6,7 @@ DB_URL = (
|
||||||
environ.get("DATABASE_URL")
|
environ.get("DATABASE_URL")
|
||||||
or environ.get("DB_URL")
|
or environ.get("DB_URL")
|
||||||
or "postgresql://postgres@localhost:5432/discoursio"
|
or "postgresql://postgres@localhost:5432/discoursio"
|
||||||
)
|
).replace("postgres://", "postgresql://")
|
||||||
JWT_ALGORITHM = "HS256"
|
JWT_ALGORITHM = "HS256"
|
||||||
JWT_SECRET_KEY = environ.get("JWT_SECRET_KEY") or "8f1bd7696ffb482d8486dfbc6e7d16dd-secret-key"
|
JWT_SECRET_KEY = environ.get("JWT_SECRET_KEY") or "8f1bd7696ffb482d8486dfbc6e7d16dd-secret-key"
|
||||||
SESSION_TOKEN_LIFE_SPAN = 30 * 24 * 60 * 60 # 1 month in seconds
|
SESSION_TOKEN_LIFE_SPAN = 30 * 24 * 60 * 60 # 1 month in seconds
|
||||||
|
|
Loading…
Reference in New Issue
Block a user