diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..6ba18a0 Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fcb5df5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,164 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +.idea +.idea/* + + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..6cc76f9 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# nba-calendar \ No newline at end of file diff --git a/app.py b/app.py new file mode 100644 index 0000000..9930a66 --- /dev/null +++ b/app.py @@ -0,0 +1,226 @@ +from flask import Flask, redirect, url_for, session, render_template, Response +from flask_oauthlib.client import OAuth +from flask_sqlalchemy import SQLAlchemy +from datetime import datetime +from icalendar import Calendar, Event +import os +from dotenv import load_dotenv +load_dotenv() + +app = Flask(__name__) + +app.config['SECRET_KEY'] = 'fjlksjfnklsdfnsdklfnsdkjfnsdjkfnds' +app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.db' +app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False +db = SQLAlchemy(app) + +oauth = OAuth(app) + +google = oauth.remote_app( + 'google', + consumer_key=os.getenv('GOOGLE_KEY'), + consumer_secret=os.getenv('GOOGLE_SECRET'), + request_token_params={ + 'scope': 'email', + }, + base_url='https://www.googleapis.com/oauth2/v1/', + request_token_url=None, + access_token_method='POST', + access_token_url='https://accounts.google.com/o/oauth2/token', + authorize_url='https://accounts.google.com/o/oauth2/auth', +) + +teams_dict = { + 1: "Lakers", + 2: "Heat", + 3: "Warriors", + 4: "Celtics", + 5: "Spurs", + 6: "Knicks", + 7: "Pistons", + 8: "Magic", + 9: "Suns", + 10: "Pacers", + 11: "Jazz", + 12: "Trail Blazers", + 13: "Raptors", + 14: "Mavericks", + 15: "Bucks", + 16: "Thunder", + 17: "Bulls", + 18: "Pelicans", + 19: "Rockets", + 20: "Kings", + 21: "Clippers", + 22: "Cavaliers", + 23: "Hawks", + 24: "Grizzlies", + 25: "Nuggets", + 26: "Hornets", + 27: "76ers", + 28: "Wizards", + 29: "Timberwolves", + 30: "Nets" +} + +class User(db.Model): + id = db.Column(db.Integer, primary_key=True) + email = db.Column(db.String(120), unique=True) + +class Team(db.Model): + id = db.Column(db.Integer, primary_key=True) + idTeam = db.Column(db.Integer, unique=True) + idUser = db.Column(db.Integer, db.ForeignKey('user.id')) + +def addTeam(idUser, idTeam): + team = Team(idTeam=idTeam, idUser=idUser) + db.session.add(team) + db.session.commit() + +def deleteTeam(idTeam): + team = Team.query.filter_by(idTeam=idTeam).first() + db.session.delete(team) + db.session.commit() + +def getTeamName(idTeam): + return teams_dict[idTeam] + +def getTeams(idUser): + teams = Team.query.filter_by(idUser=idUser).all() + return teams + +def assignTeam(idUser, idTeam): + team = Team.query.filter_by(idTeam=idTeam).first() + if team is None: + addTeam(idUser, idTeam) + else: + team.idUser = idUser + db.session.commit() + +def createEvent(summary, start_time, end_time): + event = Event() + event.add('summary', summary) + event.add('dtstart', start_time) + event.add('dtend', end_time) + return event + +def generateIcal(events): + cal = Calendar() + for event_data in events: + event = createEvent( + event_data['summary'], + event_data['start_time'], + event_data['end_time'] + ) + cal.add_component(event) + return cal.to_ical() + +@app.route('/') +def index(): + if 'google_token' in session: + me = google.get('userinfo') + if (not(me.data['email'])): + return redirect("/logout", code=302) + user = User.query.filter_by(email=me.data['email']).first() + if user is None: + user = User(email=me.data['email']) + db.session.add(user) + db.session.commit() + + otherTeams = [] + + for i in list(teams_dict.keys()): + if (Team.query.filter_by(idUser=user.id, idTeam=i).first() is None): + otherTeams.append(i) + + return render_template('index.html', userTeams=getTeams(user.id), otherTeams=otherTeams, getTeamName=getTeamName) + + + return redirect("/login", code=302) + +@app.route('/add/') +def addTeamRoute(idTeam): + if 'google_token' in session: + me = google.get('userinfo') + user = User.query.filter_by(email=me.data['email']).first() + if user is None: + user = User(email=me.data['email']) + db.session.add(user) + db.session.commit() + + assignTeam(user.id, idTeam) + return redirect("/", code=302) + return redirect("/login", code=302) + +@app.route('/del/') +def delTeamRoute(idTeam): + if 'google_token' in session: + me = google.get('userinfo') + user = User.query.filter_by(email=me.data['email']).first() + if user is None: + user = User(email=me.data['email']) + db.session.add(user) + db.session.commit() + + deleteTeam(idTeam) + return redirect("/", code=302) + return redirect("/login", code=302) + +@app.route('/calendar') +def download_ical(): + if 'google_token' in session: + me = google.get('userinfo') + user = User.query.filter_by(email=me.data['email']).first() + if user is None: + user = User(email=me.data['email']) + db.session.add(user) + db.session.commit() + + user_teams = getTeams(user.id) + + events_data = [] + for team in user_teams: + team_events = parseTeamEvents(team.events) + events_data.extend(team_events) + + ical_data = generateIcal(events_data) + + response = Response(ical_data, content_type='text/calendar') + response.headers['Content-Disposition'] = 'inline; filename=calendar.ics' + return response + + return redirect("/login", code=302) + +@app.route('/login') +def login(): + return render_template('login.html') + +@app.route('/login/google') +def google_redirect(): + return google.authorize(callback=url_for('authorized', _external=True)) + +@app.route('/logout') +def logout(): + session.pop('google_token', None) + return redirect("/", code=302) + +@app.route('/login/authorized') +def authorized(): + response = google.authorized_response() + if response is None or response.get('access_token') is None: + return 'Access denied: reason={} error={}'.format( + request.args['error_reason'], + request.args['error_description'] + ) + session['google_token'] = (response['access_token'], '') + return redirect("/", code=302) + +@google.tokengetter +def get_google_oauth_token(): + return session.get('google_token') + +if __name__ == '__main__': + with app.app_context(): + db.create_all() + + app.run(debug=True, port=5050) \ No newline at end of file diff --git a/example.env b/example.env new file mode 100644 index 0000000..728f5fd --- /dev/null +++ b/example.env @@ -0,0 +1,2 @@ +GOOGLE_KEY="" +GOOGLE_SECRET="" \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..1d4c618 --- /dev/null +++ b/index.html @@ -0,0 +1,90 @@ + + + + + + Liste d'Équipes + + + + + + + +
+

Liste d'Équipes

+ +
    +
  • + Équipe 1 +
    + + +
    +
  • +
+
+ + + + + + diff --git a/index.py b/index.py new file mode 100644 index 0000000..5c96162 --- /dev/null +++ b/index.py @@ -0,0 +1,63 @@ +import requests +import json + +# URL du JSON +url = "https://cdn.nba.com/static/json/staticData/scheduleLeagueV2.json" + +# Obtenir le contenu JSON de l'URL +response = requests.get(url) +data = response.json() + +# Liste des matchs avec les informations demandées +matches_info = [] + +for game_date in data['leagueSchedule']['gameDates']: + for game in game_date['games']: + match_info = { + 'gameDateTimeUTC': game['gameDateTimeUTC'], + 'weekNumber': game['weekNumber'], + 'arenaName': game['arenaName'], + 'seriesText': game['seriesText'], + 'hometeamName': game['homeTeam']['teamName'], + 'awayteamName': game['awayTeam']['teamName'], + } + matches_info.append(match_info) + +# Afficher la liste des matchs +#print(matches_info) + +teams_dict = { + 1: "Lakers", + 2: "Heat", + 3: "Warriors", + 4: "Celtics", + 5: "Spurs", + 6: "Knicks", + 7: "Pistons", + 8: "Magic", + 9: "Suns", + 10: "Pacers", + 11: "Jazz", + 12: "Trail Blazers", + 13: "Raptors", + 14: "Mavericks", + 15: "Bucks", + 16: "Thunder", + 17: "Bulls", + 18: "Pelicans", + 19: "Rockets", + 20: "Kings", + 21: "Clippers", + 22: "Cavaliers", + 23: "Hawks", + 24: "Grizzlies", + 25: "Nuggets", + 26: "Hornets", + 27: "76ers", + 28: "Wizards", + 29: "Timberwolves", + 30: "Nets" +} + +# Affichage du dictionnaire +print(teams_dict) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..2caba87 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +Werkzeug==2.2.2 +Flask +Flask-OAuthlib +Flask-SQLAlchemy \ No newline at end of file diff --git a/static/.DS_Store b/static/.DS_Store new file mode 100644 index 0000000..c6f835d Binary files /dev/null and b/static/.DS_Store differ diff --git a/static/Logo-NBA.png b/static/Logo-NBA.png new file mode 100644 index 0000000..f3b5896 Binary files /dev/null and b/static/Logo-NBA.png differ diff --git a/static/logo/google.png b/static/logo/google.png new file mode 100644 index 0000000..2fa8d7c Binary files /dev/null and b/static/logo/google.png differ diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..ecfa9b8 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,122 @@ + + + + + + Calendar settings + + + + +
+ + +
+ +
+

Liste d'Équipes

+ +
    + + {% for team in userTeams %} +
  • + {{ getTeamName(team.idTeam) }} +
    + Retirer +
    +
  • + {% endfor %} + + {% for team in otherTeams %} +
  • + {{ getTeamName(team) }} +
    + Ajouter +
    +
  • + {% endfor %} +
+
+ + + + + + + diff --git a/templates/login.html b/templates/login.html new file mode 100644 index 0000000..325dad6 --- /dev/null +++ b/templates/login.html @@ -0,0 +1,30 @@ + + + + + + + Login with Google + + + +
+
+
+
+
+ +
Login with Google
+

Click the button below to connect with Google

+ Login with Google +
+
+
+
+
+ + + + + +