diff --git a/README.md b/README.md index 8ae611c..3f76736 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,12 @@ # TekBetter - A better intranet for Epitech +# Table of contents + +#### Setup guide: + +- [Environement variables](#environment-variables) +- [Run in development mode](#run-in-development-mode) + ## Description TekBetter is a project that aims to create a better interface who rassemble all the tools that Epitech students use in @@ -7,9 +14,11 @@ their daily life. ## Environment variables +### Backend (`/.env`) + | Variable | Description | Default value | |----------------------|----------------------------------------------------------------------------|---------------| -| PORT | Port where the server will listen | 3000 | +| PORT | Port where the server will listen | 8080 | | MONGO_HOST | The mongodb database hostname. | mongo | | MONGO_PORT | The mongodb database port. | 27017 | | MONGO_DB | The mongodb database name. | tekbetter | @@ -21,3 +30,96 @@ their daily life. | AES_KEY | The key used to encrypt sensible data in database. 64 bytes long required. | | | SCRAPERS_CONFIG_FILE | The path to the scrapers configuration file. Optional | scrapers.json | | APP_URL | The app url used to send register links by email. | | +| ENABLE_MAILER | Enable the mailer service. | true | + +### Frontend (`/web/.env`) + +| Variable | Description | Default value | +|-------------------|-------------------------|-----------------------------| +| REACT_APP_API_URL | The backend server url. | Auto detect the current url | + +## Run in development mode + +### Setup environment variables + +You can find the front-end react app in the `web/` directory. +You need to define an environment variable `REACT_APP_API_URL` to point to the backend server. + +```dotenv +# web/.env +REACT_APP_API_URL=http://localhost:8080 +``` + +For the backend, you can create a `.env` file in the root directory of the project. +You can find a `/docker-compose.yml` file that will start a mongodb and a redis server. +Create a `scrapers.json` file in the root directory of the project to configure the scrapers, and add the following +content : + +```json +[] +``` + +This is an example `.env` file for the backend with docker-compose usage : + +```dotenv +APP_URL=http://localhost:8080 +JWT_SECRET=my_jwt_secret +AES_KEY=a9421fce83c42eeab1a958c24b516943ccda3e2c4cf6ee3ada4cc78315d228d2 +MONGO_HOST=localhost +REDIS_HOST=localhost +REDIS_PASSWORD=123456 +SCRAPERS_CONFIG_FILE=scrapers.json + +ENABLE_MAILER=false +``` + +### Run the frontend + +Please check that you have `npm` and a recent version of `node` installed on your machine. +Navigate to the `web/` directory and run the following commands : + +```bash +npm install +npm start +``` + +### Run the backend + +Please check that you have `python3` and `pip` installed on your machine. +Go back to the root directory of the project and run the following commands : + +```bash +pip install -r requirements.txt +PYTHONPATH=$(pwd) python3 app/main.py +``` + +#### Happy coding ! + +## How to configure internal scrapers + +An internal scraper is a scraper that will be controlled by the backend. +To configure a scraper, you need to create a `scrapers.json` file in the root directory of the project. + +Here is an example of a scraper configuration : + +```json +[ + { + "id": "paris-01", + "label": "PARIS-01", + "access_token": "choose_a_random_string" + }, + { + "id": "paris-02", + "label": "PARIS-02", + "access_token": "choose_a_random_string" + } +] +``` + +`id` is the unique identifier of the scraper. + +`label` is the name of the scraper. + +`access_token` is a random string that will be used to authenticate the scraper. This access token will be set in the +scraper environment variable `SCRAPER_ACCESS_TOKEN`. \ No newline at end of file diff --git a/app/main.py b/app/main.py index eacc59f..4b7cb56 100644 --- a/app/main.py +++ b/app/main.py @@ -33,7 +33,7 @@ def init_services(): load_env() except Exception as e: log_error(str(e)) - raise + exit(1) # Connect to MongoDB mongo_url = f"mongodb://{os.getenv('MONGO_HOST')}:{os.getenv('MONGO_PORT')}?directConnection=true" diff --git a/app/models/PublicScraper.py b/app/models/PublicScraper.py index 4c3ec3c..afdfca8 100644 --- a/app/models/PublicScraper.py +++ b/app/models/PublicScraper.py @@ -2,14 +2,12 @@ class PublicScraper: id: str label: str access_token: str - enabled: bool def to_dict(self): return { "id": self.id, "label": self.label, - "access_token": self.access_token, - "enabled": self.enabled + "access_token": self.access_token } def get_students(self): diff --git a/app/services/publicscraper_service.py b/app/services/publicscraper_service.py index b8b0026..22a4f3b 100644 --- a/app/services/publicscraper_service.py +++ b/app/services/publicscraper_service.py @@ -27,7 +27,7 @@ def load_scrapers_from_config(): scrapers = Globals.public_scrapers config = get_config() for scraper in config: - for key in ["id", "label", "enabled", "access_token"]: + for key in ["id", "label", "access_token"]: if not scraper.get(key): raise Exception( f"Missing key {key} in scraper configuration") @@ -37,7 +37,6 @@ def load_scrapers_from_config(): scraper["id"]) ns.id = scraper["id"] ns.name = scraper["label"] - ns.enabled = scraper["enabled"] ns.access_token = scraper["access_token"] if is_new: diff --git a/app/services/student_service.py b/app/services/student_service.py index 3724097..1e33a44 100644 --- a/app/services/student_service.py +++ b/app/services/student_service.py @@ -11,7 +11,7 @@ from app.services.redis_service import RedisService from app.tools.jwt_engine import generate_jwt from app.tools.password_tools import hash_password -from app.tools.teklogger import log_debug +from app.tools.teklogger import log_debug, log_warning class StudentService: @@ -85,23 +85,27 @@ def create_register_ticket(email: str): ticket_url = f"{os.getenv("APP_URL")}/auth?ticket={ticket}" RedisService.set(f"register_ticket_{ticket}", email, 60 * 60) # Expires in 1 hour - subject: str = "Confirm Your TekBetter Account" - body: str = f"""\ - Hello, - - Thank you for creating a TekBetter account! To complete your registration, please confirm your email address by clicking the link below: - - {ticket_url} - - Please note that this link will expire in 1 hour. If you did not request this account, you can safely ignore this email. - - Thank you for choosing TekBetter. We’re excited to have you on board! - - Best regards, - The TekBetter Team - """ - MailService.send_mail(email, subject, body) log_debug(f"Register ticket created for {email}: {ticket}") + if os.getenv("ENABLE_MAILER") == "true": + subject: str = "Confirm Your TekBetter Account" + body: str = f"""\ + Hello, + + Thank you for creating a TekBetter account! To complete your registration, please confirm your email address by clicking the link below: + + {ticket_url} + + Please note that this link will expire in 1 hour. If you did not request this account, you can safely ignore this email. + + Thank you for choosing TekBetter. We’re excited to have you on board! + + Best regards, + The TekBetter Team + """ + MailService.send_mail(email, subject, body) + else: + log_warning( + "Mailer is disabled, not sending email. You can use the following link to confirm your account:" + ticket_url) return ticket @staticmethod diff --git a/app/tools/envloader.py b/app/tools/envloader.py index e7fcc29..289bdb5 100644 --- a/app/tools/envloader.py +++ b/app/tools/envloader.py @@ -5,7 +5,7 @@ from app.tools.teklogger import log_debug, log_warning default_values = { - "PORT": "3000", + "PORT": "8080", "MONGO_HOST": "mongo", "MONGO_PORT": "27017", "MONGO_DB": "tekbetter", @@ -20,7 +20,8 @@ "SMTP_HOST": None, "SMTP_PORT": 587, "SMTP_USER": None, - "SMTP_PASSWORD": None + "SMTP_PASSWORD": None, + "ENABLE_MAILER": "false", } @@ -32,6 +33,13 @@ def load_env(): log_debug("Loading environment variables") load_dotenv() + + smtp_vars = ["SMTP_HOST", "SMTP_USER", "SMTP_PASSWORD"] + if os.getenv("ENABLE_MAILER") == "true": + for var in smtp_vars: + if os.getenv(var) is None: + raise Exception(f"ENABLE_MAILER is true, so {var} must be set") + for key, value in default_values.items(): if os.getenv(key, None) is None: if value is not None: @@ -40,5 +48,6 @@ def load_env(): os.environ[key] = value else: raise Exception(f"Missing environment variable {key}") + if len(os.getenv("AES_KEY")) != 64: raise Exception("AES_KEY must be 64 characters long") diff --git a/web/.gitignore b/web/.gitignore index 4d29575..e99ad9a 100644 --- a/web/.gitignore +++ b/web/.gitignore @@ -4,7 +4,7 @@ /node_modules /.pnp .pnp.js - +/.env # testing /coverage diff --git a/web/src/api/api.ts b/web/src/api/api.ts index c1097f5..e3693bc 100644 --- a/web/src/api/api.ts +++ b/web/src/api/api.ts @@ -7,13 +7,9 @@ export class StaticVars { this.setErrorPopup = (title: string | null, message: string | null) => { } } - } - -//const backend_url = process.env.REACT_APP_BACKEND_URL || "http://localhost:8080" -const current_domain = window.location.hostname; -const backend_url = process.env.NODE_ENV === 'development' ? "https://tekbetter.ovh" : `https://${current_domain}` +const backend_url = process.env.REACT_APP_API_URL || window.location.origin const api = axios.create({ baseURL: `${backend_url}/api/`,