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
|
||||
dev-server.pid
|
||||
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
|
||||
ADD nginx.conf.sigil ./
|
||||
RUN /usr/local/bin/python -m pip install --upgrade pip
|
||||
WORKDIR /usr/src/app
|
||||
COPY requirements.txt ./
|
||||
COPY requirements.txt .
|
||||
RUN apt update && apt install -y git gcc curl postgresql
|
||||
RUN pip install -r requirements.txt
|
||||
COPY . .
|
||||
|
||||
CMD python server.py
|
||||
|
|
|
@ -33,8 +33,8 @@ class Password:
|
|||
Verify that password hash is equal to specified hash. Hash format:
|
||||
|
||||
$2a$10$Ro0CUfOqk6cXEKf3dyaM7OhSCvnwM9s4wIX9JeLapehKK5YdLxKcm
|
||||
\__/\/ \____________________/\_____________________________/ # noqa: W605
|
||||
| | Salt Hash
|
||||
__ __ ____________________________________________________ # noqa: W605
|
||||
| | | Salt (22) | Hash
|
||||
| Cost
|
||||
Version
|
||||
|
||||
|
|
|
@ -1,45 +1,61 @@
|
|||
from asyncio import sleep
|
||||
|
||||
from aioredis import from_url
|
||||
import redis.asyncio as aredis
|
||||
|
||||
from settings import REDIS_URL
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger("[services.redis] ")
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
|
||||
class RedisCache:
|
||||
def __init__(self, uri=REDIS_URL):
|
||||
self._uri: str = uri
|
||||
self._instance = None
|
||||
self.pubsub_channels = []
|
||||
self._client = None
|
||||
|
||||
async def connect(self):
|
||||
if self._instance is not None:
|
||||
return
|
||||
self._instance = await from_url(self._uri, encoding="utf-8")
|
||||
# print(self._instance)
|
||||
self._client = aredis.Redis.from_url(self._uri, decode_responses=True)
|
||||
|
||||
async def disconnect(self):
|
||||
if self._instance is None:
|
||||
return
|
||||
await self._instance.close()
|
||||
# await self._instance.wait_closed() # deprecated
|
||||
self._instance = None
|
||||
if self._client:
|
||||
await self._client.close()
|
||||
|
||||
async def execute(self, command, *args, **kwargs):
|
||||
while not self._instance:
|
||||
await sleep(1)
|
||||
if self._client:
|
||||
try:
|
||||
# print("[redis] " + command + ' ' + ' '.join(args))
|
||||
return await self._instance.execute_command(command, *args, **kwargs)
|
||||
except Exception:
|
||||
pass
|
||||
logger.debug(f"{command} {args} {kwargs}")
|
||||
r = await self._client.execute_command(command, *args, **kwargs)
|
||||
logger.debug(type(r))
|
||||
logger.debug(r)
|
||||
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):
|
||||
# print(f"[redis] 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)
|
||||
|
||||
return await self.execute('LRANGE', key, start, stop)
|
||||
|
||||
redis = RedisCache()
|
||||
|
||||
|
|
215
nginx.conf.sigil
215
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 " " }}
|
||||
{{ $port_map_list := $port_map | split ":" }}
|
||||
{{ $scheme := index $port_map_list 0 }}
|
||||
{{ $listen_port := index $port_map_list 1 }}
|
||||
{{ $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 {
|
||||
listen [{{ $.NGINX_BIND_ADDRESS_IP6 }}]:{{ $listen_port }};
|
||||
listen {{ if $.NGINX_BIND_ADDRESS_IP4 }}{{ $.NGINX_BIND_ADDRESS_IP4 }}:{{end}}{{ $listen_port }};
|
||||
{{ 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 }};
|
||||
{{ if (and (eq $listen_port "80") ($.SSL_INUSE)) }}
|
||||
include {{ $.DOKKU_ROOT }}/{{ $.APP }}/nginx.conf.d/*.conf;
|
||||
location / {
|
||||
return 301 https://$host:{{ $.PROXY_SSL_PORT }}$request_uri;
|
||||
}
|
||||
{{ else }}
|
||||
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 }};
|
||||
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 $.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;
|
||||
}
|
||||
|
||||
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 }};
|
||||
{{ if eq $scheme "http" }}
|
||||
listen [::]:{{ $listen_port }};
|
||||
listen {{ $listen_port }};
|
||||
server_name {{ $.NOSSL_SERVER_NAME }};
|
||||
access_log /var/log/nginx/{{ $.APP }}-access.log;
|
||||
error_log /var/log/nginx/{{ $.APP }}-error.log;
|
||||
|
||||
{{ else if eq $scheme "https" }}
|
||||
listen [::]:{{ $listen_port }} ssl http2;
|
||||
listen {{ $listen_port }} ssl http2;
|
||||
server_name {{ $.NOSSL_SERVER_NAME }};
|
||||
access_log /var/log/nginx/{{ $.APP }}-access.log;
|
||||
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 {{ if eq $.TLS13_SUPPORTED "true" }}TLSv1.3{{ end }};
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
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 }}
|
||||
{{ 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;
|
||||
{{ $proxy_settings }}
|
||||
{{ $gzip_settings }}
|
||||
{{ $cors_headers_options }}
|
||||
{{ $cors_headers_post }}
|
||||
{{ $cors_headers_get }}
|
||||
}
|
||||
|
||||
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;
|
||||
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";
|
||||
}
|
||||
|
||||
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;
|
||||
root /var/lib/dokku/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;
|
||||
root /var/lib/dokku/data/nginx-vhosts/dokku-errors;
|
||||
internal;
|
||||
}
|
||||
|
||||
error_page 500 501 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;
|
||||
root /var/lib/dokku/data/nginx-vhosts/dokku-errors;
|
||||
internal;
|
||||
}
|
||||
|
||||
error_page 502 /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;
|
||||
}
|
||||
}
|
||||
{{ 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;
|
||||
}
|
||||
{{ 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 }}
|
||||
|
||||
{{ if $.DOKKU_APP_WEB_LISTENERS }}
|
||||
|
||||
{{ range $upstream_port := $.PROXY_UPSTREAM_PORTS | split " " }}
|
||||
upstream {{ $.APP }}-{{ $upstream_port }} {
|
||||
{{ range $listeners := $.DOKKU_APP_WEB_LISTENERS | split " " }}
|
||||
{{ $listener_list := $listeners | split ":" }}
|
||||
{{ $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
|
||||
aioredis~=2.0.1
|
||||
aiohttp==3.8.6
|
||||
alembic==1.11.3
|
||||
ariadne>=0.17.0
|
||||
asyncio~=3.4.3
|
||||
|
@ -32,6 +31,7 @@ sentry-sdk>=1.14.0
|
|||
sqlalchemy>=1.4.41
|
||||
sse-starlette==1.6.5
|
||||
starlette~=0.23.1
|
||||
transformers~=4.28.1
|
||||
transliterate~=1.10.2
|
||||
uvicorn>=0.18.3
|
||||
|
||||
redis
|
||||
|
|
|
@ -84,6 +84,7 @@ async def get_topic(_, _info, slug):
|
|||
q = add_topic_stat_columns(q)
|
||||
|
||||
topics = get_topics_from_query(q)
|
||||
if topics:
|
||||
return topics[0]
|
||||
|
||||
|
||||
|
@ -155,8 +156,9 @@ def get_random_topic():
|
|||
q = q.order_by(func.random()).limit(1)
|
||||
|
||||
with local_session() as session:
|
||||
[topic] = session.execute(q).first()
|
||||
return topic
|
||||
topics = session.execute(q).first()
|
||||
if topics:
|
||||
return topics[0]
|
||||
|
||||
|
||||
@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")
|
||||
or environ.get("DB_URL")
|
||||
or "postgresql://postgres@localhost:5432/discoursio"
|
||||
)
|
||||
).replace("postgres://", "postgresql://")
|
||||
JWT_ALGORITHM = "HS256"
|
||||
JWT_SECRET_KEY = environ.get("JWT_SECRET_KEY") or "8f1bd7696ffb482d8486dfbc6e7d16dd-secret-key"
|
||||
SESSION_TOKEN_LIFE_SPAN = 30 * 24 * 60 * 60 # 1 month in seconds
|
||||
|
|
Loading…
Reference in New Issue
Block a user