Skip to content

Commit 7d66eb9

Browse files
authored
Release 2.0.0 (#220)
* fixed sorting issue, pagination issue still seen * fixed server table and authentication stuff * added better admin settings * added redis UI and python linting part 1 * flake8 linted * added google analytics * ready to deploy * ready * flip flag on
1 parent e87c119 commit 7d66eb9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+635
-185
lines changed

.github/workflows/release.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ jobs:
3030
docker login -u publisher -p ${DOCKER_TOKEN} ghcr.io
3131
3232
# Build all containers
33-
QUTEX_VERSION=$(echo ${GITHUB_REF##*/}) docker compose -f docker-compose.build.yml build
34-
QUTEX_VERSION=$(echo ${GITHUB_REF##*/}) docker compose -f docker-compose.build.yml push
33+
QUTEX_VERSION=$(echo ${GITHUB_REF##*/}) docker compose -f docker-compose.yml -f docker-compose.build.yml build
34+
QUTEX_VERSION=$(echo ${GITHUB_REF##*/}) docker compose -f docker-compose.yml -f docker-compose.build.yml push
3535
env:
3636
DOCKER_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,6 @@ docs/.sass-cache
1919
docs/.jekyll-cache
2020
docs/.jekyll-metadata
2121
docs/vendor
22+
23+
# App stuff
24+
services/ui/public/env.js

.local.env

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ AUTH_SERVICE_HOST=http://auth:4000
33
FLASK_ENV=development
44
FQDN=http://localhost
55
NODE_ENV=development
6+
SUPER_ADMINS=["Y2lzY29zcGFyazovL3VzL1BFT1BMRS9kODRkZjI1MS1iYmY3LTRlZTEtOTM1OS00Y2I0MGIyOTBhN2I"]
67

78
# UI
89
DANGEROUSLY_DISABLE_HOST_CHECK=true

.production.env

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ MONGO_INITDB_DATABASE=qutex
1212
MONGO_INITDB_ROOT_PASSWORD_FILE=/run/secrets/mongoPassword
1313

1414
# FEATURE FLAGS
15-
BOT_2_0_0=false
15+
BOT_2_0_0=true

Dockerfile.mongoexpress

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
FROM mongo-express
2+
3+
RUN sed -i 's/req.adminDb = mongo.adminDb;/req.adminDb = mongo.mainClient.adminDb || undefined;/g' lib/router.js

Makefile

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
.PHONY: build $(SERVICE)
22
build:
3-
docker compose -f docker-compose.yml -f docker-compose.dev.yml build $(SERVICE)
3+
docker compose -f docker-compose.yml -f docker-compose.dev.yml -f docker-compose.build.yml build $(SERVICE)
44

5-
.PHONY: up
5+
.PHONY: up $(SERVICE)
66
up:
7-
docker compose -f docker-compose.yml -f docker-compose.dev.yml up --build -d
7+
docker compose -f docker-compose.yml -f docker-compose.dev.yml -f docker-compose.build.yml up --build $(SERVICE) -d
88

99
.PHONY: deploy $(VERSION)
1010
deploy:
@@ -18,15 +18,24 @@ logs:
1818
down:
1919
docker compose down
2020

21-
.PHONY: test
22-
test:
21+
.PHONY: test-qutex
22+
test-qutex:
2323
export QUTEX_TESTING=true && \
2424
yarn --cwd services/bot test --verbose && \
2525
unset QUTEX_TESTING
2626

27+
.PHONY: test-nginx
28+
test-nginx:
29+
pytest services/nginx/tests
30+
31+
.PHONY: test
32+
test:
33+
${MAKE} test-qutex
34+
${MAKE} test-nginx
35+
2736
.PHONY: lint
2837
lint:
2938
yarn --cwd services/bot lint
3039
yarn --cwd services/ui lint
31-
docker run -it -v $(PWD)services:/apps/services alpine/flake8 /apps
40+
flake8 services
3241

docker-compose.build.yml

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,36 @@
11
version: '3.9'
22
services:
33
nginx:
4-
image: ghcr.io/amthorn/qutex/qutex_nginx:${QUTEX_VERSION:-latest}
54
build:
65
context: services/nginx
76
bot:
8-
image: ghcr.io/amthorn/qutex/qutex_bot:${QUTEX_VERSION:-latest}
97
build:
108
context: ./services/bot
119
ui:
12-
image: ghcr.io/amthorn/qutex/qutex_ui:${QUTEX_VERSION:-latest}
1310
build:
1411
context: services/ui/
1512
projects:
16-
image: ghcr.io/amthorn/qutex/qutex_projects:${QUTEX_VERSION:-latest}
1713
build:
1814
context: .
1915
dockerfile: services/_api_service_template/Dockerfile
2016
args:
2117
SERVICE_PREFIX: projects
2218
users:
23-
image: ghcr.io/amthorn/qutex/qutex_users:${QUTEX_VERSION:-latest}
2419
build:
2520
context: .
2621
dockerfile: services/_api_service_template/Dockerfile
2722
args:
2823
SERVICE_PREFIX: users
2924
auth:
30-
image: ghcr.io/amthorn/qutex/qutex_auth:${QUTEX_VERSION:-latest}
3125
build:
3226
context: .
3327
dockerfile: services/_api_service_template/Dockerfile
3428
args:
35-
SERVICE_PREFIX: auth
29+
SERVICE_PREFIX: auth
30+
mongo_ui:
31+
build:
32+
context: .
33+
dockerfile: Dockerfile.mongoexpress
34+
mongo_backup:
35+
build:
36+
context: services/mongo_backup

docker-compose.dev.yml

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ x-interactive: &interactive
88
services:
99
nginx:
1010
image: qutex_nginx:latest
11-
build:
12-
context: services/nginx
1311
environment:
14-
CERTBOT_EMAIL: [email protected]
15-
STAGING: "1"
16-
DEBUG: "1"
17-
RENEWAL_INTERVAL: 8d
12+
STAGING: 1
13+
# DEBUG: 1
14+
volumes:
15+
- ./services/nginx/dev_default.conf:/etc/nginx/user_conf.d/default.conf
16+
ports:
17+
- 80:80
1818
bot:
1919
<<: *interactive
2020
image: qutex_bot:latest
@@ -79,23 +79,14 @@ services:
7979
build:
8080
context: ./services/bot
8181
env_file: *env_files
82+
volumes:
83+
- ./services/bot:/app
84+
mongo_backup:
85+
image: qutex_mongo_backup:latest
8286
mongo:
8387
env_file: *env_files
8488
ports:
8589
- 27017:27017
86-
####################
87-
## -- DEV ONLY -- ## ( FOR NOW )
88-
####################
89-
mongo_ui:
90-
image: mongo-express:latest
91-
environment:
92-
ME_CONFIG_MONGODB_SERVER: mongo
93-
ME_CONFIG_MONGODB_ADMINUSERNAME: root
94-
ME_CONFIG_MONGODB_ADMINPASSWORD_FILE: /run/secrets/mongoPassword
95-
ports:
96-
- 8081:8081
97-
secrets:
98-
- mongoPassword
9990
volumes:
10091
# ignore all css from the docker container and do not mount to my local dir
10192
# This is because the CSS files shouldn't be modified. Only the sass files

docker-compose.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,43 @@ services:
9595
- mongo_volume:/data/db
9696
secrets:
9797
- mongoPassword
98+
mongo_ui:
99+
image: mongo-express:1.0.0-alpha
100+
depends_on:
101+
- mongo
102+
environment:
103+
ME_CONFIG_MONGODB_SERVER: mongo
104+
ME_CONFIG_MONGODB_ADMINUSERNAME: root
105+
ME_CONFIG_MONGODB_ADMINPASSWORD_FILE: /run/secrets/mongoPassword
106+
ME_CONFIG_SITE_BASEURL: /admin/mongo/
107+
ME_CONFIG_OPTIONS_NO_DELETE: "true"
108+
ME_CONFIG_OPTIONS_READONLY: "true"
109+
ME_CONFIG_MONGODB_ENABLE_ADMIN: "true"
110+
secrets:
111+
- mongoPassword
112+
mongo_backup:
113+
image: ghcr.io/amthorn/qutex/qutex_mongo_backup:${QUTEX_VERSION:-latest}
114+
environment:
115+
MONGODB_HOST: mongo
116+
MONGODB_PORT: 27017
117+
MONGODB_USER: root
118+
MONGODB_PASS_FILE: /run/secrets/mongoPassword
119+
CRON_TIME: 0 0 * * *
120+
EXTRA_OPTS: --authenticationDatabase admin --db qutex --gzip --forceTableScan
121+
MAX_BACKUPS: 14
122+
INIT_BACKUP: 1
123+
volumes:
124+
- ./mongo_backups:/backup
125+
secrets:
126+
- mongoPassword
127+
redis_ui:
128+
image: rediscommander/redis-commander
129+
environment:
130+
REDIS_HOST: redis
131+
REDIS_PORT: "6379"
132+
URL_PREFIX: /admin/redis
133+
ports:
134+
- 8081:8081
98135
secrets:
99136
token:
100137
file: secrets/prod/token

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"dependencies": {
33
"eslint": "^7.32.0",
4-
"qutex_web": "file:services/ui"
4+
"qutex_web": "file:services/ui",
5+
"react-dotenv": "^0.1.3"
56
}
67
}

services/_api_service_template/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM python:3.9-alpine
1+
FROM python:3.10-alpine
22
LABEL MAINTAINER="Ava Thorn" EMAIL="[email protected]"
33
ARG SERVICE_PREFIX
44

services/_api_service_template/src/main.py

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
app.config['SERVICE_PREFIX'] = os.environ.get('SERVICE_PREFIX')
1414
app.config['AUTH_SERVICE_TOKEN_CHECK_ROUTE'] = os.environ['AUTH_SERVICE_TOKEN_CHECK_ROUTE']
1515
app.config['AUTH_SERVICE_HOST'] = os.environ['AUTH_SERVICE_HOST']
16+
app.config['SUPER_ADMINS'] = json.loads(os.environ['SUPER_ADMINS'])
1617
app.config['TOKEN_COOKIE_NAME'] = 'qutexToken'
1718
app.config['FQDN'] = os.environ.get('FQDN', 'http://localhost')
1819
app.config['DEFAULT_PAGE_LENGTH'] = 50
@@ -22,11 +23,12 @@
2223

2324

2425
class CustomJSONEncoder(flask.json.JSONEncoder):
25-
def default(self, o):
26+
def default(self, o: object) -> str:
2627
if isinstance(o, ObjectId):
2728
return str(o)
2829
return super().default(o)
2930

31+
3032
app.config["RESTX_JSON"] = {"cls": CustomJSONEncoder}
3133

3234
########################
@@ -35,34 +37,33 @@ def default(self, o):
3537
try:
3638
with open('/run/secrets/privateKey') as f:
3739
app.secret_key = f.read()
38-
except Exception as e:
40+
except Exception:
3941
print("WARNING: No privateKey secret provided for Flask application")
4042

4143
try:
4244
with open('/run/secrets/token') as f:
4345
app.config['WEBEX_TEAMS_ACCESS_TOKEN'] = f.read().strip()
44-
except Exception as e:
46+
except Exception:
4547
print("WARNING: No webex teams access token provided for Flask application")
4648

4749
try:
4850
with open('/run/secrets/mongoPassword') as f:
4951
app.config['MONGO_PASSWORD'] = f.read()
50-
except Exception as e:
52+
except Exception:
5153
print("WARNING: No mongo password provided for Flask application")
5254

5355
##########
5456
# MODELS #
5557
##########
56-
import setup_db
58+
import setup_db # noqa
5759

5860
##########
5961
# APIS #
6062
##########
6163
from setup_api import v1 # noqa
6264

63-
64-
import documents
65-
import api
65+
import documents # noqa
66+
import api # noqa
6667

6768

6869
@v1.errorhandler(Exception)
@@ -73,16 +74,24 @@ def handle_exception(e: Exception) -> flask.Response:
7374
return dump_data(e, flask.make_response(), e.messages, 422)
7475
elif isinstance(e, werkzeug.exceptions.Unauthorized):
7576
response = dump_data(e, e.get_response(), {e.name: e.description}, e.code)
76-
return response[0], response[1], {**response[2], 'Set-Cookie': f'{app.config.get("TOKEN_COOKIE_NAME")}=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT'}
77+
return response[0], response[1], {
78+
**response[2],
79+
'Set-Cookie': app.config.get("TOKEN_COOKIE_NAME") +
80+
'=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT'
81+
}
7782
elif isinstance(e, werkzeug.exceptions.HTTPException):
7883
return dump_data(e, e.get_response(), {e.name: e.description}, e.code)
7984
return dump_data(e, flask.make_response(), {str(e.__class__.__name__): str(e)}, 500)
8085

8186

8287
@app.before_request
83-
def authenticate():
88+
def authenticate() -> None:
8489
# if its not an unauthenticated route
85-
if not flask.request.path.startswith('/api/v1/auth/') and not flask.request.path.endswith('/healthcheck'):
90+
unauthenticated = [
91+
'/api/v1/auth/',
92+
'healthcheck'
93+
]
94+
if not any([flask.request.path.startswith(i) for i in unauthenticated]):
8695
# Will throw 401 if not authenticated
8796
result = requests.get(
8897
f"{app.config['AUTH_SERVICE_HOST']}/api/v1/auth/token/check",
Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import json
2-
31
from app import app
42
from flask_mongoengine import MongoEngine
53

@@ -10,16 +8,12 @@
108
db = MongoEngine(app)
119
app.db = db
1210

13-
class SerializerMixin:
14-
def as_dict(self):
15-
ugly = json.loads(self.to_json())
16-
1711

1812
class TimestampMixin():
1913
created_at = db.DateTimeField(auto_now_add=True, auto_now=False)
2014
updated_at = db.DateTimeField(auto_now_add=False, auto_now=True)
2115
deleted_at = db.DateTimeField(required=False)
2216

2317

24-
class BaseMixin(TimestampMixin, SerializerMixin):
18+
class BaseMixin(TimestampMixin):
2519
id = db.StringField(primary_key=True)

services/auth/api/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
from api import v1
1+
from api import v1 # noqa

services/auth/api/v1/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
from api.v1 import auth
2-
from api.v1 import token
1+
from api.v1 import auth # noqa
2+
from api.v1 import token # noqa

services/auth/api/v1/auth/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
from api.v1.auth import login
2-
from api.v1.auth import logout
3-
from api.v1.auth import register
1+
from api.v1.auth import login # noqa
2+
from api.v1.auth import logout # noqa
3+
from api.v1.auth import register # noqa

services/auth/api/v1/auth/login.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
from app import app
22
from setup_api import v1
33

4-
from blacklist_handler import BlacklistHandler
54
from encoder import JWTEncoder
65
from flask import jsonify, request
7-
from flask_restx import Api, Resource
6+
from flask_restx import Resource
87
from marshmallow import Schema, fields
98
from documents.person import PersonDocument
109
from werkzeug.exceptions import Unauthorized
11-
from typing import Union
1210

1311

1412
class LoginSchema(Schema):
@@ -25,6 +23,7 @@ def post(self) -> dict[str, dict[str, str]]:
2523
if not user or user.passwordHash != PersonDocument._hash(data['password']):
2624
raise Unauthorized('Username or password incorrect')
2725
else:
26+
# TODO: roles?
2827
token = JWTEncoder().encode(userId=user.id)
2928
response = jsonify({
3029
'data': {'token': token},

0 commit comments

Comments
 (0)