,
- },{
+ },
+ {
path: "data-sources",
element:
,
},
@@ -56,6 +58,10 @@ const routes = [
path: "feedback",
element:
,
},
+ {
+ path: "adminportal",
+ element:
,
+ },
];
export default routes;
diff --git a/frontend/src/services/actions/types.tsx b/frontend/src/services/actions/types.tsx
index 5867c811..add0dad9 100644
--- a/frontend/src/services/actions/types.tsx
+++ b/frontend/src/services/actions/types.tsx
@@ -22,5 +22,6 @@ export interface RootState {
auth: {
error: any;
isAuthenticated: boolean;
+ isSuperuser: boolean;
};
}
diff --git a/frontend/src/services/reducers/auth.ts b/frontend/src/services/reducers/auth.ts
index 2566194f..5b4fbea9 100644
--- a/frontend/src/services/reducers/auth.ts
+++ b/frontend/src/services/reducers/auth.ts
@@ -1,3 +1,4 @@
+import { jwtDecode } from 'jwt-decode';
import {
LOGIN_SUCCESS,
LOGIN_FAIL,
@@ -21,6 +22,10 @@ import {
} from '../actions/types';
+type TokenClaims = {
+ is_superuser: boolean;
+};
+
type ActionType =
| { type: typeof LOGIN_SUCCESS; payload: { access: string; refresh: string } }
| { type: typeof LOGIN_FAIL; payload: string }
@@ -49,6 +54,7 @@ export interface StateType {
isAuthenticated: boolean | null;
user: string; //
error?: string | null;
+ isSuperuser: boolean | null;
}
// Initial state with correct types
@@ -56,6 +62,7 @@ const initialState: StateType = {
access: localStorage.getItem('access'),
refresh: localStorage.getItem('refresh'),
isAuthenticated: null,
+ isSuperuser: null,
user: ""
};
@@ -68,15 +75,18 @@ export default function authReducer(state = initialState, action: ActionType): S
}
case LOGIN_SUCCESS:
case GOOGLE_AUTH_SUCCESS:
- case FACEBOOK_AUTH_SUCCESS:
+ case FACEBOOK_AUTH_SUCCESS:{
localStorage.setItem('access', action.payload.access);
localStorage.setItem('refresh', action.payload.refresh);
+ const decoded: TokenClaims = jwtDecode(action.payload.access);
return {
...state,
isAuthenticated: true,
access: action.payload.access,
- refresh: action.payload.refresh
- }
+ refresh: action.payload.refresh,
+ isSuperuser: decoded.is_superuser
+ };
+ }
case SIGNUP_SUCCESS:
return {
...state,
diff --git a/frontend/src/services/store.tsx b/frontend/src/services/store.tsx
index 8adca99a..8b48d449 100644
--- a/frontend/src/services/store.tsx
+++ b/frontend/src/services/store.tsx
@@ -1,5 +1,5 @@
import { applyMiddleware } from "redux";
-import { composeWithDevTools } from "redux-devtools-extension";
+import { composeWithDevTools } from "@redux-devtools/extension";
import thunk from "redux-thunk";
import rootReducer from "./reducers";
import { legacy_createStore as createStore } from "redux";
diff --git a/server/Dockerfile.dev b/server/Dockerfile.dev
index 6659d362..a3c280eb 100644
--- a/server/Dockerfile.dev
+++ b/server/Dockerfile.dev
@@ -4,7 +4,7 @@
FROM python:3.11.4-slim-buster
# set work directory
-WORKDIR /usr/src/app
+WORKDIR /usr/src/server
# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
@@ -19,13 +19,10 @@ COPY ./requirements.txt .
RUN pip install -r requirements.txt
# copy project
-COPY . .
+COPY . /usr/src/app
# Correct line endings in entrypoint.sh and make it executable
-RUN sed -i 's/\r$//' entrypoint.sh && chmod +x entrypoint.sh
+RUN sed -i 's/\r$//' /usr/src/app/entrypoint.sh && chmod +x /usr/src/app/entrypoint.sh
# run entrypoint.sh
-ENTRYPOINT ["./entrypoint.sh"]
-
-# Default command to run on container start
-CMD ["python", "manage.py", "runserver", "0.0.0.0:8000", "--noreload"]
+ENTRYPOINT ["/usr/src/app/entrypoint.sh"]
diff --git a/server/Dockerfile.prodBackup b/server/Dockerfile.prodBackup
new file mode 100644
index 00000000..9c5244c6
--- /dev/null
+++ b/server/Dockerfile.prodBackup
@@ -0,0 +1,71 @@
+###########
+# BUILDER #
+###########
+
+# pull official base image
+FROM python:3.11.4-slim-buster as builder
+
+# set work directory
+WORKDIR /usr/src/app
+
+# set environment variables
+ENV PYTHONDONTWRITEBYTECODE 1
+ENV PYTHONUNBUFFERED 1
+
+# install system dependencies
+RUN apt-get update && \
+ apt-get install -y --no-install-recommends gcc
+
+# lint
+# RUN pip install --upgrade pip
+# RUN pip install flake8==6.0.0
+# COPY . /usr/src/app/
+# RUN flake8 --ignore=E501,F401 .
+
+# install python dependencies
+COPY ./requirements.txt .
+RUN pip wheel --no-cache-dir --no-deps --wheel-dir /usr/src/app/wheels -r requirements.txt
+
+
+#########
+# FINAL #
+#########
+
+# pull official base image
+FROM python:3.11.4-slim-buster
+
+# create directory for the app user
+RUN mkdir -p /home/app
+
+# create the app user
+RUN addgroup --system app && adduser --system --group app
+
+# create the appropriate directories
+ENV HOME=/home/app
+ENV APP_HOME=/home/app/web
+RUN mkdir $APP_HOME
+WORKDIR $APP_HOME
+
+# install dependencies
+RUN apt-get update && apt-get install -y --no-install-recommends netcat
+COPY --from=builder /usr/src/app/wheels /wheels
+COPY --from=builder /usr/src/app/requirements.txt .
+RUN pip install --upgrade pip
+RUN pip install --no-cache /wheels/*
+
+# copy entrypoint.prod.sh
+COPY ./entrypoint.prod.sh .
+RUN sed -i 's/\r$//g' $APP_HOME/entrypoint.prod.sh
+RUN chmod +x $APP_HOME/entrypoint.prod.sh
+
+# copy project
+COPY . $APP_HOME
+
+# chown all the files to the app user
+RUN chown -R app:app $APP_HOME
+
+# change to the app user
+USER app
+
+# run entrypoint.prod.sh
+ENTRYPOINT ["/home/app/web/entrypoint.prod.sh"]
\ No newline at end of file
diff --git a/server/api/admin.py b/server/api/admin.py
index 3c91cf73..b85f6ab9 100644
--- a/server/api/admin.py
+++ b/server/api/admin.py
@@ -1,6 +1,7 @@
from django.contrib import admin
from .views.uploadFile.models import UploadFile
from .views.listMeds.models import StateMedication
+from .models.authUser import UserAccount
@admin.register(StateMedication)
@@ -11,3 +12,8 @@ class StateMedicationAdmin(admin.ModelAdmin):
@admin.register(UploadFile)
class UploadFile(admin.ModelAdmin):
list_display = ['guid', 'file_name', 'file']
+
+
+@admin.register(UserAccount)
+class UserAccountAdmin(admin.ModelAdmin):
+ list_display = ['id', 'first_name', 'email', 'is_superuser']
diff --git a/server/api/migrations/0002_alter_uploadfile_file.py b/server/api/migrations/0002_alter_uploadfile_file.py
new file mode 100644
index 00000000..4b678383
--- /dev/null
+++ b/server/api/migrations/0002_alter_uploadfile_file.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.2.3 on 2024-03-09 20:37
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('api', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='uploadfile',
+ name='file',
+ field=models.BinaryField(null=True),
+ ),
+ ]
diff --git a/server/api/models/TokenObtainPairSerializer.py b/server/api/models/TokenObtainPairSerializer.py
new file mode 100644
index 00000000..6b514202
--- /dev/null
+++ b/server/api/models/TokenObtainPairSerializer.py
@@ -0,0 +1,10 @@
+from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
+
+
+class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
+ @classmethod
+ def get_token(cls, user):
+ token = super(MyTokenObtainPairSerializer, cls).get_token(user)
+ # Add custom claims
+ token['is_superuser'] = user.is_superuser
+ return token
diff --git a/server/api/views/uploadFile/urls.py b/server/api/views/uploadFile/urls.py
index 385e8cb1..e36dd8c6 100644
--- a/server/api/views/uploadFile/urls.py
+++ b/server/api/views/uploadFile/urls.py
@@ -2,5 +2,5 @@
from api.views.uploadFile import views
urlpatterns = [
- path("chatgpt/uploadFile", views.uploadFiles, name="uploadFile")
+ path("chatgpt/uploadFile", views.uploadFiles, name="uploadFiles")
]
diff --git a/server/api/views/uploadFile/views.py b/server/api/views/uploadFile/views.py
index 1be42195..17e00f25 100644
--- a/server/api/views/uploadFile/views.py
+++ b/server/api/views/uploadFile/views.py
@@ -15,12 +15,12 @@ def uploadFiles(request):
# Read file contents in binary mode
file_contents = file.read()
-
+ print(file.read())
# Use the original file name
file_name = file.name
# Create an instance of the model
- upload_file = UploadFile(file_name=file_name, file_data=file_contents)
+ upload_file = UploadFile(file_name=file_name, file=file_contents)
# Save the instance to the database
try:
diff --git a/server/balancer_backend/settings.py b/server/balancer_backend/settings.py
index 41b660e9..13988358 100644
--- a/server/balancer_backend/settings.py
+++ b/server/balancer_backend/settings.py
@@ -113,8 +113,8 @@
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
-EMAIL_HOST_USER = 'tyc50ff@gmail.com'
-EMAIL_HOST_PASSWORD = 'uvherhprtetbkzzn'
+EMAIL_HOST_USER = os.environ.get("EMAIL_HOST_USER", "")
+EMAIL_HOST_PASSWORD = os.environ.get("EMAIL_HOST_PASSWORD", "")
EMAIL_USE_TLS = True
@@ -171,6 +171,7 @@
'AUTH_HEADER_TYPES': ('JWT',),
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60),
'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
+ 'TOKEN_OBTAIN_SERIALIZER': 'api.models.TokenObtainPairSerializer.MyTokenObtainPairSerializer',
'AUTH_TOKEN_CLASSES': (
'rest_framework_simplejwt.tokens.AccessToken',
)
diff --git a/server/balancer_backend/urls.py b/server/balancer_backend/urls.py
index aee2dae3..7bec66dc 100644
--- a/server/balancer_backend/urls.py
+++ b/server/balancer_backend/urls.py
@@ -18,7 +18,7 @@
]
# List of application names for which URL patterns will be dynamically added
-urls = ['chatgpt', 'jira', 'listDrugs', 'listMeds', 'risk']
+urls = ['chatgpt', 'jira', 'listDrugs', 'listMeds', 'risk', 'uploadFile']
# Loop through each application name and dynamically import and add its URL patterns
for url in urls: