diff --git a/BACKEND/app/auth.py b/BACKEND/app/auth.py
new file mode 100644
index 0000000..11091b7
--- /dev/null
+++ b/BACKEND/app/auth.py
@@ -0,0 +1,68 @@
+from fastapi import HTTPException, status, Request
+from fastapi.security import OAuth2PasswordBearer
+from functools import wraps
+import requests
+
+oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
+
+GITEA_API_URL = "http://localhost:3000/api/v1"
+
+def validate_token(func):
+ @wraps(func)
+ async def wrapper(*args, **kwargs):
+ request = None
+ for arg in args:
+ if isinstance(arg, Request):
+ request = arg
+ break
+
+ if request is None:
+ for key, value in kwargs.items():
+ if isinstance(value, Request):
+ request = value
+ break
+
+ if request is None:
+ raise HTTPException(
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
+ detail="Request object not found",
+ )
+
+ auth_header = request.headers.get("Authorization")
+ if not auth_header or not auth_header.startswith("Bearer "):
+ raise HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Missing or invalid authorization header"
+ )
+ token = auth_header.replace("Bearer ", "")
+
+ try:
+ headers = {"Authorization": f"{token}"}
+ response = requests.get(f"{GITEA_API_URL}/user", headers=headers)
+
+
+ if response.status_code == 401:
+ raise HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Token expired or invalid"
+ )
+ elif response.status_code != 200:
+ raise HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Authentication failed"
+ )
+
+ if "user_info" in kwargs:
+ user_info = response.json()
+ kwargs["user_info"] = user_info
+ return await func(*args, **kwargs)
+
+ except Exception as e:
+ if isinstance(e, HTTPException):
+ raise e
+ raise HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Invalid authentication credentials"
+ )
+
+ return wrapper
\ No newline at end of file
diff --git a/BACKEND/app/crud.py b/BACKEND/app/crud.py
index 04508ad..4fe4690 100644
--- a/BACKEND/app/crud.py
+++ b/BACKEND/app/crud.py
@@ -46,11 +46,15 @@ def parse_usfm_to_csv(book_name, usfm_content, project_id):
""" Convert USFM content to CSV format and return extracted data """
try:
my_parser = USFMParser(usfm_content) # Initialize parser
- output = my_parser.to_list(include_markers=Filter.BCV + Filter.TEXT) # Extract BCV and Text
+ output = my_parser.to_list(include_markers=Filter.BCV + Filter.TEXT) # Extract BCV and Text
processed_output = [
- [re.sub(r"\s+", " ", value).strip() if isinstance(value, str) else value for value in row]
- for row in output
- ]
+ [normalize_text(value).replace("\n", " ") if isinstance(value, str) else value for value in row]
+ for row in output]
+ # processed_output = [
+ # [re.sub(r"\s+", " ", value).strip() if isinstance(value, str) else value for value in row]
+ # for row in output
+ # ]
+
if not processed_output:
logging.error(f"No data extracted for {book_name}!")
else:
diff --git a/BACKEND/app/router.py b/BACKEND/app/router.py
index 75338cf..cef5e5d 100644
--- a/BACKEND/app/router.py
+++ b/BACKEND/app/router.py
@@ -1,5 +1,5 @@
import itertools
-from fastapi import APIRouter, HTTPException,File,UploadFile,Query
+from fastapi import APIRouter, HTTPException,File,UploadFile,Query, Request, Depends
from fastapi import Body
from pydantic import BaseModel
from database import SessionLocal
@@ -14,6 +14,8 @@
import crud
from fastapi.responses import JSONResponse
import base64
+from auth import validate_token
+from utils import input_token
@@ -35,10 +37,11 @@ class USFMUploadRequest(BaseModel):
@router.post("/add_project/")
-async def add_project(request: ProjectRequest):
+@validate_token
+async def add_project(request: Request, project_request: ProjectRequest, user_details=Depends(input_token)):
""" Add a new project and return the project ID """
session = SessionLocal()
- project_name = request.project_name.strip()
+ project_name = project_request.project_name.strip()
# Validate project name (Ensure it's not empty after trimming)
if not project_name:
@@ -47,7 +50,7 @@ async def add_project(request: ProjectRequest):
# Check if the project already exists
existing_project = session.query(Project).filter_by(
- project_name=request.project_name
+ project_name=project_request.project_name
).first()
if existing_project:
@@ -56,7 +59,7 @@ async def add_project(request: ProjectRequest):
# Insert new project
new_project = Project(
- project_name=request.project_name
+ project_name=project_request.project_name
)
session.add(new_project)
session.commit()
@@ -69,13 +72,19 @@ async def add_project(request: ProjectRequest):
@router.get("/list_projects/")
-async def list_projects(project_name: str = Query(None)):
+@validate_token
+async def list_projects(request: Request, project_name: str = Query(None),
+ user_details=Depends(input_token)):
"""
List all projects or fetch a specific project by project_name.
If project_name is provided, returns the matching project or null if not found.
"""
session = SessionLocal()
try:
+
+ # username = user_info.get("login")
+ # print(f"User {username} is fetching projects")
+
if project_name:
project = session.query(Project).filter(Project.project_name == project_name).first()
return {"project": project if project else None}
@@ -95,8 +104,9 @@ async def list_projects(project_name: str = Query(None)):
@router.post("/upload_usfm/")
-async def upload_usfm(
- request: USFMUploadRequest
+@validate_token
+async def upload_usfm(request: Request,
+ project_request: USFMUploadRequest, user_details=Depends(input_token)
):
"""
Upload a USFM content as a string, process it, and store data in DB.
@@ -106,9 +116,9 @@ async def upload_usfm(
try:
# Get project_id from project_name
- project_name = request.project_name
- usfm_sha = request.usfm_sha
- encoded_usfm = request.encoded_usfm
+ project_name = project_request.project_name
+ usfm_sha = project_request.usfm_sha
+ encoded_usfm = project_request.encoded_usfm
project_id = crud.get_project_id(session,project_name)
logging.info(f"Processing USFM file for project: {project_name} (Project ID: {project_id})")
@@ -200,17 +210,18 @@ async def upload_usfm(
@router.put("/update_usfm/")
-async def update_usfm(
- request: USFMUploadRequest
+@validate_token
+async def update_usfm(request: Request,
+ project_request: USFMUploadRequest, user_details=Depends(input_token)
):
""" Update an existing USFM file, reprocess it, and update both book and verse tables properly. """
session = SessionLocal()
try:
# Extract values from request body
- project_name = request.project_name
- usfm_sha = request.usfm_sha
- encoded_usfm = request.encoded_usfm
+ project_name = project_request.project_name
+ usfm_sha = project_request.usfm_sha
+ encoded_usfm = project_request.encoded_usfm
# Extract book name from USFM
project_id = crud.get_project_id(session,project_name)
@@ -218,7 +229,8 @@ async def update_usfm(
try:
usfm_bytes = base64.b64decode(encoded_usfm)
usfm = usfm_bytes.decode("utf-8") # Convert bytes to string
- usfm=crud.normalize_text(usfm)
+ #errors are not displaying properly
+ # usfm=crud.normalize_text(usfm)
except Exception as e:
logging.error(f"Failed to decode USFM content: {str(e)}")
raise HTTPException(status_code=400, detail="Invalid encoded USFM content")
@@ -289,7 +301,9 @@ async def update_usfm(
@router.get("/list_books/")
-async def list_books(project_name: str = Query(None)):
+@validate_token
+async def list_books(request: Request,project_name: str = Query(None),
+ user_details=Depends(input_token)):
""" Retrieve all Bibles (projects) along with their books and their status, optionally filtering by project name """
session = SessionLocal()
try:
@@ -328,7 +342,9 @@ async def list_books(project_name: str = Query(None)):
@router.get("/find_missing_verses/")
-async def find_missing_verses(book_name: str, project_name: str):
+@validate_token
+async def find_missing_verses(request: Request,book_name: str, project_name: str,
+ user_details=Depends(input_token)):
"""Find missing verses for a given book_id and project_id by comparing with versification.json."""
session = SessionLocal()
@@ -400,7 +416,9 @@ async def find_missing_verses(book_name: str, project_name: str):
@router.get("/book/usfm/")
-async def get_book_usfm(project_name: str, book_name: str):
+@validate_token
+async def get_book_usfm(request: Request,project_name: str, book_name: str,
+ user_details=Depends(input_token)):
"""
Get the USFM content of a book from the database.
"""
@@ -434,7 +452,9 @@ async def get_book_usfm(project_name: str, book_name: str):
@router.get("/book/json/")
-async def get_book_json(project_name: str, book_name: str):
+@validate_token
+async def get_book_json(request: Request,project_name: str, book_name: str,
+ user_details=Depends(input_token)):
"""
Get the book's content in JSON format.
"""
@@ -476,7 +496,9 @@ async def get_book_json(project_name: str, book_name: str):
@router.get("/chapter/json/")
-async def get_chapter_json(project_name: str, book_name: str, chapter: int):
+@validate_token
+async def get_chapter_json(request: Request,project_name: str, book_name: str,
+ chapter: int, user_details=Depends(input_token)):
"""
Get the chapter's content in JSON format.
"""
@@ -518,8 +540,10 @@ async def get_chapter_json(project_name: str, book_name: str, chapter: int):
@router.get("/book/chapters/")
+@validate_token
# async def get_book_chapters(book_id: int):
-async def get_book_chapters(project_name: str, book_name: str):
+async def get_book_chapters(request: Request, project_name: str, book_name: str,
+ user_details=Depends(input_token)):
"""
Get the list of chapters available in a book.
"""
@@ -554,10 +578,13 @@ async def get_book_chapters(project_name: str, book_name: str):
@router.get("/parallel_corpora/withbcv/")
+@validate_token
async def get_parallel_corpora_withbcv(
+ request: Request,
project_name_1: str,
project_name_2: str,
- response_type: str = Query("csv", description="Set 'json' for JSON response, 'csv' for file download")
+ response_type: str = Query("csv", description="Set 'json' for JSON response, 'csv' for file download"),
+ user_details=Depends(input_token)
):
"""
Generate and return the parallel corpus between two projects (two languages) in CSV or JSON format.
@@ -675,8 +702,12 @@ async def get_parallel_corpora_withbcv(
@router.get("/parallel_corpora/withoutbcv/")
-async def get_parallel_corpora_texts(project_name_1: str, project_name_2: str,
- response_type: str = Query("csv", description="Set 'json' for JSON response, 'csv' for file download")):
+@validate_token
+async def get_parallel_corpora_texts(request: Request,
+ project_name_1: str, project_name_2: str,
+ response_type: str = Query("csv",
+ description="Set 'json' for JSON response, 'csv' for file download"),
+ user_details=Depends(input_token)):
"""
Generate and return the parallel corpus between two projects in CSV format with only Text_1 and Text_2.
"""
diff --git a/BACKEND/app/utils.py b/BACKEND/app/utils.py
new file mode 100644
index 0000000..ac12e97
--- /dev/null
+++ b/BACKEND/app/utils.py
@@ -0,0 +1,9 @@
+from fastapi import Security
+from fastapi.security import HTTPBearer
+
+oauth2_scheme = HTTPBearer()
+
+async def input_token(token: str = Security(oauth2_scheme)):
+ '''Function to validate API key, currently only for swagger to have a token input'''
+ user_token = {"token": token}
+ return user_token
diff --git a/BACKEND/requirements.txt b/BACKEND/requirements.txt
index b495fb9..87d6a41 100644
--- a/BACKEND/requirements.txt
+++ b/BACKEND/requirements.txt
@@ -4,4 +4,5 @@ SQLAlchemy
psycopg2
uvicorn
python-multipart
-sacremoses
\ No newline at end of file
+sacremoses
+requests
\ No newline at end of file
diff --git a/UI/.dockerignore b/UI/.dockerignore
new file mode 100644
index 0000000..329d75c
--- /dev/null
+++ b/UI/.dockerignore
@@ -0,0 +1,2 @@
+node_modules
+.env.local
\ No newline at end of file
diff --git a/UI/Dockerfile b/UI/Dockerfile
new file mode 100644
index 0000000..2dbdc74
--- /dev/null
+++ b/UI/Dockerfile
@@ -0,0 +1,15 @@
+FROM node:18-alpine
+
+WORKDIR /app
+
+COPY package*.json ./
+
+RUN npm install
+
+COPY . .
+
+RUN npm run build
+
+EXPOSE 3001
+
+CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]
\ No newline at end of file
diff --git a/UI/src/pages/CreateRepo.tsx b/UI/src/pages/CreateRepo.tsx
index d5be625..9d72089 100644
--- a/UI/src/pages/CreateRepo.tsx
+++ b/UI/src/pages/CreateRepo.tsx
@@ -22,9 +22,8 @@ import { useNavigate } from "react-router-dom";
import FeedbackDialog from "@/components/FeedbackDialog";
import { useStore } from "@/stores/Store";
import MultiSelect from "@/components/MultiSelect";
-import { API } from "@/services/Api";
+import { API, FastAPI } from "@/services/Api";
import { useAppEffects } from "@/hooks/UseAppEffects";
-import axios from "axios";
interface Option {
value: string;
@@ -199,20 +198,38 @@ const CreateRepo: React.FC = () => {
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
+ let giteaRepoCreated = false;
+
try {
+ // Step 1: Create repo in Gitea
const orgRepoData = {
org: "BCS",
name: formData.projectName,
private: formData.isPrivate,
description: formData.description,
};
+
const topics = [
...selectedOptions.map((option) => option.value),
formData.language,
];
+
await postCreateRepoInOrg(orgRepoData, orgRepoData.org);
+ giteaRepoCreated = true;
+
await postCreateRepoCatalogue(topics, formData.projectName);
+
+ // Step 2: Create project in FastAPI if applicable
+ if (selectedOptions[0]?.value === "bible") {
+ console.log("Executing add_project endpoint");
+ const response = await FastAPI.post("/add_project", {
+ project_name: formData.projectName,
+ });
+ console.log("Response from add_project endpoint:", response);
+ }
+
await fetchHomePageData();
+
setDialogState({
isOpen: true,
title: "Success",
@@ -220,27 +237,12 @@ const CreateRepo: React.FC = () => {
isError: false,
type: "project",
});
-
- //hackathon
- if (selectedOptions[0]?.value === "bible") {
- console.log("Executing add_project endpoint");
- const response = await axios.post(
- `${import.meta.env.VITE_FASTAPI_BASE_URL}/add_project`,
- {
- project_name: formData.projectName,
- }
- );
- console.log("Response from add_project endpoint:", response);
- }
- //hackathon
-
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
console.log("Error details:", error);
let errorMessage = "Failed to create Project. Please try again.";
+ let errorTitle = "Error";
- console.log("Error details:", error.status);
// Check for error status
if (error.status === 409) {
errorMessage = "A project with this name already exists.";
@@ -251,16 +253,22 @@ const CreateRepo: React.FC = () => {
"Failed to create Project. Please try again.";
}
+ // Handle the case where Gitea repo was created but FastAPI project creation failed
+ if (giteaRepoCreated && selectedOptions[0]?.value === "bible") {
+ errorTitle = "Partial Success";
+ errorMessage =
+ "The repository was created successfully, but we couldn't create the associated project in the system. Please try adding the project manually or contact support.";
+ }
+
setDialogState({
isOpen: true,
- title: "Error",
+ title: errorTitle,
message: errorMessage,
isError: true,
type: "project",
});
}
};
-
const handleDialogClose = () => {
const { isError, type } = dialogState;
@@ -272,8 +280,19 @@ const CreateRepo: React.FC = () => {
}));
// Only navigate to /repo for successful project creation
- if (!isError && type === "project") {
- navigate("/repo");
+ if (
+ (!isError && type === "project") ||
+ (isError && dialogState.title === "Partial Success")
+ ) {
+ // For partial success, fetch the data before navigating
+ if (isError && dialogState.title === "Partial Success") {
+ fetchHomePageData().then(() => {
+ navigate("/repo");
+ });
+ } else {
+ // For complete success, data is already fetched
+ navigate("/repo");
+ }
}
};
diff --git a/UI/src/pages/ViewFile.tsx b/UI/src/pages/ViewFile.tsx
index eb26be0..7d8c09a 100644
--- a/UI/src/pages/ViewFile.tsx
+++ b/UI/src/pages/ViewFile.tsx
@@ -53,8 +53,10 @@ export const ViewFile: React.FC = () => {
: (fileContent.size / 1024).toFixed(2) + " KB";
// Determine whether "Copy" and "Lines" are enabled
- const isCopyEnabled = ["txt", "md", "usfm", "csv"].includes(fileExtension);
- const isLineEnabled = ["txt", "pdf", "md", "usfm", "csv"].includes(
+ const isCopyEnabled = ["txt", "md", "usfm", "sfm", "csv"].includes(
+ fileExtension
+ );
+ const isLineEnabled = ["txt", "pdf", "md", "usfm", "sfm", "csv"].includes(
fileExtension
);
const isDownloadEnabled = ["pdf"].includes(fileExtension);
@@ -187,10 +189,13 @@ export const ViewFile: React.FC = () => {
);
- } else if (["txt", "usfm", "json"].includes(fileExtension)) {
+ } else if (["txt", "usfm", "sfm", "json"].includes(fileExtension)) {
return (
{
const fetchListBibles = async (repo: string, selectedRepo: string) => {
try {
- const response = await axios.get(
- `${import.meta.env.VITE_FASTAPI_BASE_URL}/list_books/?project_name=${selectedRepo}`
+ const response = await FastAPI.get(
+ `/list_books/?project_name=${selectedRepo}`
);
-
// Handle different response scenarios
if (repo === "repo1") {
// Get the bibles array or default to empty array
const bibles = response?.data?.bibles || [];
// Calculate the total successful books across all bibles
- const successfulBooksCount = bibles.reduce((total, bible) => {
+ const successfulBooksCount = bibles.reduce((total: any, bible: any) => {
// Check if bible has books array
if (bible.books && Array.isArray(bible.books)) {
// Count only the books with status "success"
const successfulBooks = bible.books.filter(
- (book) => book.status === "success"
+ (book: any) => book.status === "success"
);
return total + successfulBooks.length;
}
@@ -133,10 +131,10 @@ const ParallelCorpora: React.FC = () => {
// Same logic for repo2
const bibles = response?.data?.bibles || [];
- const successfulBooksCount = bibles.reduce((total, bible) => {
+ const successfulBooksCount = bibles.reduce((total: any, bible: any) => {
if (bible.books && Array.isArray(bible.books)) {
const successfulBooks = bible.books.filter(
- (book) => book.status === "success"
+ (book: any) => book.status === "success"
);
return total + successfulBooks.length;
}
@@ -175,11 +173,11 @@ const ParallelCorpora: React.FC = () => {
try {
// Determine which API endpoint to use based on withBCV
const apiEndpoint = withBCV
- ? `${import.meta.env.VITE_FASTAPI_BASE_URL}/parallel_corpora/withbcv/csv/`
- : `${import.meta.env.VITE_FASTAPI_BASE_URL}/parallel_corpora/withoutbcv/csv/`;
+ ? `/parallel_corpora/withbcv/`
+ : `/parallel_corpora/withoutbcv/`;
// Make the API call
- const response = await axios.get(apiEndpoint, {
+ const response = await FastAPI.get(apiEndpoint, {
params: {
project_name_1: selectedProject1,
project_name_2: selectedProject2,
@@ -193,12 +191,14 @@ const ParallelCorpora: React.FC = () => {
// Create a link element and trigger download
const link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
- const fileName = withBCV ? `parallel_corpora_BCV_${selectedProject1}_${selectedProject2}.csv`: `parallel_corpora_${selectedProject1}_${selectedProject2}.csv`;
+ const fileName = withBCV
+ ? `parallel_corpora_BCV_${selectedProject1}_${selectedProject2}.csv`
+ : `parallel_corpora_${selectedProject1}_${selectedProject2}.csv`;
link.download = fileName;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
- } catch (error) {
+ } catch (error: any) {
console.error("Error downloading CSV:", error);
toast({
variant: "destructive",
@@ -252,7 +252,7 @@ const ParallelCorpora: React.FC = () => {
handleSelectValueChange("repo2", value)
}
options={projects.filter(
- (project) => project.name !== selectedProject1
+ (project: any) => project.name !== selectedProject1
)}
placeholder="Select target project"
/>
diff --git a/UI/src/pages/data-preprocessing/ParseBooks.tsx b/UI/src/pages/data-preprocessing/ParseBooks.tsx
index dea8874..80fe9a1 100644
--- a/UI/src/pages/data-preprocessing/ParseBooks.tsx
+++ b/UI/src/pages/data-preprocessing/ParseBooks.tsx
@@ -1,6 +1,5 @@
import { Button } from "@/components/ui/button";
-import { API } from "@/services/Api";
-import axios from "axios";
+import { API, FastAPI } from "@/services/Api";
import { useState } from "react";
import { Dialog, DialogContent, DialogFooter } from "@/components/ui/dialog";
@@ -28,9 +27,7 @@ const ParseBooks = ({ owner, repo }: ParseBooksProps) => {
const fetchListBibles = async () => {
try {
- const response = await axios.get(
- `${import.meta.env.VITE_FASTAPI_BASE_URL}/list_books/?project_name=${repo}`
- );
+ const response = await FastAPI.get(`/list_books/?project_name=${repo}`);
const fetchedBooks = response?.data?.bibles[0]?.books || [];
return fetchedBooks;
} catch (error) {
@@ -46,8 +43,9 @@ const ParseBooks = ({ owner, repo }: ParseBooksProps) => {
const responseData = contentResponse.data.content;
if (responseData) {
try {
- const uploadResponse = await axios[method](
- `${import.meta.env.VITE_FASTAPI_BASE_URL}/${method === "post" ? "upload_usfm" : "update_usfm"}`,
+ const uploadResponse = await FastAPI[method](
+ `/${method === "post" ? "upload_usfm" : "update_usfm"}`,
+
{
project_name: repo,
usfm_sha: contentResponse?.data?.sha,
@@ -89,8 +87,9 @@ const ParseBooks = ({ owner, repo }: ParseBooksProps) => {
const filesResponse = await API.get(
`/api/v1/repos/${owner}/${repo}/contents/`
);
- const usfmFiles = filesResponse.data.filter((file: { name: string }) =>
- file.name.endsWith(".usfm")
+ const usfmFiles = filesResponse.data.filter(
+ (file: { name: string }) =>
+ file.name.endsWith(".usfm") || file.name.endsWith(".SFM")
);
setUsfmCount(usfmFiles.length);
if (usfmFiles.length === 0) return;
diff --git a/UI/src/services/Api.ts b/UI/src/services/Api.ts
index 63eb330..0419644 100644
--- a/UI/src/services/Api.ts
+++ b/UI/src/services/Api.ts
@@ -11,6 +11,16 @@ export const setHeader = (access_token: string | null) => {
API.defaults.headers.common["Authorization"] = `token ${access_token}`;
};
+const FastAPIBaseURL = import.meta.env.VITE_FASTAPI_BASE_URL as string;
+
+export const FastAPI = axios.create({
+ baseURL: FastAPIBaseURL,
+})
+
+export const setFastAPIHeader = (access_token: string | null) => {
+ FastAPI.defaults.headers.common["Authorization"] = `Bearer token ${access_token}`;
+};
+
/**
* Axios instance for making authenticated requests.
*/
diff --git a/UI/src/stores/Store.ts b/UI/src/stores/Store.ts
index 2b65e42..98899e4 100644
--- a/UI/src/stores/Store.ts
+++ b/UI/src/stores/Store.ts
@@ -1,4 +1,4 @@
-import { apiService, setHeader } from "@/services/Api";
+import { apiService, setFastAPIHeader, setHeader } from "@/services/Api";
import { setupTokenRefresh } from "@/utils/refreshToken";
import { create } from "zustand";
import { createJSONStorage, persist } from "zustand/middleware";
@@ -176,6 +176,7 @@ export const useStore = create()(
set({ access_token, refresh_token, expires_in });
set({ oauth_state: null });
setHeader(access_token);
+ setFastAPIHeader(access_token);
setupTokenRefresh(expires_in);
// Initialize repository after token is set
diff --git a/docker/Readme.md b/docker/Readme.md
new file mode 100644
index 0000000..cf7e0b5
--- /dev/null
+++ b/docker/Readme.md
@@ -0,0 +1,57 @@
+# Gitea Docker Setup Guide
+
+## Introduction
+
+This guide will help you set up Gitea using Docker. Gitea is a lightweight Git service that can be self-hosted. This guide assumes you have Docker and Docker Compose installed on your system.
+
+## Prerequisites
+
+- Docker
+- Docker Compose
+
+## Steps to Install Gitea
+
+1. **Clone the Repository**
+ Clone the repository containing the Docker Compose file and other necessary configurations.
+
+ ```sh
+ git clone https://github.com/Bridgeconn/ai_mft_data_preprocessing.git
+ cd ai_mft_data_preprocessing
+ ```
+
+2. **Run Docker Compose**
+ Start the Gitea service using Docker Compose.
+
+ ```sh
+ cd docker
+ docker compose up -d
+ ```
+
+3. **Initial Setup of Gitea**
+ When you first boot the Gitea image, you will be prompted to configure the database. Since the database configuration is already included in the Docker Compose file, you can proceed with the following steps:
+
+ - **Database Configuration**: This step will be pre-configured based on your Docker Compose settings.
+ - **SMTP Configuration**: You can skip this step if you do not need email notifications.
+ - **Root Admin Creation**: This can be done later when you create the first user.
+
+4. **Complete Installation**
+ Click the "Install" button to complete the setup. Gitea will now be running.
+
+5. **Accessing the Gitea**
+ Open your web browser and navigate to the URL where Gitea is hosted. Refer to the UI documentation for detailed instructions on how to use the Gitea-UI and how you can setup the Oauth configuration.
+
+## Additional Documentation
+
+For more detailed instructions on using the Gitea UI, please refer to the [Gitea UI Documentation](https://github.com/Bridgeconn/ai_mft_data_preprocessing/tree/main/UI/docs/Installation).
+
+## Adding variables
+
+Once you have created a new application for oauth in the gitea, you will be having a `client-id` and `client-secret` . Make sure you add them to our docker compose file. Rest for the variables are already added.
+
+## Note
+
+Once you created the backend(Gitea), create a Organization named `BCS`. and make sure if you are creating repositories in the backend, create under the organization while if you are using the UI , then you dont have to worry on that.
+
+## Conclusion
+
+You have successfully set up Gitea using Docker. You can now start using Gitea for your Git repositories.
diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml
index 0c1fd49..73f4f8a 100644
--- a/docker/docker-compose.yml
+++ b/docker/docker-compose.yml
@@ -40,15 +40,35 @@ services:
- gitea
volumes:
- ./postgres:/var/lib/postgresql/data
+ ui:
+ # image: joeljosephgeorge/gitea-ui:v1.0.3
+ build:
+ context: ../UI
+ dockerfile: Dockerfile
+ healthcheck:
+ timeout: 45s
+ interval: 10s
+ retries: 10
+ container_name: gitea-ui
- #Uncomment the following lines to enable the gitea-ui
- # ui:
- # image: joeljosephgeorge/gitea-ui:v1.0.0
- # container_name: gitea-ui
- # restart: always
- # networks:
- # - gitea
- # ports:
- # - "3001:3001"
- # depends_on:
- # - server
+ # env_file:
+ # - .env.local
+ environment:
+ - VITE_GITEA_BASE_URL=http://localhost:3000
+ - VITE_GITEA_UI_URL=http://localhost:3001
+ - VITE_GITEA_ORG_NAME=BCS
+ - VITE_FASTAPI_BASE_URL=http://localhost:8000
+ #The below values are dummy values, replace them with your own values
+ #the values where not taking when running the api and ui in docker, i could run it by adding
+ #them in the .env.local file and adding the file in the env_file section
+ - VITE_GITEA_CLIENT_ID = {your-client-id}
+ - VITE_GITEA_CLIENT_SECRET = {your-client-secret}
+ - VITE_GITEA_REDIRECT_URI=http://localhost:3001/oauth/callback
+
+ restart: always
+ networks:
+ - gitea
+ ports:
+ - "3001:3001"
+ depends_on:
+ - server
diff --git a/docs/Images/Auth activity diagram.jpeg b/docs/Images/Auth activity diagram.jpeg
new file mode 100644
index 0000000..34f0ca7
Binary files /dev/null and b/docs/Images/Auth activity diagram.jpeg differ
diff --git a/docs/Images/Repo creation diagram.png b/docs/Images/Repo creation diagram.png
new file mode 100644
index 0000000..d8280f5
Binary files /dev/null and b/docs/Images/Repo creation diagram.png differ