index OK db

main
Valentin 2023-11-17 10:17:31 +01:00
parent d87effe510
commit 9c1ce6dcf2
13 changed files with 702 additions and 0 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

164
.gitignore vendored Normal file
View File

@ -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/

1
README.md Normal file
View File

@ -0,0 +1 @@
# nba-calendar

226
app.py Normal file
View File

@ -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/<int:idTeam>')
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/<int:idTeam>')
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)

2
example.env Normal file
View File

@ -0,0 +1,2 @@
GOOGLE_KEY=""
GOOGLE_SECRET=""

90
index.html Normal file
View File

@ -0,0 +1,90 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Liste d'Équipes</title>
<!-- Bootstrap CSS (via CDN) -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<style>
body {
background-color: #ffffff; /* Fond blanc */
color: #000000; /* Text color */
margin: 0;
padding: 0;
}
.header {
background: rgba(255, 255, 255, 0.8);
padding: 20px;
display: flex;
justify-content: space-between;
align-items: center;
}
.logo {
width: 150px;
height: auto;
}
.header-links {
display: flex;
align-items: center;
}
.header-links a {
color: #000000;
margin-right: 20px;
text-decoration: none;
font-weight: bold;
}
.header-links a:hover {
color: #ffffff;
}
.container {
background: linear-gradient(rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.8)), /* White faded background */
linear-gradient(to right, #0C2340, #1D428A, #006BB6); /* Background for the content */
padding: 20px;
border-radius: 10px;
margin-top: 20px;
}
.list-group-item {
display: flex;
justify-content: space-between;
align-items: center;
background-color: #1D428A;
color: #ffffff; /* Text color for list items */
border: none; /* Remove border */
margin-bottom: 5px; /* Adjust spacing between list items */
}
.button-group button {
margin-right: 5px;
}
</style>
</head>
<body>
<div class="header">
<img src="static/Logo-NBA.png" alt="Logo NBA" class="logo">
<div class="header-links">
<a href="#">Accueil</a>
<a href="autre-page1.html">Autre Page 1</a>
<a href="autre-page2.html">Autre Page 2</a>
<!-- Ajoutez plus de liens au besoin -->
</div>
</div>
<div class="container">
<h1 class="text-center mb-4">Liste d'Équipes</h1>
<input type="text" id="searchInput" class="form-control mb-4" placeholder="Rechercher une équipe..." oninput="filterTeams()">
<ul id="teamList" class="list-group">
<li class="list-group-item">
Équipe 1
<div class="button-group">
<button class="btn btn-success" onclick="ajouterEquipe(0)">+</button>
<button class="btn btn-danger" onclick="enleverEquipe(0)">-</button>
</div>
</li>
</ul>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
</body>
</html>

63
index.py Normal file
View File

@ -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)

4
requirements.txt Normal file
View File

@ -0,0 +1,4 @@
Werkzeug==2.2.2
Flask
Flask-OAuthlib
Flask-SQLAlchemy

BIN
static/.DS_Store vendored Normal file

Binary file not shown.

BIN
static/Logo-NBA.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

BIN
static/logo/google.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

122
templates/index.html Normal file
View File

@ -0,0 +1,122 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Calendar settings</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<style>
body {
background-color: #ffffff;
color: #000000;
margin: 0;
padding: 0;
}
.header {
background: rgba(255, 255, 255, 0.8);
padding: 20px;
display: flex;
justify-content: space-between;
align-items: center;
}
.logo {
width: 150px;
height: auto;
}
.header-links {
display: flex;
align-items: center;
}
.header-links a {
color: #000000;
margin-right: 20px;
text-decoration: none;
font-weight: bold;
}
.header-links a:hover {
color: #ffffff;
}
.container {
background: linear-gradient(rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.8)), /* White faded background */
linear-gradient(to right, #0C2340, #1D428A, #006BB6); /* Background for the content */
padding: 20px;
border-radius: 10px;
margin-top: 20px;
}
.list-group-item {
display: flex;
justify-content: space-between;
align-items: center;
background-color: #1D428A;
color: #ffffff;
border: none;
margin-bottom: 5px;
}
.button-group button {
margin-right: 5px;
}
.list-group-item.d-none {
display: none !important;
}
</style>
</head>
<body>
<div class="header">
<img src="static/Logo-NBA.png" alt="Logo NBA" class="logo">
<div class="header-links">
<a href="">Accueil</a>
<a href="/logout">Déconnexion</a>
</div>
</div>
<div class="container">
<h1 class="text-center mb-4">Liste d'Équipes</h1>
<input type="text" id="searchInput" class="form-control mb-4" placeholder="Rechercher une équipe..." oninput="filterTeams()">
<ul id="teamList" class="list-group">
{% for team in userTeams %}
<li class="list-group-item">
{{ getTeamName(team.idTeam) }}
<div class="button-group">
<a class="btn btn-danger" href="/del/{{ team.idTeam }}">Retirer</a>
</div>
</li>
{% endfor %}
{% for team in otherTeams %}
<li class="list-group-item">
{{ getTeamName(team) }}
<div class="button-group">
<a class="btn btn-success" href="/add/{{ team }}">Ajouter</a>
</div>
</li>
{% endfor %}
</ul>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<script>
function filterTeams() {
var input, filter, ul, li, a, i, txtValue;
input = document.getElementById("searchInput");
filter = input.value.toUpperCase();
ul = document.getElementById("teamList");
li = ul.getElementsByClassName("list-group-item");
for (i = 0; i < li.length; i++) {
a = li[i];
txtValue = a.textContent || a.innerText;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
a.classList.remove("d-none");
} else {
a.classList.add("d-none");
}
}
}
</script>
</body>
</html>

30
templates/login.html Normal file
View File

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<title>Login with Google</title>
</head>
<body>
<div class="container">
<div class="row justify-content-center align-items-center" style="height:100vh;">
<div class="col-md-4">
<div class="card">
<div class="card-body text-center">
<img src="static/logo/google.png" width="150px">
<h5 class="card-title">Login with Google</h5>
<p class="card-text">Click the button below to connect with Google</p>
<a href="/login/google" class="btn btn-danger btn-lg">Login with Google</a>
</div>
</div>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.10.2/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</body>
</html>