design + calendar

main
Valentin 2023-12-22 15:57:13 +01:00
parent 4e3df085e2
commit 9d185f71c3
8 changed files with 149 additions and 75 deletions

BIN
.DS_Store vendored

Binary file not shown.

111
app.py
View File

@ -1,9 +1,9 @@
from flask import Flask, redirect, url_for, session, render_template, Response from flask import Flask, redirect, url_for, session, render_template, Response, request
from flask_oauthlib.client import OAuth from flask_oauthlib.client import OAuth
from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import SQLAlchemy
from datetime import datetime from datetime import datetime, timedelta
from icalendar import Calendar, Event from icalendar import Calendar, Event
import os import os, requests, pytz, hashlib
from dotenv import load_dotenv from dotenv import load_dotenv
load_dotenv() load_dotenv()
@ -85,7 +85,7 @@ def deleteTeam(idTeam):
def getTeamName(idTeam): def getTeamName(idTeam):
return teams_dict[idTeam] return teams_dict[idTeam]
def getTeams(idUser): def getUserTeams(idUser):
teams = Team.query.filter_by(idUser=idUser).all() teams = Team.query.filter_by(idUser=idUser).all()
return teams return teams
@ -98,25 +98,63 @@ def assignTeam(idUser, idTeam):
db.session.commit() db.session.commit()
def get_team_logo(idTeam): def get_team_logo(idTeam):
# Supposons que les logos sont stockés dans le dossier 'static/logos/' avec des noms comme 'team1.png', 'team2.png', etc.
return f"static/logo/team_nba/team_{idTeam}.png" return f"static/logo/team_nba/team_{idTeam}.png"
def createEvent(summary, start_time, end_time): def getSchedules():
event = Event() response = requests.get("https://cdn.nba.com/static/json/staticData/scheduleLeagueV2.json")
event.add('summary', summary) matches_info = []
event.add('dtstart', start_time)
event.add('dtend', end_time)
return event
def generateIcal(events): for game_date in response.json()['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'],
'url': game['branchLink'],
'arenaCity': game['arenaCity'],
'hometeamTricode': game['homeTeam']['teamTricode'],
'awayteamTricode': game['awayTeam']['teamTricode'],
'hometeamScore': game['homeTeam']['score'],
'awayteamScore': game['awayTeam']['score'],
}
matches_info.append(match_info)
return matches_info
def getTeamMatches(idTeam):
result = []
matches_info = getSchedules()
for i in matches_info:
if (i['hometeamName'] == getTeamName(idTeam) or i['awayteamName'] == getTeamName(idTeam)):
result.append(i)
return result
def getUserMatches(idUser):
result = []
teams = getUserTeams(idUser)
for i in teams:
result += getTeamMatches(i.idTeam)
return result
def convert_to_datetime(date_str):
return datetime.strptime(date_str, '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=pytz.UTC)
def generate_ical(events):
cal = Calendar() cal = Calendar()
for event_data in events: for event_data in events:
event = createEvent( event = Event()
event_data['summary'], print("event: ", event)
event_data['start_time'], event.add('summary', f"{event_data['hometeamTricode']} vs {event_data['awayteamTricode']} 🏀")
event_data['end_time'] event.add('location', f"🏟 {event_data['arenaName']}, {event_data['arenaCity']}")
) event.add("description", f"🎖Scores: \n{event_data['hometeamName']} {event_data['hometeamScore']} - {event_data['awayteamScore']} {event_data['awayteamName']}")
event.add("url", event_data['url'])
event.add('dtstart', datetime.strptime(event_data['gameDateTimeUTC'], '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=pytz.UTC))
event.add('dtend', datetime.strptime(event_data['gameDateTimeUTC'], '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=pytz.UTC) + timedelta(hours=3))
cal.add_component(event) cal.add_component(event)
return cal.to_ical() return cal.to_ical()
@app.route('/') @app.route('/')
@ -137,7 +175,7 @@ def index():
if (Team.query.filter_by(idUser=user.id, idTeam=i).first() is None): if (Team.query.filter_by(idUser=user.id, idTeam=i).first() is None):
otherTeams.append(i) otherTeams.append(i)
return render_template('index.html', userTeams=getTeams(user.id), otherTeams=otherTeams, getTeamName=getTeamName, getTeamLogo=get_team_logo) return render_template('index.html', userTeams=getUserTeams(user.id), otherTeams=otherTeams, getTeamName=getTeamName, getTeamLogo=get_team_logo, userId=user.id)
return redirect("/login", code=302) return redirect("/login", code=302)
@ -169,31 +207,30 @@ def delTeamRoute(idTeam):
return redirect("/", code=302) return redirect("/", code=302)
return redirect("/login", 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) @app.route('/events/<int:user_id>')
def api_events(user_id):
events = getUserMatches(user_id)
return render_template('events.html', events=events)
events_data = [] @app.route('/calendar/<int:user_id>.ics')
for team in user_teams: def generate_ical_feed(user_id):
team_events = parseTeamEvents(team.events) events = getUserMatches(user_id)
events_data.extend(team_events) ical_content = generate_ical(events)
ical_data = generateIcal(events_data) response = Response(
ical_content,
content_type='text/calendar',
headers={
'Content-Disposition': 'inline; filename=calendar.ics',
'Cache-Control': 'no-store, no-cache, must-revalidate, max-age=0',
'Pragma': 'no-cache',
'Expires': '0',
}
)
response = Response(ical_data, content_type='text/calendar')
response.headers['Content-Disposition'] = 'inline; filename=calendar.ics'
return response return response
return redirect("/login", code=302)
@app.route('/login') @app.route('/login')
def login(): def login():
return render_template('login.html') return render_template('login.html')

View File

@ -23,8 +23,6 @@ for game_date in data['leagueSchedule']['gameDates']:
} }
matches_info.append(match_info) matches_info.append(match_info)
# Afficher la liste des matchs
#print(matches_info)
teams_dict = { teams_dict = {
1: "Lakers", 1: "Lakers",
@ -59,5 +57,6 @@ teams_dict = {
30: "Nets" 30: "Nets"
} }
# Affichage du dictionnaire for i in matches_info:
print(teams_dict) if (i['hometeamName'] == teams_dict[1] or i['awayteamName'] == teams_dict[1]):
print(i['hometeamName'] + " vs " + i['awayteamName'] + " " + i['gameDateTimeUTC'])

BIN
static/.DS_Store vendored

Binary file not shown.

BIN
static/logo/.DS_Store vendored

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 12 KiB

17
templates/events.html Normal file
View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>API Events</title>
</head>
<body>
<h1>API Events</h1>
<ul>
{% for event in events %}
<li>{{ event }}</li>
{% endfor %}
</ul>
</body>
</html>

View File

@ -5,6 +5,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Calendar settings</title> <title>Calendar settings</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<link rel="stylesheet" href="https://pro.fontawesome.com/releases/v5.10.0/css/all.css" integrity="sha384-AYmEC3Yw5cVb3ZcuHtOA93w35dYTsvhLPVnYs9eStHfGJvOvKxVfELGroGkvsg+p" crossorigin="anonymous">
<style> <style>
body { body {
background-color: #ffffff; background-color: #ffffff;
@ -20,7 +22,7 @@
align-items: center; align-items: center;
} }
.logo { .logo {
width: 250px; width: 150px;
height: auto; height: auto;
} }
.header-links { .header-links {
@ -37,7 +39,7 @@
color: #ffffff; color: #ffffff;
} }
.container { .container {
background: linear-gradient(rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.8)), grey; /* Background for the content */ background: linear-gradient(rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.8)), grey;
padding: 20px; padding: 20px;
border-radius: 10px; border-radius: 10px;
margin-top: 20px; margin-top: 20px;
@ -51,7 +53,7 @@
border: none; border: none;
margin-bottom: 5px; margin-bottom: 5px;
} }
.button-group button { .button-group a {
margin-right: 5px; margin-right: 5px;
} }
@ -67,19 +69,25 @@
</style> </style>
</head> </head>
<body> <body>
<div class="header"> <nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="#">
<img src="static/logo/logo.png" alt="Logo SC" class="logo"> <img src="static/logo/logo.png" alt="Logo SC" class="logo">
<div class="header-links"> </a>
<a href="">Accueil</a> <div class="navbar-nav header-links ml-auto">
<a href="/logout">Déconnexion</a> <a class="nav-item nav-link" href="#">Accueil</a>
<a class="nav-item nav-link" href="{{ url_for('generate_ical_feed', user_id=userId) }}" target="_blank">S'abonner au calendrier</a>
<a class="nav-item nav-link" href="/logout">Déconnexion</a>
</div> </div>
</div> </nav>
<div class="container"> <div class="container">
<h1 class="text-center mb-4">Liste d'Équipes</h1> <div class="d-flex align-items-center mb-4">
<input type="text" id="searchInput" class="form-control mb-4" placeholder="Rechercher une équipe..." oninput="filterTeams()"> <h2 class="mr-2">Equipes:</h2>&nbsp;&nbsp;&nbsp;&nbsp;
<ul id="teamList" class="list-group"> <input type="text" id="searchInput" class="form-control" oninput="filterTeams()">
</div>
<div class="row" id="teamList">
{% for team in userTeams %} {% for team in userTeams %}
<div class="col-md-4 mb-3">
<li class="list-group-item"> <li class="list-group-item">
<img src="{{ getTeamLogo(team.idTeam) }}" alt="Logo de l'équipe" class="team-logo"> <img src="{{ getTeamLogo(team.idTeam) }}" alt="Logo de l'équipe" class="team-logo">
{{ getTeamName(team.idTeam) }} {{ getTeamName(team.idTeam) }}
@ -87,8 +95,10 @@
<a class="btn btn-danger" href="/del/{{ team.idTeam }}">Retirer</a> <a class="btn btn-danger" href="/del/{{ team.idTeam }}">Retirer</a>
</div> </div>
</li> </li>
</div>
{% endfor %} {% endfor %}
{% for team in otherTeams %} {% for team in otherTeams %}
<div class="col-md-4 mb-3">
<li class="list-group-item"> <li class="list-group-item">
<img src="{{ getTeamLogo(team) }}" alt="Logo de l'équipe" class="team-logo"> <img src="{{ getTeamLogo(team) }}" alt="Logo de l'équipe" class="team-logo">
{{ getTeamName(team) }} {{ getTeamName(team) }}
@ -96,10 +106,20 @@
<a class="btn btn-success" href="/add/{{ team }}">Ajouter</a> <a class="btn btn-success" href="/add/{{ team }}">Ajouter</a>
</div> </div>
</li> </li>
</div>
{% endfor %} {% endfor %}
</ul> </div>
</div> </div>
<footer class="footer mt-auto py-3">
<div class="container text-center">
<a href="https://github.com/itsmrval/nba-calendar" target="_blank" class="ml-3 text-muted text-decoration-none">
<i class="fab fa-github"></i> &copy; 2023 Sport Calendar
</a>
</div>
</footer>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script> <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://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 src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
@ -109,7 +129,7 @@
input = document.getElementById("searchInput"); input = document.getElementById("searchInput");
filter = input.value.toUpperCase(); filter = input.value.toUpperCase();
ul = document.getElementById("teamList"); ul = document.getElementById("teamList");
li = ul.getElementsByClassName("list-group-item"); li = ul.getElementsByClassName("col-md-4");
for (i = 0; i < li.length; i++) { for (i = 0; i < li.length; i++) {
a = li[i]; a = li[i];
@ -122,5 +142,6 @@
} }
} }
</script> </script>
</body> </body>
</html> </html>