diff --git a/motm_app/README.md b/motm_app/README.md index b698299..3743443 100644 --- a/motm_app/README.md +++ b/motm_app/README.md @@ -1,6 +1,6 @@ -# HKFC Men's D Team - MOTM (Man of the Match) System +# HKFC Men's C Team - MOTM (Man of the Match) System -This is a standalone Flask application for managing Man of the Match and Dick of the Day voting for the HKFC Men's D Team hockey club. +This is a standalone Flask application for managing Man of the Match and Dick of the Day voting for the HKFC Men's C Team hockey club. ## Features @@ -113,11 +113,11 @@ The application will be available at `http://localhost:5000` ## Database Requirements The application requires access to the following database tables: -- `_hkfcD_matchSquad` - Current match squad +- `_hkfcC_matchSquad` - Current match squad - `_HKFC_players` - Player database -- `hkfcDAdminSettings` - Admin configuration +- `hkfcCAdminSettings` - Admin configuration - `hockeyFixtures` - Match fixtures -- `_hkfc_d_motm` - MOTM/DotD voting results +- `_hkfc_c_motm` - MOTM/DotD voting results - `_motmComments` - Match comments - `_clubTeams` - Club and team information - `mensHockeyClubs` - Club logos and information diff --git a/motm_app/database.py b/motm_app/database.py index 7ca2389..92219d0 100644 --- a/motm_app/database.py +++ b/motm_app/database.py @@ -231,7 +231,9 @@ def fetch_all(sql_command, params=None): result = session.execute(sql_command, params) else: result = session.execute(sql_command) - return result.fetchall() + rows = result.fetchall() + # Convert to list of dictionaries for compatibility + return [dict(row._mapping) for row in rows] if rows else [] except Exception as e: print(f"SQL Error: {e}") return [] @@ -246,7 +248,8 @@ def fetch_one(sql_command, params=None): result = session.execute(sql_command, params) else: result = session.execute(sql_command) - return result.fetchone() + row = result.fetchone() + return dict(row._mapping) if row else None except Exception as e: print(f"SQL Error: {e}") return None @@ -254,32 +257,31 @@ def fetch_one(sql_command, params=None): session.close() # Legacy compatibility functions -def sql_write(sql_cmd): +def sql_write(sql_cmd, params=None): """Legacy compatibility function for sql_write.""" try: - execute_sql(sql_cmd) + execute_sql(sql_cmd, params) return True except Exception as e: print(f"Write Error: {e}") return False -def sql_write_static(sql_cmd): +def sql_write_static(sql_cmd, params=None): """Legacy compatibility function for sql_write_static.""" - return sql_write(sql_cmd) + return sql_write(sql_cmd, params) -def sql_read(sql_cmd): +def sql_read(sql_cmd, params=None): """Legacy compatibility function for sql_read.""" try: - result = fetch_all(sql_cmd) - # Convert to list of dictionaries for compatibility - return [dict(row) for row in result] if result else [] + result = fetch_all(sql_cmd, params) + return result except Exception as e: print(f"Read Error: {e}") return [] -def sql_read_static(sql_cmd): +def sql_read_static(sql_cmd, params=None): """Legacy compatibility function for sql_read_static.""" - return sql_read(sql_cmd) + return sql_read(sql_cmd, params) # Initialize database tables def init_database(): diff --git a/motm_app/database_config.ini b/motm_app/database_config.ini new file mode 100644 index 0000000..1e4c090 --- /dev/null +++ b/motm_app/database_config.ini @@ -0,0 +1,19 @@ +[DATABASE] +type = postgresql +sqlite_database_path = hockey_results.db + +[MYSQL] +host = localhost +port = 3306 +database = hockey_results +username = root +password = +charset = utf8mb4 + +[POSTGRESQL] +host = icarus.ipa.champion +port = 5432 +database = motm +username = motm_user +password = q7y7f7Lv*sODJZ2wGiv0Wq5a + diff --git a/motm_app/db_setup.py b/motm_app/db_setup.py index c450c35..61f5bd6 100644 --- a/motm_app/db_setup.py +++ b/motm_app/db_setup.py @@ -20,6 +20,9 @@ class DatabaseConfigManager: """Manages database configuration and setup.""" def __init__(self, config_file='database_config.ini'): + # Use absolute path to ensure we save in the right location + if not os.path.isabs(config_file): + config_file = os.path.join(os.path.dirname(__file__), config_file) self.config_file = config_file self.config = configparser.ConfigParser() self.load_config() @@ -49,6 +52,8 @@ class DatabaseConfigManager: 'username': 'postgres', 'password': '' } + # Save the default configuration to file + self._save_config_file() def save_config(self, form_data): """Save configuration from form data.""" @@ -60,38 +65,42 @@ class DatabaseConfigManager: self.config['DATABASE']['sqlite_database_path'] = form_data['sqlite_database_path'] # Update MySQL settings - if 'mysql_host' in form_data: - self.config['MYSQL']['host'] = form_data['mysql_host'] - if 'mysql_port' in form_data: + if 'mysql_host' in form_data and form_data['mysql_host'] is not None: + self.config['MYSQL']['host'] = str(form_data['mysql_host']) + if 'mysql_port' in form_data and form_data['mysql_port'] is not None: self.config['MYSQL']['port'] = str(form_data['mysql_port']) - if 'mysql_database' in form_data: - self.config['MYSQL']['database'] = form_data['mysql_database'] - if 'mysql_username' in form_data: - self.config['MYSQL']['username'] = form_data['mysql_username'] - if 'mysql_password' in form_data: - self.config['MYSQL']['password'] = form_data['mysql_password'] - if 'mysql_charset' in form_data: - self.config['MYSQL']['charset'] = form_data['mysql_charset'] + if 'mysql_database' in form_data and form_data['mysql_database'] is not None: + self.config['MYSQL']['database'] = str(form_data['mysql_database']) + if 'mysql_username' in form_data and form_data['mysql_username'] is not None: + self.config['MYSQL']['username'] = str(form_data['mysql_username']) + if 'mysql_password' in form_data and form_data['mysql_password'] is not None: + self.config['MYSQL']['password'] = str(form_data['mysql_password']) + if 'mysql_charset' in form_data and form_data['mysql_charset'] is not None: + self.config['MYSQL']['charset'] = str(form_data['mysql_charset']) # Update PostgreSQL settings - if 'postgres_host' in form_data: - self.config['POSTGRESQL']['host'] = form_data['postgres_host'] - if 'postgres_port' in form_data: + if 'postgres_host' in form_data and form_data['postgres_host'] is not None: + self.config['POSTGRESQL']['host'] = str(form_data['postgres_host']) + if 'postgres_port' in form_data and form_data['postgres_port'] is not None: self.config['POSTGRESQL']['port'] = str(form_data['postgres_port']) - if 'postgres_database' in form_data: - self.config['POSTGRESQL']['database'] = form_data['postgres_database'] - if 'postgres_username' in form_data: - self.config['POSTGRESQL']['username'] = form_data['postgres_username'] - if 'postgres_password' in form_data: - self.config['POSTGRESQL']['password'] = form_data['postgres_password'] + if 'postgres_database' in form_data and form_data['postgres_database'] is not None: + self.config['POSTGRESQL']['database'] = str(form_data['postgres_database']) + if 'postgres_username' in form_data and form_data['postgres_username'] is not None: + self.config['POSTGRESQL']['username'] = str(form_data['postgres_username']) + if 'postgres_password' in form_data and form_data['postgres_password'] is not None: + self.config['POSTGRESQL']['password'] = str(form_data['postgres_password']) # Save to file - with open(self.config_file, 'w') as f: - self.config.write(f) + self._save_config_file() # Update environment variables self._update_environment_variables() + def _save_config_file(self): + """Save configuration to file.""" + with open(self.config_file, 'w') as f: + self.config.write(f) + def _update_environment_variables(self): """Update environment variables based on configuration.""" db_type = self.config['DATABASE']['type'] @@ -188,7 +197,7 @@ class DatabaseConfigManager: session = get_db_session() try: - # Create sample clubs + # Create sample clubs (only if they don't exist) clubs_data = [ {'hockey_club': 'HKFC', 'logo_url': '/static/images/hkfc_logo.png'}, {'hockey_club': 'KCC', 'logo_url': '/static/images/kcc_logo.png'}, @@ -197,59 +206,72 @@ class DatabaseConfigManager: ] for club_data in clubs_data: - club = Club(**club_data) - session.add(club) + # Check if club already exists + existing_club = session.query(Club).filter_by(hockey_club=club_data['hockey_club']).first() + if not existing_club: + club = Club(**club_data) + session.add(club) - # Create sample teams + # Create sample teams (only if they don't exist) teams_data = [ {'club': 'HKFC', 'team': 'A', 'display_name': 'HKFC A', 'league': 'Premier Division'}, {'club': 'HKFC', 'team': 'B', 'display_name': 'HKFC B', 'league': 'Division 1'}, {'club': 'HKFC', 'team': 'C', 'display_name': 'HKFC C', 'league': 'Division 2'}, - {'club': 'HKFC', 'team': 'D', 'display_name': 'HKFC D', 'league': 'Division 3'}, ] for team_data in teams_data: - team = Team(**team_data) - session.add(team) + # Check if team already exists + existing_team = session.query(Team).filter_by(club=team_data['club'], team=team_data['team']).first() + if not existing_team: + team = Team(**team_data) + session.add(team) - # Create sample players + # Create sample players (only if they don't exist) players_data = [ - {'player_number': 1, 'player_forenames': 'John', 'player_surname': 'Smith', 'player_nickname': 'Smithers', 'player_team': 'HKFC D'}, - {'player_number': 2, 'player_forenames': 'Mike', 'player_surname': 'Jones', 'player_nickname': 'Jonesy', 'player_team': 'HKFC D'}, - {'player_number': 3, 'player_forenames': 'David', 'player_surname': 'Brown', 'player_nickname': 'Brownie', 'player_team': 'HKFC D'}, - {'player_number': 4, 'player_forenames': 'Chris', 'player_surname': 'Wilson', 'player_nickname': 'Willy', 'player_team': 'HKFC D'}, - {'player_number': 5, 'player_forenames': 'Tom', 'player_surname': 'Taylor', 'player_nickname': 'Tayls', 'player_team': 'HKFC D'}, + {'player_number': 1, 'player_forenames': 'John', 'player_surname': 'Smith', 'player_nickname': 'Smithers', 'player_team': 'HKFC C'}, + {'player_number': 2, 'player_forenames': 'Mike', 'player_surname': 'Jones', 'player_nickname': 'Jonesy', 'player_team': 'HKFC C'}, + {'player_number': 3, 'player_forenames': 'David', 'player_surname': 'Brown', 'player_nickname': 'Brownie', 'player_team': 'HKFC C'}, + {'player_number': 4, 'player_forenames': 'Chris', 'player_surname': 'Wilson', 'player_nickname': 'Willy', 'player_team': 'HKFC C'}, + {'player_number': 5, 'player_forenames': 'Tom', 'player_surname': 'Taylor', 'player_nickname': 'Tayls', 'player_team': 'HKFC C'}, ] for player_data in players_data: - player = Player(**player_data) - session.add(player) + # Check if player already exists + existing_player = session.query(Player).filter_by(player_number=player_data['player_number']).first() + if not existing_player: + player = Player(**player_data) + session.add(player) - # Create sample admin settings - admin_settings = AdminSettings( - userid='admin', - next_fixture=1, - next_club='KCC', - next_team='KCC A', - curr_motm=1, - curr_dotd=2, - oppo_logo='/static/images/kcc_logo.png', - hkfc_logo='/static/images/hkfc_logo.png', - motm_url_suffix='abc123', - prev_fixture=0 - ) - session.add(admin_settings) + # Create sample admin settings (only if they don't exist) + existing_admin = session.query(AdminSettings).filter_by(userid='admin').first() + if not existing_admin: + admin_settings = AdminSettings( + userid='admin', + next_fixture=1, + next_club='KCC', + next_team='KCC A', + curr_motm=1, + curr_dotd=2, + oppo_logo='/static/images/kcc_logo.png', + hkfc_logo='/static/images/hkfc_logo.png', + motm_url_suffix='abc123', + prev_fixture=0 + ) + session.add(admin_settings) - # Create sample fixtures + # Create sample fixtures (only if they don't exist) fixtures_data = [ - {'fixture_number': 1, 'date': datetime(2024, 1, 15), 'home_team': 'HKFC D', 'away_team': 'KCC A', 'venue': 'HKFC'}, - {'fixture_number': 2, 'date': datetime(2024, 1, 22), 'home_team': 'USRC A', 'away_team': 'HKFC D', 'venue': 'USRC'}, - {'fixture_number': 3, 'date': datetime(2024, 1, 29), 'home_team': 'HKFC D', 'away_team': 'Valley A', 'venue': 'HKFC'}, + {'fixture_number': 1, 'date': datetime(2024, 1, 15), 'home_team': 'HKFC C', 'away_team': 'KCC A', 'venue': 'HKFC'}, + {'fixture_number': 2, 'date': datetime(2024, 1, 22), 'home_team': 'USRC A', 'away_team': 'HKFC C', 'venue': 'USRC'}, + {'fixture_number': 3, 'date': datetime(2024, 1, 29), 'home_team': 'HKFC C', 'away_team': 'Valley A', 'venue': 'HKFC'}, ] for fixture_data in fixtures_data: - fixture = HockeyFixture(**fixture_data) - session.add(fixture) + # Check if fixture already exists + existing_fixture = session.query(HockeyFixture).filter_by(fixture_number=fixture_data['fixture_number']).first() + if not existing_fixture: + fixture = HockeyFixture(**fixture_data) + session.add(fixture) session.commit() diff --git a/motm_app/forms.py b/motm_app/forms.py index b60b1e4..d2163c2 100644 --- a/motm_app/forms.py +++ b/motm_app/forms.py @@ -18,7 +18,7 @@ class motmAdminForm(FlaskForm): class adminSettingsForm2(FlaskForm): - nextMatch = SelectField('Fixture', choices=[]) + nextMatchDate = DateField('Match Date', format='%Y-%m-%d') nextOppoClub = StringField('Next Opposition Club:') nextOppoTeam = StringField("Next Opposition Team:") currMotM = SelectField('Current Man of the Match:', choices=[]) @@ -47,8 +47,7 @@ class DatabaseSetupForm(FlaskForm): # SQLite fields sqlite_database_path = StringField('Database File Path', - default='hockey_results.db', - validators=[InputRequired()]) + default='hockey_results.db') # MySQL/MariaDB fields mysql_host = StringField('Host', default='localhost') @@ -73,3 +72,57 @@ class DatabaseSetupForm(FlaskForm): test_connection = SubmitField('Test Connection') save_config = SubmitField('Save Configuration') initialize_database = SubmitField('Initialize Database') + + +class PlayerForm(FlaskForm): + """Form for adding/editing players.""" + + player_number = IntegerField('Player Number', validators=[InputRequired()]) + player_forenames = StringField('First Names', validators=[InputRequired()]) + player_surname = StringField('Surname', validators=[InputRequired()]) + player_nickname = StringField('Nickname', validators=[InputRequired()]) + player_team = SelectField('Team', + choices=[('HKFC A', 'HKFC A'), + ('HKFC B', 'HKFC B'), + ('HKFC C', 'HKFC C')], + default='HKFC C') + + # Action buttons + save_player = SubmitField('Save Player') + cancel = SubmitField('Cancel') + + +class ClubForm(FlaskForm): + """Form for adding/editing clubs.""" + + hockey_club = StringField('Club Name', validators=[InputRequired()]) + logo_url = StringField('Logo URL', validators=[InputRequired()]) + + # Action buttons + save_club = SubmitField('Save Club') + cancel = SubmitField('Cancel') + + +class TeamForm(FlaskForm): + """Form for adding/editing teams.""" + + club = StringField('Club', validators=[InputRequired()]) + team = StringField('Team', validators=[InputRequired()]) + display_name = StringField('Display Name', validators=[InputRequired()]) + league = StringField('League', validators=[InputRequired()]) + + # Action buttons + save_team = SubmitField('Save Team') + cancel = SubmitField('Cancel') + + +class DataImportForm(FlaskForm): + """Form for importing data from Hong Kong Hockey Association.""" + + import_clubs = BooleanField('Import Clubs', default=True) + import_teams = BooleanField('Import Teams', default=True) + import_players = BooleanField('Import Sample Players', default=False) + + # Action buttons + import_data = SubmitField('Import Data') + cancel = SubmitField('Cancel') diff --git a/motm_app/main.py b/motm_app/main.py index d68f6b4..ae05703 100644 --- a/motm_app/main.py +++ b/motm_app/main.py @@ -15,8 +15,9 @@ from flask_basicauth import BasicAuth from wtforms import StringField, PasswordField, BooleanField from wtforms import DateField from wtforms.validators import InputRequired, Email, Length -from forms import motmForm, adminSettingsForm2, goalsAssistsForm, DatabaseSetupForm +from forms import motmForm, adminSettingsForm2, goalsAssistsForm, DatabaseSetupForm, PlayerForm, ClubForm, TeamForm, DataImportForm from db_config import sql_write, sql_write_static, sql_read, sql_read_static +from sqlalchemy import text from tables import matchSquadTable from readSettings import mySettings from db_setup import db_config_manager @@ -37,10 +38,15 @@ def index(): @app.route('/motm/') def motm_vote(randomUrlSuffix): """Public voting page for Man of the Match and Dick of the Day""" - sql = "SELECT playerNumber, playerForenames, playerSurname, playerNickname FROM _hkfcD_matchSquad ORDER BY RAND()" - sql2 = "SELECT nextClub, nextTeam, nextDate, oppoLogo, hkfcLogo, currMotM, currDotD, nextFixture FROM hkfcDAdminSettings" + sql = "SELECT playerNumber, playerForenames, playerSurname, playerNickname FROM _hkfcC_matchSquad ORDER BY RAND()" + sql2 = "SELECT nextClub, nextTeam, nextDate, oppoLogo, hkfcLogo, currMotM, currDotD, nextFixture FROM motmAdminSettings" rows = sql_read(sql) nextInfo = sql_read_static(sql2) + + # Handle empty results + if not nextInfo: + return render_template('error.html', message="Database not initialized. Please go to Database Setup to initialize the database.") + nextClub = nextInfo[0]['nextClub'] nextTeam = nextInfo[0]['nextTeam'] nextFixture = nextInfo[0]['nextFixture'] @@ -49,25 +55,34 @@ def motm_vote(randomUrlSuffix): currMotM = nextInfo[0]['currMotM'] currDotD = nextInfo[0]['currDotD'] oppo = nextTeam - sql3 = "SELECT hockeyResults2021.hockeyFixtures.date, hockeyResults.hkfcDAdminSettings.nextFixture FROM hockeyResults2021.hockeyFixtures INNER JOIN hockeyResults.hkfcDAdminSettings ON hockeyResults2021.hockeyFixtures.fixtureNumber = hockeyResults.hkfcDAdminSettings.nextFixture" + sql3 = "SELECT hockeyResults2021.hockeyFixtures.date, hockeyResults.motmAdminSettings.nextFixture FROM hockeyResults2021.hockeyFixtures INNER JOIN hockeyResults.motmAdminSettings ON hockeyResults2021.hockeyFixtures.fixtureNumber = hockeyResults.motmAdminSettings.nextFixture" nextMatchDate = sql_read(sql3) + if not nextMatchDate: + return render_template('error.html', message="No fixtures found. Please initialize the database with sample data.") nextDate = nextMatchDate[0]['date'] formatDate = datetime.strftime(nextDate, '%A, %d %B %Y') - sql3 = "SELECT playerPictureURL FROM _HKFC_players INNER JOIN hockeyResults.hkfcDAdminSettings ON _HKFC_players.playerNumber=hockeyResults.hkfcDAdminSettings.currMotM" - sql4 = "SELECT playerPictureURL FROM _HKFC_players INNER JOIN hockeyResults.hkfcDAdminSettings ON _HKFC_players.playerNumber=hockeyResults.hkfcDAdminSettings.currDotD" + sql3 = "SELECT playerPictureURL FROM _HKFC_players INNER JOIN hockeyResults.motmAdminSettings ON _HKFC_players.playerNumber=hockeyResults.motmAdminSettings.currMotM" + sql4 = "SELECT playerPictureURL FROM _HKFC_players INNER JOIN hockeyResults.motmAdminSettings ON _HKFC_players.playerNumber=hockeyResults.motmAdminSettings.currDotD" motm = sql_read(sql3) dotd = sql_read(sql4) + + # Handle empty results + if not motm or not dotd: + return render_template('error.html', message="Player data not found. Please initialize the database with sample data.") + motmURL = motm[0]['playerPictureURL'] dotdURL = dotd[0]['playerPictureURL'] - sql5 = "SELECT comment FROM _motmComments INNER JOIN hockeyResults.hkfcDAdminSettings ON _motmComments.matchDate=hockeyResults.hkfcDAdminSettings.nextDate ORDER BY RAND() LIMIT 1" + sql5 = "SELECT comment FROM _motmComments INNER JOIN hockeyResults.motmAdminSettings ON _motmComments.matchDate=hockeyResults.motmAdminSettings.nextDate ORDER BY RAND() LIMIT 1" comment = sql_read(sql5) if comment == "": comment = "No comments added yet" form = motmForm() - sql6 = "SELECT motmUrlSuffix FROM hockeyResults.hkfcDAdminSettings WHERE userid='admin'" + sql6 = "SELECT motmUrlSuffix FROM hockeyResults.motmAdminSettings WHERE userid='admin'" urlSuff = sql_read_static(sql6) + if not urlSuff: + return render_template('error.html', message="Admin settings not found. Please initialize the database.") randomSuff = urlSuff[0]['motmUrlSuffix'] print(randomSuff) if randomSuff == randomUrlSuffix: @@ -79,8 +94,11 @@ def motm_vote(randomUrlSuffix): @app.route('/motm/comments', methods=['GET', 'POST']) def match_comments(): """Display and allow adding match comments""" - sql = "SELECT nextClub, nextTeam, nextDate, oppoLogo, hkfcLogo FROM hkfcDAdminSettings" + sql = "SELECT nextClub, nextTeam, nextDate, oppoLogo, hkfcLogo FROM motmAdminSettings" row = sql_read_static(sql) + if not row: + return render_template('error.html', message="Database not initialized. Please go to Database Setup to initialize the database.") + _oppo = row[0]['nextClub'] commentDate = row[0]['nextDate'].strftime('%Y-%m-%d') _matchDate = row[0]['nextDate'].strftime('%Y_%m_%d') @@ -109,8 +127,8 @@ def vote_thanks(): _oppo = request.form['oppo'] if _motm and _dotd and request.method == 'POST': - sql = "INSERT INTO _hkfc_d_motm (playerNumber, playerName, motmTotal, motm_" + _matchDate + ") SELECT playerNumber, playerNickname, '1', '1' FROM _HKFC_players WHERE playerNumber='" + _motm + "' ON DUPLICATE KEY UPDATE motmTotal = motmTotal + 1, motm_" + _matchDate + " = motm_" + _matchDate + " + 1" - sql2 = "INSERT INTO _hkfc_d_motm (playerNumber, playerName, dotdTotal, dotd_" + _matchDate + ") SELECT playerNumber, playerNickname, '1', '1' FROM _HKFC_players WHERE playerNumber='" + _dotd + "' ON DUPLICATE KEY UPDATE dotdTotal = dotdTotal + 1, dotd_" + _matchDate + " = dotd_" + _matchDate + " + 1" + sql = "INSERT INTO _hkfc_c_motm (playerNumber, playerName, motmTotal, motm_" + _matchDate + ") SELECT playerNumber, playerNickname, '1', '1' FROM _HKFC_players WHERE playerNumber='" + _motm + "' ON DUPLICATE KEY UPDATE motmTotal = motmTotal + 1, motm_" + _matchDate + " = motm_" + _matchDate + " + 1" + sql2 = "INSERT INTO _hkfc_c_motm (playerNumber, playerName, dotdTotal, dotd_" + _matchDate + ") SELECT playerNumber, playerNickname, '1', '1' FROM _HKFC_players WHERE playerNumber='" + _dotd + "' ON DUPLICATE KEY UPDATE dotdTotal = dotdTotal + 1, dotd_" + _matchDate + " = dotd_" + _matchDate + " + 1" if _comments == "": print("No comment") elif _comments == "Optional comments added here": @@ -147,28 +165,36 @@ def motm_admin(): else: print('Activated') _nextTeam = request.form['nextOppoTeam'] - _nextFixture = request.form['nextMatch'] + _nextMatchDate = request.form['nextMatchDate'] _currMotM = request.form['currMotM'] _currDotD = request.form['currDotD'] sql1 = "SELECT club FROM _clubTeams WHERE displayName='" + _nextTeam + "'" _nextClubName = sql_read_static(sql1) + if not _nextClubName: + flash('Error: Club not found for team ' + _nextTeam, 'error') + return redirect(url_for('motm_admin')) _nextClub = _nextClubName[0]['club'] - sql = "UPDATE hkfcDAdminSettings SET nextFixture='" + _nextFixture + "', nextClub='" + _nextClub + "', nextTeam='" + _nextTeam + "', currMotM=" + _currMotM + ", currDotD=" + _currDotD + "" + sql = "UPDATE motmAdminSettings SET nextDate='" + _nextMatchDate + "', nextClub='" + _nextClub + "', nextTeam='" + _nextTeam + "', currMotM=" + _currMotM + ", currDotD=" + _currDotD + "" sql_write_static(sql) - sql2 = "UPDATE hkfcDAdminSettings INNER JOIN mensHockeyClubs ON hkfcDAdminSettings.nextClub = mensHockeyClubs.hockeyClub SET hkfcDAdminSettings.oppoLogo = mensHockeyClubs.logoURL WHERE mensHockeyClubs.hockeyClub='" + _nextClub + "'" + sql2 = "UPDATE motmAdminSettings INNER JOIN mensHockeyClubs ON motmAdminSettings.nextClub = mensHockeyClubs.hockeyClub SET motmAdminSettings.oppoLogo = mensHockeyClubs.logoURL WHERE mensHockeyClubs.hockeyClub='" + _nextClub + "'" sql_write_static(sql2) if form.saveButton.data: flash('Settings saved!') urlSuffix = randomUrlSuffix(8) print(urlSuffix) - sql3 = "UPDATE hkfcDAdminSettings SET motmUrlSuffix='" + urlSuffix + "' WHERE userid='admin'" + sql3 = "UPDATE motmAdminSettings SET motmUrlSuffix='" + urlSuffix + "' WHERE userid='admin'" sql_write_static(sql3) flash('MotM URL https://hockey.ervine.cloud/motm/'+urlSuffix) elif form.activateButton.data: - sql4 = "ALTER TABLE _hkfc_d_motm ADD COLUMN motm_" + _nextFixture + " smallint DEFAULT 0, ADD COLUMN dotd_" + _nextFixture + " smallint DEFAULT 0, ADD COLUMN assists_" + _nextFixture + " smallint DEFAULT 0, ADD COLUMN goals_" + _nextFixture + " smallint DEFAULT 0 " + # Generate a fixture number based on the date + _nextFixture = _nextMatchDate.replace('-', '') + sql4 = "ALTER TABLE _hkfc_c_motm ADD COLUMN motm_" + _nextFixture + " smallint DEFAULT 0, ADD COLUMN dotd_" + _nextFixture + " smallint DEFAULT 0, ADD COLUMN assists_" + _nextFixture + " smallint DEFAULT 0, ADD COLUMN goals_" + _nextFixture + " smallint DEFAULT 0 " sql_write(sql4) - sql5 = "SELECT motmUrlSuffix FROM hkfcDAdminSettings WHERE userid='admin'" + sql5 = "SELECT motmUrlSuffix FROM motmAdminSettings WHERE userid='admin'" tempSuffix = sql_read_static(sql5) + if not tempSuffix: + flash('Error: Admin settings not found', 'error') + return redirect(url_for('motm_admin')) currSuffix = tempSuffix[0]['motmUrlSuffix'] print(currSuffix) flash('Man of the Match vote is now activated') @@ -176,15 +202,31 @@ def motm_admin(): else: flash('Something went wrong - check with Smithers') - sql7 = "SELECT date, homeTeam, awayTeam, venue, fixtureNumber FROM hockeyFixtures WHERE homeTeam='HKFC D' OR awayTeam='HKFC D'" - matches = sql_read(sql7) - form.nextMatch.choices = [(match['fixtureNumber'], match['date']) for match in matches] + # Load current settings to populate the form + sql_current = "SELECT nextDate FROM motmAdminSettings WHERE userid='admin'" + current_settings = sql_read_static(sql_current) + if current_settings: + from datetime import datetime + try: + current_date = datetime.strptime(current_settings[0]['nextDate'], '%Y-%m-%d').date() + form.nextMatchDate.data = current_date + except: + pass sql4 = "SELECT hockeyClub FROM mensHockeyClubs ORDER BY hockeyClub" - sql5 = "SELECT nextClub, oppoLogo FROM hkfcDAdminSettings" - sql6 = "SELECT playerNumber, playerForenames, playerSurname FROM _hkfcD_matchSquad_" + prevFixture + " ORDER BY playerForenames" + sql5 = "SELECT nextClub, oppoLogo FROM motmAdminSettings" + sql6 = "SELECT playerNumber, playerForenames, playerSurname FROM _hkfcC_matchSquad_" + prevFixture + " ORDER BY playerForenames" clubs = sql_read_static(sql4) settings = sql_read_static(sql5) players = sql_read(sql6) + + # Handle empty results gracefully + if not clubs: + clubs = [] + if not settings: + settings = [{'nextClub': 'Unknown', 'oppoLogo': '/static/images/default_logo.png'}] + if not players: + players = [] + form.nextOppoClub.choices = [(oppo['hockeyClub'], oppo['hockeyClub']) for oppo in clubs] form.currMotM.choices = [(player['playerNumber'], player['playerForenames'] + " " + player['playerSurname']) for player in players] form.currDotD.choices = [(player['playerNumber'], player['playerForenames'] + " " + player['playerSurname']) for player in players] @@ -193,15 +235,286 @@ def motm_admin(): return render_template('motm_admin.html', form=form, nextOppoLogo=clubLogo) +@app.route('/admin/players', methods=['GET']) +@basic_auth.required +def player_management(): + """Admin page for managing players""" + sql = text("SELECT playerNumber, playerForenames, playerSurname, playerNickname, playerTeam FROM _HKFC_players ORDER BY playerNumber") + players = sql_read(sql) + return render_template('player_management.html', players=players) + + +@app.route('/admin/players/add', methods=['GET', 'POST']) +@basic_auth.required +def add_player(): + """Add a new player""" + form = PlayerForm() + + if form.validate_on_submit(): + if form.save_player.data: + # Check if player number already exists + sql_check = text("SELECT playerNumber FROM _HKFC_players WHERE playerNumber = :player_number") + existing = sql_read(sql_check, {'player_number': form.player_number.data}) + + if existing: + flash('Player number already exists!', 'error') + return render_template('add_player.html', form=form) + + # Insert new player + sql = text("INSERT INTO _HKFC_players (playerNumber, playerForenames, playerSurname, playerNickname, playerTeam) VALUES (:player_number, :forenames, :surname, :nickname, :team)") + sql_write(sql, { + 'player_number': form.player_number.data, + 'forenames': form.player_forenames.data, + 'surname': form.player_surname.data, + 'nickname': form.player_nickname.data, + 'team': form.player_team.data + }) + flash('Player added successfully!', 'success') + return redirect(url_for('player_management')) + elif form.cancel.data: + return redirect(url_for('player_management')) + + return render_template('add_player.html', form=form) + + +@app.route('/admin/players/edit/', methods=['GET', 'POST']) +@basic_auth.required +def edit_player(player_number): + """Edit an existing player""" + form = PlayerForm() + + if request.method == 'GET': + # Load player data + sql = text("SELECT playerNumber, playerForenames, playerSurname, playerNickname, playerTeam FROM _HKFC_players WHERE playerNumber = :player_number") + player_data = sql_read(sql, {'player_number': player_number}) + + if not player_data: + flash('Player not found!', 'error') + return redirect(url_for('player_management')) + + player = player_data[0] + form.player_number.data = player['playerNumber'] + form.player_forenames.data = player['playerForenames'] + form.player_surname.data = player['playerSurname'] + form.player_nickname.data = player['playerNickname'] + form.player_team.data = player['playerTeam'] + + if form.validate_on_submit(): + if form.save_player.data: + # Update player + sql = text("UPDATE _HKFC_players SET playerForenames = :forenames, playerSurname = :surname, playerNickname = :nickname, playerTeam = :team WHERE playerNumber = :player_number") + sql_write(sql, { + 'forenames': form.player_forenames.data, + 'surname': form.player_surname.data, + 'nickname': form.player_nickname.data, + 'team': form.player_team.data, + 'player_number': player_number + }) + flash('Player updated successfully!', 'success') + return redirect(url_for('player_management')) + elif form.cancel.data: + return redirect(url_for('player_management')) + + return render_template('edit_player.html', form=form, player_number=player_number) + + +@app.route('/admin/players/delete/', methods=['POST']) +@basic_auth.required +def delete_player(player_number): + """Delete a player""" + sql = text("DELETE FROM _HKFC_players WHERE playerNumber = :player_number") + sql_write(sql, {'player_number': player_number}) + flash('Player deleted successfully!', 'success') + return redirect(url_for('player_management')) + + @app.route('/admin/squad', methods=['GET']) @basic_auth.required def match_squad(): """Admin page for managing match squad""" - sql1 = "SELECT team from _clubTeams WHERE club='HKFC' ORDER BY team" - sql2 = "SELECT playerTeam, playerForenames, playerSurname, playerNickname, playerNumber FROM _HKFC_players" - teams = sql_read(sql1) - players = sql_read(sql2) - return render_template('match_squad.html', teams=teams, players=players) + sql = text("SELECT playerNumber, playerForenames, playerSurname, playerNickname, playerTeam FROM _HKFC_players ORDER BY playerTeam, playerNumber") + players = sql_read(sql) + return render_template('match_squad.html', players=players) + + +# ==================== CLUB MANAGEMENT ==================== + +@app.route('/admin/clubs', methods=['GET']) +@basic_auth.required +def club_management(): + """Admin page for managing clubs""" + sql = text("SELECT id, hockey_club, logo_url FROM clubs ORDER BY hockey_club") + clubs = sql_read(sql) + return render_template('club_management.html', clubs=clubs) + + +@app.route('/admin/clubs/add', methods=['GET', 'POST']) +@basic_auth.required +def add_club(): + """Add a new club""" + form = ClubForm() + + if form.validate_on_submit(): + if form.save_club.data: + # Check if club already exists + sql_check = text("SELECT hockey_club FROM clubs WHERE hockey_club = :club_name") + existing = sql_read(sql_check, {'club_name': form.hockey_club.data}) + + if existing: + flash('Club already exists!', 'error') + return render_template('add_club.html', form=form) + + # Insert new club + sql = text("INSERT INTO clubs (hockey_club, logo_url) VALUES (:club_name, :logo_url)") + sql_write(sql, { + 'club_name': form.hockey_club.data, + 'logo_url': form.logo_url.data + }) + flash('Club added successfully!', 'success') + return redirect(url_for('club_management')) + elif form.cancel.data: + return redirect(url_for('club_management')) + + return render_template('add_club.html', form=form) + + +@app.route('/admin/clubs/edit/', methods=['GET', 'POST']) +@basic_auth.required +def edit_club(club_id): + """Edit an existing club""" + form = ClubForm() + + if request.method == 'GET': + # Load club data + sql = text("SELECT id, hockey_club, logo_url FROM clubs WHERE id = :club_id") + club_data = sql_read(sql, {'club_id': club_id}) + + if not club_data: + flash('Club not found!', 'error') + return redirect(url_for('club_management')) + + club = club_data[0] + form.hockey_club.data = club['hockey_club'] + form.logo_url.data = club['logo_url'] + + if form.validate_on_submit(): + if form.save_club.data: + # Update club + sql = text("UPDATE clubs SET hockey_club = :club_name, logo_url = :logo_url WHERE id = :club_id") + sql_write(sql, { + 'club_name': form.hockey_club.data, + 'logo_url': form.logo_url.data, + 'club_id': club_id + }) + flash('Club updated successfully!', 'success') + return redirect(url_for('club_management')) + elif form.cancel.data: + return redirect(url_for('club_management')) + + return render_template('edit_club.html', form=form, club_id=club_id) + + +@app.route('/admin/clubs/delete/', methods=['POST']) +@basic_auth.required +def delete_club(club_id): + """Delete a club""" + sql = text("DELETE FROM clubs WHERE id = :club_id") + sql_write(sql, {'club_id': club_id}) + flash('Club deleted successfully!', 'success') + return redirect(url_for('club_management')) + + +# ==================== TEAM MANAGEMENT ==================== + +@app.route('/admin/teams', methods=['GET']) +@basic_auth.required +def team_management(): + """Admin page for managing teams""" + sql = text("SELECT id, club, team, display_name, league FROM teams ORDER BY club, team") + teams = sql_read(sql) + return render_template('team_management.html', teams=teams) + + +@app.route('/admin/teams/add', methods=['GET', 'POST']) +@basic_auth.required +def add_team(): + """Add a new team""" + form = TeamForm() + + if form.validate_on_submit(): + if form.save_team.data: + # Check if team already exists + sql_check = text("SELECT club, team FROM teams WHERE club = :club AND team = :team") + existing = sql_read(sql_check, {'club': form.club.data, 'team': form.team.data}) + + if existing: + flash('Team already exists!', 'error') + return render_template('add_team.html', form=form) + + # Insert new team + sql = text("INSERT INTO teams (club, team, display_name, league) VALUES (:club, :team, :display_name, :league)") + sql_write(sql, { + 'club': form.club.data, + 'team': form.team.data, + 'display_name': form.display_name.data, + 'league': form.league.data + }) + flash('Team added successfully!', 'success') + return redirect(url_for('team_management')) + elif form.cancel.data: + return redirect(url_for('team_management')) + + return render_template('add_team.html', form=form) + + +@app.route('/admin/teams/edit/', methods=['GET', 'POST']) +@basic_auth.required +def edit_team(team_id): + """Edit an existing team""" + form = TeamForm() + + if request.method == 'GET': + # Load team data + sql = text("SELECT id, club, team, display_name, league FROM teams WHERE id = :team_id") + team_data = sql_read(sql, {'team_id': team_id}) + + if not team_data: + flash('Team not found!', 'error') + return redirect(url_for('team_management')) + + team = team_data[0] + form.club.data = team['club'] + form.team.data = team['team'] + form.display_name.data = team['display_name'] + form.league.data = team['league'] + + if form.validate_on_submit(): + if form.save_team.data: + # Update team + sql = text("UPDATE teams SET club = :club, team = :team, display_name = :display_name, league = :league WHERE id = :team_id") + sql_write(sql, { + 'club': form.club.data, + 'team': form.team.data, + 'display_name': form.display_name.data, + 'league': form.league.data, + 'team_id': team_id + }) + flash('Team updated successfully!', 'success') + return redirect(url_for('team_management')) + elif form.cancel.data: + return redirect(url_for('team_management')) + + return render_template('edit_team.html', form=form, team_id=team_id) + + +@app.route('/admin/teams/delete/', methods=['POST']) +@basic_auth.required +def delete_team(team_id): + """Delete a team""" + sql = text("DELETE FROM teams WHERE id = :team_id") + sql_write(sql, {'team_id': team_id}) + flash('Team deleted successfully!', 'success') + return redirect(url_for('team_management')) @app.route('/admin/squad/submit', methods=['POST']) @@ -210,9 +523,9 @@ def match_squad_submit(): """Process squad selection""" _playerNumbers = request.form.getlist('playerNumber') for _playerNumber in _playerNumbers: - sql = "INSERT INTO _hkfcD_matchSquad (playerNumber, playerForenames, playerSurname, playerNickname) SELECT playerNumber, playerForenames, playerSurname, playerNickname FROM _HKFC_players WHERE playerNumber='" + _playerNumber + "'" + sql = "INSERT INTO _hkfcC_matchSquad (playerNumber, playerForenames, playerSurname, playerNickname) SELECT playerNumber, playerForenames, playerSurname, playerNickname FROM _HKFC_players WHERE playerNumber='" + _playerNumber + "'" sql_write(sql) - sql2 = "SELECT playerNumber, playerForenames, playerSurname, playerNickname FROM _hkfcD_matchSquad" + sql2 = "SELECT playerNumber, playerForenames, playerSurname, playerNickname FROM _hkfcC_matchSquad" players = sql_read(sql2) table = matchSquadTable(players) table.border = True @@ -224,7 +537,7 @@ def match_squad_submit(): @basic_auth.required def match_squad_list(): """Display current squad list""" - sql = "SELECT playerNumber, playerForenames, playerSurname, playerNickname FROM _hkfcD_matchSquad" + sql = "SELECT playerNumber, playerForenames, playerSurname, playerNickname FROM _hkfcC_matchSquad" players = sql_read(sql) table = matchSquadTable(players) table.border = True @@ -237,7 +550,7 @@ def match_squad_list(): def delPlayerFromSquad(): """Remove player from squad""" _playerNumber = request.args['playerNumber'] - sql = "DELETE FROM _hkfcD_matchSquad WHERE playerNumber=" + _playerNumber + "" + sql = "DELETE FROM _hkfcC_matchSquad WHERE playerNumber=" + _playerNumber + "" sql_write(sql) return render_template('player_removed.html', number=_playerNumber) @@ -248,9 +561,9 @@ def matchSquadReset(): """Reset squad for new match""" _matchNumber = str(mySettings('fixture')) print(_matchNumber) - sql1 = "RENAME TABLE _hkfcD_matchSquad TO _hkfcD_matchSquad_" + _matchNumber + "" - sql2 = "CREATE TABLE _hkfcD_matchSquad (playerNumber smallint UNIQUE, playerForenames varchar(50), playerSurname varchar(30), playerNickname varchar(30) NOT NULL, PRIMARY KEY (playerNumber))" - sql3 = "UPDATE hkfcDAdminSettings SET prevFixture='" + _matchNumber + "'" + sql1 = "RENAME TABLE _hkfcC_matchSquad TO _hkfcC_matchSquad_" + _matchNumber + "" + sql2 = "CREATE TABLE _hkfcC_matchSquad (playerNumber smallint UNIQUE, playerForenames varchar(50), playerSurname varchar(30), playerNickname varchar(30) NOT NULL, PRIMARY KEY (playerNumber))" + sql3 = "UPDATE motmAdminSettings SET prevFixture='" + _matchNumber + "'" sql_write(sql1) sql_write(sql2) sql_write_static(sql3) @@ -262,10 +575,10 @@ def matchSquadReset(): def stats_admin(): """Admin page for managing goals and assists statistics""" form = goalsAssistsForm() - sql = "SELECT date, homeTeam, awayTeam, venue, fixtureNumber FROM hockeyFixtures WHERE homeTeam='HKFC D' OR awayTeam='HKFC D'" + sql = "SELECT date, homeTeam, awayTeam, venue, fixtureNumber FROM hockeyFixtures WHERE homeTeam='HKFC C' OR awayTeam='HKFC C'" matches = sql_read(sql) form.match.choices = [(match['fixtureNumber'], match['date']) for match in matches] - sql2 = "SELECT playerNumber, playerNickname FROM _hkfcD_matchSquad" + sql2 = "SELECT playerNumber, playerNickname FROM _hkfcC_matchSquad" players = sql_read(sql2) return render_template('goals_assists_admin.html', data=players, form=form) @@ -282,7 +595,7 @@ def goalsAssistsSubmit(): goals = request.form.getlist('goals') match = request.form['match'] for idx, player in enumerate(playerNumber): - sql = "INSERT INTO _hkfc_d_motm (playerNumber, playerName, assistsTotal, goalsTotal, assists_" + match + ", goals_" + match + ") SELECT playerNumber, playerNickname, '" + assists[idx] + "', '" + goals[idx] + "', '" + assists[idx] + "', '" + goals[idx] + "' FROM _HKFC_players WHERE playerNumber='" + player + "' ON DUPLICATE KEY UPDATE assistsTotal = assistsTotal + " + assists[idx] + ", goalsTotal = goalsTotal + " + goals[idx] + ", assists_" + match + " = " + assists[idx] + ", goals_" + match + " = " + goals[idx] + "" + sql = "INSERT INTO _hkfc_c_motm (playerNumber, playerName, assistsTotal, goalsTotal, assists_" + match + ", goals_" + match + ") SELECT playerNumber, playerNickname, '" + assists[idx] + "', '" + goals[idx] + "', '" + assists[idx] + "', '" + goals[idx] + "' FROM _HKFC_players WHERE playerNumber='" + player + "' ON DUPLICATE KEY UPDATE assistsTotal = assistsTotal + " + assists[idx] + ", goalsTotal = goalsTotal + " + goals[idx] + ", assists_" + match + " = " + assists[idx] + ", goals_" + match + " = " + goals[idx] + "" sql_write(sql) except Exception as e: print(e) @@ -313,6 +626,8 @@ def admin_fixture_lookup(fixture): """API endpoint for fixture team lookup""" sql = "SELECT homeTeam, awayTeam FROM hockeyFixtures WHERE fixtureNumber='" + fixture + "'" myteams = sql_read(sql) + if not myteams: + return jsonify({'error': 'Fixture not found'}) if myteams[0]['homeTeam'].startswith("HKFC"): nextOppo = myteams[0]['awayTeam'] else: @@ -325,15 +640,21 @@ def admin_fixture_logo_lookup(fixture): """API endpoint for fixture logo lookup""" sql = "SELECT homeTeam, awayTeam FROM hockeyFixtures WHERE fixtureNumber='" + fixture + "'" myteams = sql_read(sql) - if myteams[0]['homeTeam'].startswith("HKFC D"): + if not myteams: + return jsonify({'error': 'Fixture not found'}) + if myteams[0]['homeTeam'].startswith("HKFC C"): nextOppo = myteams[0]['awayTeam'] else: nextOppo = myteams[0]['homeTeam'] sql2 = "SELECT club FROM _clubTeams WHERE displayName ='" + nextOppo + "'" clubs = sql_read_static(sql2) + if not clubs: + return jsonify({'error': 'Club not found'}) clubName = clubs[0]['club'] sql3 = "SELECT logoUrl FROM mensHockeyClubs WHERE hockeyClub ='" + clubName + "'" logo = sql_read_static(sql3) + if not logo: + return jsonify({'error': 'Logo not found'}) clubLogo = logo[0]['logoUrl'] return jsonify(clubLogo) @@ -343,7 +664,7 @@ def vote_results(): """API endpoint for voting results""" _matchDate = str(mySettings('fixture')) print(_matchDate) - sql = "SELECT playerName, motm_" + _matchDate + ", dotd_" + _matchDate + " FROM _hkfc_d_motm WHERE (motm_" + _matchDate + " > '0') OR (dotd_" + _matchDate + " > '0')" + sql = "SELECT playerName, motm_" + _matchDate + ", dotd_" + _matchDate + " FROM _hkfc_c_motm WHERE (motm_" + _matchDate + " > '0') OR (dotd_" + _matchDate + " > '0')" print(sql) rows = sql_read(sql) print(rows) @@ -353,7 +674,7 @@ def vote_results(): @app.route('/api/poty-results') def poty_results(): """API endpoint for Player of the Year results""" - sql = "SELECT playerName, motmTotal, dotdTotal FROM _hkfc_d_motm WHERE (motmTotal > '0') OR (dotdTotal > '0')" + sql = "SELECT playerName, motmTotal, dotdTotal FROM _hkfc_c_motm WHERE (motmTotal > '0') OR (dotdTotal > '0')" print(sql) rows = sql_read(sql) return json.dumps(rows) @@ -382,14 +703,6 @@ def database_setup(): """Admin page for database setup and configuration""" form = DatabaseSetupForm() - # Load current configuration - current_config = db_config_manager.get_config_dict() - - # Populate form with current configuration - for field_name, value in current_config.items(): - if hasattr(form, field_name): - getattr(form, field_name).data = value - if request.method == 'POST': if form.test_connection.data: # Test database connection @@ -452,6 +765,14 @@ def database_setup(): except Exception as e: flash(f'❌ Database initialization failed: {str(e)}', 'error') + # Load current configuration for display + current_config = db_config_manager.get_config_dict() + + # Populate form with current configuration (only for GET requests or after POST processing) + for field_name, value in current_config.items(): + if hasattr(form, field_name): + getattr(form, field_name).data = value + return render_template('database_setup.html', form=form, current_config=current_config) @@ -460,8 +781,10 @@ def database_setup(): def database_status(): """Admin page showing current database status and configuration""" try: - from database import db_config - engine = db_config.engine + # Reload database configuration to get latest settings + from database import DatabaseConfig + current_db_config = DatabaseConfig() + engine = current_db_config.engine # Test connection with engine.connect() as conn: @@ -472,7 +795,7 @@ def database_status(): # Get database info db_info = { - 'database_url': str(db_config.database_url), + 'database_url': str(current_db_config.database_url), 'database_type': os.getenv('DATABASE_TYPE', 'unknown'), 'connection_status': connection_status } diff --git a/motm_app/readSettings.py b/motm_app/readSettings.py index 64ef5de..f019af9 100644 --- a/motm_app/readSettings.py +++ b/motm_app/readSettings.py @@ -5,7 +5,7 @@ from db_config import sql_read_static def mySettings(setting): try: - sql = "SELECT " + setting + " FROM hkfcDAdminSettings WHERE userid='admin'" + sql = "SELECT " + setting + " FROM motmAdminSettings WHERE userid='admin'" rows = sql_read_static(sql) if rows: return rows[0][setting] diff --git a/motm_app/templates/add_club.html b/motm_app/templates/add_club.html new file mode 100644 index 0000000..e7d35f2 --- /dev/null +++ b/motm_app/templates/add_club.html @@ -0,0 +1,74 @@ + + + + + + Add Club - HKFC Men's C Team + + + +
+
+
+
+
+

Add New Club

+
+
+ {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} + {% for category, message in messages %} + + {% endfor %} + {% endif %} + {% endwith %} + +
+ {{ form.hidden_tag() }} + +
+ {{ form.hockey_club.label(class="form-label") }} + {{ form.hockey_club(class="form-control") }} + {% if form.hockey_club.errors %} +
+ {% for error in form.hockey_club.errors %} + {{ error }} + {% endfor %} +
+ {% endif %} +
+ +
+ {{ form.logo_url.label(class="form-label") }} + {{ form.logo_url(class="form-control") }} + {% if form.logo_url.errors %} +
+ {% for error in form.logo_url.errors %} + {{ error }} + {% endfor %} +
+ {% endif %} + Enter the full URL to the club's logo image +
+ +
+ {{ form.cancel(class="btn btn-secondary me-md-2") }} + {{ form.save_club(class="btn btn-primary") }} +
+
+
+
+ + +
+
+
+ + + + diff --git a/motm_app/templates/add_player.html b/motm_app/templates/add_player.html new file mode 100644 index 0000000..78fb72f --- /dev/null +++ b/motm_app/templates/add_player.html @@ -0,0 +1,109 @@ + + + + + + Add Player - HKFC Men's C Team + + + +
+
+
+
+
+

Add New Player

+
+
+ {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} + {% for category, message in messages %} + + {% endfor %} + {% endif %} + {% endwith %} + +
+ {{ form.hidden_tag() }} + +
+ {{ form.player_number.label(class="form-label") }} + {{ form.player_number(class="form-control") }} + {% if form.player_number.errors %} +
+ {% for error in form.player_number.errors %} + {{ error }} + {% endfor %} +
+ {% endif %} +
+ +
+ {{ form.player_forenames.label(class="form-label") }} + {{ form.player_forenames(class="form-control") }} + {% if form.player_forenames.errors %} +
+ {% for error in form.player_forenames.errors %} + {{ error }} + {% endfor %} +
+ {% endif %} +
+ +
+ {{ form.player_surname.label(class="form-label") }} + {{ form.player_surname(class="form-control") }} + {% if form.player_surname.errors %} +
+ {% for error in form.player_surname.errors %} + {{ error }} + {% endfor %} +
+ {% endif %} +
+ +
+ {{ form.player_nickname.label(class="form-label") }} + {{ form.player_nickname(class="form-control") }} + {% if form.player_nickname.errors %} +
+ {% for error in form.player_nickname.errors %} + {{ error }} + {% endfor %} +
+ {% endif %} +
+ +
+ {{ form.player_team.label(class="form-label") }} + {{ form.player_team(class="form-select") }} + {% if form.player_team.errors %} +
+ {% for error in form.player_team.errors %} + {{ error }} + {% endfor %} +
+ {% endif %} +
+ +
+ {{ form.cancel(class="btn btn-secondary me-md-2") }} + {{ form.save_player(class="btn btn-primary") }} +
+
+
+
+ + +
+
+
+ + + + diff --git a/motm_app/templates/add_team.html b/motm_app/templates/add_team.html new file mode 100644 index 0000000..b6ef3ca --- /dev/null +++ b/motm_app/templates/add_team.html @@ -0,0 +1,101 @@ + + + + + + Add Team - HKFC Men's C Team + + + +
+
+
+
+
+

Add New Team

+
+
+ {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} + {% for category, message in messages %} + + {% endfor %} + {% endif %} + {% endwith %} + +
+ {{ form.hidden_tag() }} + +
+ {{ form.club.label(class="form-label") }} + {{ form.club(class="form-control") }} + {% if form.club.errors %} +
+ {% for error in form.club.errors %} + {{ error }} + {% endfor %} +
+ {% endif %} + Enter the club name (e.g., HKFC, KCC, USRC) +
+ +
+ {{ form.team.label(class="form-label") }} + {{ form.team(class="form-control") }} + {% if form.team.errors %} +
+ {% for error in form.team.errors %} + {{ error }} + {% endfor %} +
+ {% endif %} + Enter the team identifier (e.g., A, B, C, 1st, 2nd) +
+ +
+ {{ form.display_name.label(class="form-label") }} + {{ form.display_name(class="form-control") }} + {% if form.display_name.errors %} +
+ {% for error in form.display_name.errors %} + {{ error }} + {% endfor %} +
+ {% endif %} + Enter the full display name (e.g., HKFC A, KCC 1st Team) +
+ +
+ {{ form.league.label(class="form-label") }} + {{ form.league(class="form-control") }} + {% if form.league.errors %} +
+ {% for error in form.league.errors %} + {{ error }} + {% endfor %} +
+ {% endif %} + Enter the league/division (e.g., Premier Division, Division 1) +
+ +
+ {{ form.cancel(class="btn btn-secondary me-md-2") }} + {{ form.save_team(class="btn btn-primary") }} +
+
+
+
+ + +
+
+
+ + + + diff --git a/motm_app/templates/club_management.html b/motm_app/templates/club_management.html new file mode 100644 index 0000000..cb70602 --- /dev/null +++ b/motm_app/templates/club_management.html @@ -0,0 +1,83 @@ + + + + + + Club Management - HKFC Men's C Team + + + +
+
+
+

Club Management

+

Manage hockey clubs in the database

+ + + + {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} + {% for category, message in messages %} + + {% endfor %} + {% endif %} + {% endwith %} + +
+
+
All Clubs
+
+
+ {% if clubs %} +
+ + + + + + + + + + + {% for club in clubs %} + + + + + + + {% endfor %} + +
IDClub NameLogo URLActions
{{ club.id }}{{ club.hockey_club }} + + {{ club.logo_url }} + + + Edit +
+ +
+
+
+ {% else %} +
+
No clubs found
+

There are no clubs in the database. Add the first club to get started.

+
+ {% endif %} +
+
+
+
+
+ + + + diff --git a/motm_app/templates/edit_club.html b/motm_app/templates/edit_club.html new file mode 100644 index 0000000..6e68dba --- /dev/null +++ b/motm_app/templates/edit_club.html @@ -0,0 +1,74 @@ + + + + + + Edit Club - HKFC Men's C Team + + + +
+
+
+
+
+

Edit Club #{{ club_id }}

+
+
+ {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} + {% for category, message in messages %} + + {% endfor %} + {% endif %} + {% endwith %} + +
+ {{ form.hidden_tag() }} + +
+ {{ form.hockey_club.label(class="form-label") }} + {{ form.hockey_club(class="form-control") }} + {% if form.hockey_club.errors %} +
+ {% for error in form.hockey_club.errors %} + {{ error }} + {% endfor %} +
+ {% endif %} +
+ +
+ {{ form.logo_url.label(class="form-label") }} + {{ form.logo_url(class="form-control") }} + {% if form.logo_url.errors %} +
+ {% for error in form.logo_url.errors %} + {{ error }} + {% endfor %} +
+ {% endif %} + Enter the full URL to the club's logo image +
+ +
+ {{ form.cancel(class="btn btn-secondary me-md-2") }} + {{ form.save_club(class="btn btn-primary") }} +
+
+
+
+ + +
+
+
+ + + + diff --git a/motm_app/templates/edit_player.html b/motm_app/templates/edit_player.html new file mode 100644 index 0000000..127ccf7 --- /dev/null +++ b/motm_app/templates/edit_player.html @@ -0,0 +1,103 @@ + + + + + + Edit Player - HKFC Men's C Team + + + +
+
+
+
+
+

Edit Player #{{ player_number }}

+
+
+ {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} + {% for category, message in messages %} + + {% endfor %} + {% endif %} + {% endwith %} + +
+ {{ form.hidden_tag() }} + +
+ {{ form.player_number.label(class="form-label") }} + {{ form.player_number(class="form-control", readonly=true) }} + Player number cannot be changed +
+ +
+ {{ form.player_forenames.label(class="form-label") }} + {{ form.player_forenames(class="form-control") }} + {% if form.player_forenames.errors %} +
+ {% for error in form.player_forenames.errors %} + {{ error }} + {% endfor %} +
+ {% endif %} +
+ +
+ {{ form.player_surname.label(class="form-label") }} + {{ form.player_surname(class="form-control") }} + {% if form.player_surname.errors %} +
+ {% for error in form.player_surname.errors %} + {{ error }} + {% endfor %} +
+ {% endif %} +
+ +
+ {{ form.player_nickname.label(class="form-label") }} + {{ form.player_nickname(class="form-control") }} + {% if form.player_nickname.errors %} +
+ {% for error in form.player_nickname.errors %} + {{ error }} + {% endfor %} +
+ {% endif %} +
+ +
+ {{ form.player_team.label(class="form-label") }} + {{ form.player_team(class="form-select") }} + {% if form.player_team.errors %} +
+ {% for error in form.player_team.errors %} + {{ error }} + {% endfor %} +
+ {% endif %} +
+ +
+ {{ form.cancel(class="btn btn-secondary me-md-2") }} + {{ form.save_player(class="btn btn-primary") }} +
+
+
+
+ + +
+
+
+ + + + diff --git a/motm_app/templates/edit_team.html b/motm_app/templates/edit_team.html new file mode 100644 index 0000000..8676daf --- /dev/null +++ b/motm_app/templates/edit_team.html @@ -0,0 +1,101 @@ + + + + + + Edit Team - HKFC Men's C Team + + + +
+
+
+
+
+

Edit Team #{{ team_id }}

+
+
+ {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} + {% for category, message in messages %} + + {% endfor %} + {% endif %} + {% endwith %} + +
+ {{ form.hidden_tag() }} + +
+ {{ form.club.label(class="form-label") }} + {{ form.club(class="form-control") }} + {% if form.club.errors %} +
+ {% for error in form.club.errors %} + {{ error }} + {% endfor %} +
+ {% endif %} + Enter the club name (e.g., HKFC, KCC, USRC) +
+ +
+ {{ form.team.label(class="form-label") }} + {{ form.team(class="form-control") }} + {% if form.team.errors %} +
+ {% for error in form.team.errors %} + {{ error }} + {% endfor %} +
+ {% endif %} + Enter the team identifier (e.g., A, B, C, 1st, 2nd) +
+ +
+ {{ form.display_name.label(class="form-label") }} + {{ form.display_name(class="form-control") }} + {% if form.display_name.errors %} +
+ {% for error in form.display_name.errors %} + {{ error }} + {% endfor %} +
+ {% endif %} + Enter the full display name (e.g., HKFC A, KCC 1st Team) +
+ +
+ {{ form.league.label(class="form-label") }} + {{ form.league(class="form-control") }} + {% if form.league.errors %} +
+ {% for error in form.league.errors %} + {{ error }} + {% endfor %} +
+ {% endif %} + Enter the league/division (e.g., Premier Division, Division 1) +
+ +
+ {{ form.cancel(class="btn btn-secondary me-md-2") }} + {{ form.save_team(class="btn btn-primary") }} +
+
+
+
+ + +
+
+
+ + + + diff --git a/motm_app/templates/index.html b/motm_app/templates/index.html index d403f3e..87a0191 100644 --- a/motm_app/templates/index.html +++ b/motm_app/templates/index.html @@ -1,6 +1,6 @@ - HKFC Men's D Team - MOTM System + HKFC Men's C Team - MOTM System @@ -11,7 +11,7 @@
-

HKFC Men's D Team - Man of the Match System

+

HKFC Men's C Team - Man of the Match System

Welcome to the MOTM Voting System

This system allows players to vote for Man of the Match and Dick of the Day, while providing admin tools for managing matches and squads.

@@ -31,18 +31,34 @@

Admin Section

+ +

Player Management

+

Add, edit, and manage players in the database

+
+ +

Club Management

+

Add, edit, and manage hockey clubs

+
+ +

Team Management

+

Add, edit, and manage hockey teams

+
+ +

Match Squad Selection

+

Select players for the match squad

+
+ +

View Current Squad

+

View current match squad

+
+ +

Reset Squad

+

Reset squad for new match

+

MOTM Admin

Manage match settings and activate voting

- -

Squad Management

-

Add players to match squads

-
- -

View Squad

-

View current match squad

-

Goals & Assists

Record goals and assists statistics

diff --git a/motm_app/templates/match_comments.html b/motm_app/templates/match_comments.html index 7ebe05a..59d1197 100644 --- a/motm_app/templates/match_comments.html +++ b/motm_app/templates/match_comments.html @@ -1,6 +1,6 @@ - HKFC Men's D Team - Match Comments + HKFC Men's C Team - Match Comments diff --git a/motm_app/templates/match_squad.html b/motm_app/templates/match_squad.html index f7b620d..905d317 100644 --- a/motm_app/templates/match_squad.html +++ b/motm_app/templates/match_squad.html @@ -1,200 +1,73 @@ - - - - - + + + + + + Match Squad Selection - HKFC Men's C Team + + -
- -

Add Players to Squad

- - -{% for team in teams %} -
{{ team.team }} Team Players -

- {% for item in players %} - {% if item.playerTeam == team.team %} - -
- {% endif %} - {% endfor %} -

-
-{% endfor %} - -
-
- - -
-
- - -
- - - - - - - - -
- -
- - - +
+
+
+

Match Squad Selection

+

Select players for the match squad from the available players

+ +
+ + {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} + {% for category, message in messages %} + + {% endfor %} + {% endif %} + {% endwith %} + + {% if players %} +
+
+
+
Available Players
+ Select players to add to the match squad +
+
+
+ {% for player in players %} +
+
+ + +
+
+ {% endfor %} +
+
+ +
+
+ {% else %} +
+
No players available
+

There are no players in the database. Add some players before selecting a squad.

+
+ {% endif %} +
+
+
+ + diff --git a/motm_app/templates/match_squad_selected.html b/motm_app/templates/match_squad_selected.html index 82417a9..9ce3fd7 100644 --- a/motm_app/templates/match_squad_selected.html +++ b/motm_app/templates/match_squad_selected.html @@ -1,6 +1,6 @@ - HKFC Men's D Team - Match Squad Selected + HKFC Men's C Team - Match Squad Selected diff --git a/motm_app/templates/motm_admin.html b/motm_app/templates/motm_admin.html index a863b30..9a63958 100644 --- a/motm_app/templates/motm_admin.html +++ b/motm_app/templates/motm_admin.html @@ -1,13 +1,13 @@ - HKFC Men's D Team - MotM and DotD vote admin + HKFC Men's C Team - MotM and DotD vote admin -

HKFC Men's D Team MotM and DotD online vote admin page

+

HKFC Men's C Team MotM and DotD online vote admin page

{% with messages = get_flashed_messages() %} {% if messages %} {% for message in messages %} @@ -23,7 +23,7 @@

{{ form.csrf_token }} - HKFC D Next Opponent: + HKFC C Next Opponent:

@@ -32,7 +32,7 @@
Date: - {{ form.nextMatch(class_="form-control") }} + {{ form.nextMatchDate(class_="form-control") }}
@@ -74,32 +74,8 @@
diff --git a/motm_app/templates/motm_vote.html b/motm_app/templates/motm_vote.html index 6c431fa..7e46298 100644 --- a/motm_app/templates/motm_vote.html +++ b/motm_app/templates/motm_vote.html @@ -1,13 +1,13 @@ - HKFC Men's D Team - MotM and DotD online vote + HKFC Men's C Team - MotM and DotD online vote -

HKFC Men's D Team MotM and DotD online vote

+

HKFC Men's C Team MotM and DotD online vote

{{ formatDate }}

diff --git a/motm_app/templates/player_management.html b/motm_app/templates/player_management.html new file mode 100644 index 0000000..2347a53 --- /dev/null +++ b/motm_app/templates/player_management.html @@ -0,0 +1,87 @@ + + + + + + Player Management - HKFC Men's C Team + + + +
+
+
+

Player Management

+

Manage players in the HKFC Men's C Team database

+ + + + {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} + {% for category, message in messages %} + + {% endfor %} + {% endif %} + {% endwith %} + +
+
+
All Players
+
+
+ {% if players %} +
+ + + + + + + + + + + + + {% for player in players %} + + + + + + + + + {% endfor %} + +
NumberFirst NamesSurnameNicknameTeamActions
{{ player.playerNumber }}{{ player.playerForenames }}{{ player.playerSurname }}{{ player.playerNickname }} + + {{ player.playerTeam }} + + + Edit +
+ +
+
+
+ {% else %} +
+
No players found
+

There are no players in the database. Add the first player to get started.

+
+ {% endif %} +
+
+
+
+
+ + + + diff --git a/motm_app/templates/team_management.html b/motm_app/templates/team_management.html new file mode 100644 index 0000000..1f81515 --- /dev/null +++ b/motm_app/templates/team_management.html @@ -0,0 +1,83 @@ + + + + + + Team Management - HKFC Men's C Team + + + +
+
+
+

Team Management

+

Manage hockey teams in the database

+ + + + {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} + {% for category, message in messages %} + + {% endfor %} + {% endif %} + {% endwith %} + +
+
+
All Teams
+
+
+ {% if teams %} +
+ + + + + + + + + + + + + {% for team in teams %} + + + + + + + + + {% endfor %} + +
IDClubTeamDisplay NameLeagueActions
{{ team.id }}{{ team.club }}{{ team.team }}{{ team.display_name }}{{ team.league }} + Edit +
+ +
+
+
+ {% else %} +
+
No teams found
+

There are no teams in the database. Add the first team to get started.

+
+ {% endif %} +
+
+
+
+
+ + + + diff --git a/motm_app/templates/vote_thanks.html b/motm_app/templates/vote_thanks.html index 524606f..d9c2443 100644 --- a/motm_app/templates/vote_thanks.html +++ b/motm_app/templates/vote_thanks.html @@ -1,6 +1,6 @@ - HKFC Men's D Team - MotM and DotD vote + HKFC Men's C Team - MotM and DotD vote