Skip to content

Commit

Permalink
werkplaats 4 added
Browse files Browse the repository at this point in the history
  • Loading branch information
Alaa-1074002 committed Sep 26, 2024
0 parents commit 72157ff
Show file tree
Hide file tree
Showing 125 changed files with 44,784 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*venv
*.idea
*.pyc
*__pycache__
**/node_modules/
Binary file added GLITCH-assignment.pdf
Binary file not shown.
77 changes: 77 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# wp4-2024-starter
# GLITCH

## Overzicht

Dit project maakt gebruik van Docker-containers om meerdere toepassingen te orchestreren, waaronder een database, een Flask API-backend en React-gebaseerde web- en mobiele front-ends. Het heeft tot doel een naadloze ontwikkelings- en implementatieomgeving te bieden.

## Belangrijke opmerkingen!!

1. **URL-aanpassing in constante bestanden**: Zorg ervoor dat u de URL in de constantebestanden van zowel de web- als de mobiele frontend aanpast om overeen te komen met de URL van uw backend.

2. **Problemen met inloggen en CORS**: Als u problemen ondervindt bij het inloggen, moet u mogelijk de CORS-instellingen (Cross-Origin Resource Sharing) op de backend aanpassen om het juiste domein toe te staan.

3. **Gebruik van HTTPS**: Om HTTPS te gebruiken, moet u de "secure session" vlag inschakelen in uw Flask-applicatie en Flask-Talisman configureren om HTTPS af te dwingen.

4. **Talisman en HTTPS**: Als u uw applicatie via HTTPS wilt laten draaien, moet u ervoor zorgen dat Flask-Talisman correct is geconfigureerd om HTTPS te handhaven.

5. **Gebruik aub FireFox**: Gebruik alstublieft Firefox: Gebruik alstublieft Firefox voor testdoeleinden, omdat dit de enige browser is die onbeveiligde cookies ondersteunt.

6. **Inloggen Gebruikgegevens**:
User Name: user1, Password: password1<br/>
User Name: user2, Password: password2<br/>
User Name: user3, Password: password3<br/>
User Name: teacher1, Password: teacherpass<br/>

## Projectstructuur

- **database_**: Bevat bestanden die verband houden met de SQLite-databasecontainer.
- **Dockerfile**: Configuratie voor het uitvoeren van de SQLite-server.
- **backend**: Bevat de Flask API-backend.
- **Dockerfile**: Configuratie voor het uitvoeren python.
- **frontend**:
- **web**: Bevat de op React gebaseerde webfrontend.
- **Dockerfile**: Configuratie voor het uitvoeren python.
- **mobile**: Bevat de op React Native gebaseerde mobiele frontend.
- **Dockerfile**: Configuratie voor het uitvoeren python.

## Installatie en Gebruik

### Vereisten

- Docker moet zijn geïnstalleerd op uw systeem. U kunt het downloaden van https://www.docker.com/get-started.

### Het starten van de Containers

1. Kloon deze repository naar uw lokale machine.

2. Navigeer naar de projectdirectory.

3. Gebruik Docker Compose om de containers te bouwen en uit te voeren:

```bash
docker-compose up --build
```

Deze command zal alle containers bouwen en starten die zijn gedefinieerd in het `docker-compose.yml` bestand.

### Toegang tot Toepassingen

- **Flask API-backend**:
- Poort: 5000
- Zodra de containers actief zijn, is de Flask API toegankelijk op `http://localhost:<port>`. Vervang `<port>` door de poort die is gespecificeerd in uw `docker-compose.yml`.

- **React-webfrontend**:
- Poort: 3000
- Nadat de containers zijn gestart, kunt u de webfrontend openen door naar `http://localhost:<port>` te navigeren in uw webbrowser. Vervang `<port>` door de poort die is gespecificeerd in uw `docker-compose.yml`.

- **React Native mobiele frontend**:
- Poort: 8081
- Om de React Native mobiele frontend uit te voeren, volgt u de instructies in de `mobile` map. U moet mogelijk aanvullende configuraties instellen voor uw ontwikkelomgeving.

### Stoppen van de Containers

Om de containers te stoppen, kunt u de volgende command gebruiken:

```bash
docker-compose down
12 changes: 12 additions & 0 deletions backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM python:3.9

WORKDIR /

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 5000

CMD ["python", "app.py"]
194 changes: 194 additions & 0 deletions backend/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
import os
from flask import Flask, jsonify, request, session
from flask_cors import CORS
from flask_socketio import SocketIO, emit, join_room, leave_room
from models.user_model import UserTable
from models.domain_model import DomainTable
import schedule
import time
import threading
from routes.user_route import users_bp
from routes.domain_route import domains_bp
from flask_talisman import Talisman
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
from werkzeug.security import generate_password_hash, check_password_hash
from routes.validation import sanitize_input, is_valid_email

app = Flask(__name__)
app.secret_key = os.environ.get('SECRET_KEY', 'fallback_secret_key') # Use environment variable
# app.config['SESSION_COOKIE_SECURE'] = True // https
# app.config['SESSION_COOKIE_HTTPONLY'] = True // http // https ssh
# app.config['SESSION_COOKIE_SAMESITE'] = 'Lax'

limiter = Limiter(
app=app,
key_func=get_remote_address,
default_limits=["10 per minute"],
storage_uri="memory://"
)
allowed_origins = ["http://localhost:3000", "http://192.168.178.17:3000", "http://192.168.2.8:3000", "http://192.168.56.1:3000", "http://145.137.104.145:3000"]
socketio = SocketIO(app, cors_allowed_origins=allowed_origins)
CORS(app, origins=allowed_origins, supports_credentials=True)

# talisman = Talisman(
# app,
# content_security_policy={
# 'default-src': "'self'",
# 'script-src': "'self' 'unsafe-inline'",
# 'style-src': "'self' 'unsafe-inline'",
# 'img-src': "'self' data:",
# 'connect-src': "'self' ws: wss:",
# },
# force_https=True,
# session_cookie_secure=True,
# strict_transport_security=True,
# referrer_policy='strict-origin-when-cross-origin'
# )

app.register_blueprint(users_bp)
app.register_blueprint(domains_bp)

@app.route('/')
def main():
return 'Welcome to your Flask-SocketIO application!'

@socketio.on('connect')
def handle_connect():
print('Client connected:', request.sid)

@socketio.on('disconnect')
def handle_disconnect():
print('Client disconnected:', request.sid)

@socketio.on('join_user_room')
def handle_join_user_room(data):
room = str(sanitize_input(data.get("room", "")))
if room:
join_room(room)
print(f'User {room} joined their room')

@socketio.on('leave_room')
def handle_leave_room(data):
room = str(sanitize_input(data.get('room', "")))
if room:
leave_room(room)
print(f'User left room: {room}')

@app.route('/notify', methods=['POST'])
@limiter.limit("10/minute")
def notify():
message = sanitize_input(request.json.get('message', 'Hello, World!'))
user_id = session.get('user_id')
if user_id:
socketio.emit('notification', {'message': message}, room=str(user_id))
return jsonify({'status': 'notification sent'})
else:
return jsonify({'status': 'user not authenticated'}), 401

@app.route('/send_message', methods=['POST'])
@limiter.limit("20/minute")
def send_message():
data = request.json
user_id = sanitize_input(data.get('user_id', ''))
message = sanitize_input(data.get('message', ''))

if user_id:
socketio.emit('new_message', {'message': message}, room=str(user_id))
return jsonify({'status': 'message sent'})
else:
return jsonify({'status': 'user_id not provided'}), 400

@app.route('/users/login', methods=['POST'])
@limiter.limit("5/minute")
def login():
data = request.json
username = data.get('user_name', '')
password = data.get('password', '')

if not username or not password:
return jsonify({'message': 'Username and password are required'}), 400

userTable = UserTable()
user = userTable.get_teacher_by_username(username)

if user and check_password_hash(user['password'], password):
session['user_id'] = user['user_id']
socketio.emit('join_user_room', room=str(user['user_id']))
return jsonify({'message': 'User logged in successfully!', 'user': user}), 200

return jsonify({'message': 'Invalid username or password'}), 401

@app.route('/users/signup', methods=['POST'])
@limiter.limit("3/hour")
def signup():
data = request.json
username = sanitize_input(data.get('user_name', ''))
password = data.get('password', '')
email = sanitize_input(data.get('email', ''))
first_name = sanitize_input(data.get('first_name', ''))
last_name = sanitize_input(data.get('last_name', ''))

if not all([username, password, email, first_name, last_name]):
return jsonify({'message': 'All fields are required'}), 400

if not is_valid_email(email):
return jsonify({'message': 'Invalid email format'}), 400

userTable = UserTable()
if userTable.get_teacher_by_username(username):
return jsonify({'message': 'Username already exists'}), 409

hashed_password = generate_password_hash(password)
user = userTable.create_user(
username=username,
password=hashed_password,
email=email,
first_name=first_name,
last_name=last_name,
profile_picture=None,
IsTeacher=False
)

if user:
session['user_id'] = user['user_id']
join_room(str(user['user_id']))
return jsonify({'message': 'User signed up successfully!', 'user': user}), 201

return jsonify({'message': 'Something went wrong, please try again later'}), 500

@app.route('/users/check-auth', methods=['GET'])
def isAuth():
return jsonify({'auth': 'user_id' in session}), 200

def check_messages():
messages = DomainTable().get_unfinished_progress_modules()
for message in messages:
socketio.emit('notification', {
'message': f'⚠️ Hurry Up! You have only {message["difference_in_days"]} days to finish 📚 {message["course_name"]} 🎓'
}, room=str(message['user_id']))

def schedule_checker():
print(generate_password_hash('password1'))
print(generate_password_hash('password2'))
print(generate_password_hash('password3'))
print(generate_password_hash('teacherpass'))
while True:
schedule.run_pending()
time.sleep(1)

if __name__ == '__main__':
socketio_thread = threading.Thread(target=socketio.run, args=(app,), kwargs={
'host': '0.0.0.0',
'port': int(os.environ.get('PORT', 5000)),
# 'ssl_context': 'adhoc' # Use this for development. For production, use proper SSL certificates.
})
socketio_thread.start()

schedule.every(10).seconds.do(check_messages)

schedule_thread = threading.Thread(target=schedule_checker)
schedule_thread.start()

socketio_thread.join()
schedule_thread.join()
Loading

0 comments on commit 72157ff

Please sign in to comment.