From ad5286b043b6fd880a19b2bd64819ee5fa2ba6bb Mon Sep 17 00:00:00 2001 From: GeorgBrantegger Date: Thu, 26 Mar 2026 14:39:31 +0100 Subject: [PATCH] made an athletes list from the contact files --- Nextcloud_Athletes/create_athletes_list.ipynb | 217 ++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100644 Nextcloud_Athletes/create_athletes_list.ipynb diff --git a/Nextcloud_Athletes/create_athletes_list.ipynb b/Nextcloud_Athletes/create_athletes_list.ipynb new file mode 100644 index 0000000..d9d22a0 --- /dev/null +++ b/Nextcloud_Athletes/create_athletes_list.ipynb @@ -0,0 +1,217 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 83, + "id": "152c4ce0", + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "import pandas as pd\n", + "import datetime as dt\n", + "import openpyxl.styles" + ] + }, + { + "cell_type": "code", + "execution_count": 84, + "id": "041b0ab6", + "metadata": {}, + "outputs": [], + "source": [ + "# --- Configuration ---\n", + "NEXTCLOUD_URL = \"https://nextcloud.karnelegger.eu\"\n", + "USERNAME = \"Georg Brantegger\"\n", + "with open('app_pw.txt','r') as f:\n", + " APP_PASSWORD = f.readline()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 85, + "id": "b4c04efb", + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "import vobject\n", + "\n", + "\n", + "# This is the \"URL slug\" of your address book. \n", + "# Usually, if you name it \"Athletes\", the slug is \"athletes\" (lowercase).\n", + "# You can find the exact name by going to Contacts -> Settings (bottom left) -> \n", + "# Click the 3 dots next to your address book -> \"Copy link\". \n", + "# The link will end with /addressbooks/users/username/THIS_PART/\n", + "ADDRESSBOOK_NAME = \"rv-villach-athletinnen\" \n", + "\n", + "\n", + "# The ?export parameter tells Nextcloud to dump the whole address book at once\n", + "CARDDAV_URL = f\"{NEXTCLOUD_URL}/remote.php/dav/addressbooks/users/{USERNAME}/{ADDRESSBOOK_NAME}/?export\"\n", + "\n", + "def get_athlete_data():\n", + " print(f\"Fetching contacts from the '{ADDRESSBOOK_NAME}' address book...\")\n", + " response = requests.get(CARDDAV_URL, auth=(USERNAME, APP_PASSWORD))\n", + " \n", + " if response.status_code != 200:\n", + " print(f\"❌ Error {response.status_code}: Could not fetch address book.\")\n", + " print(\"Check your URL, credentials, and make sure the ADDRESSBOOK_NAME is exactly right.\")\n", + " return []\n", + "\n", + " vcf_data = response.text\n", + " first_names = []\n", + " last_names = []\n", + " genders = []\n", + " years_of_birth = []\n", + "\n", + " # Parse the multi-contact VCF data\n", + " for vcard in vobject.readComponents(vcf_data):\n", + " # The 'n' property in a vCard holds the structured Name (First, Last, etc.)\n", + " if hasattr(vcard, 'n'):\n", + " first_name = vcard.n.value.given\n", + " last_name = vcard.n.value.family\n", + " \n", + " first_names.append(first_name)\n", + " last_names.append(last_name)\n", + " else: print(vcard.fn.value)\n", + " \n", + " if hasattr(vcard, 'note'):\n", + " [_,year_of_birth,gender] = vcard.note.value.split(' ')\n", + " \n", + " genders.append(gender)\n", + " years_of_birth.append(int(year_of_birth))\n", + " \n", + " return last_names,first_names,genders,years_of_birth" + ] + }, + { + "cell_type": "code", + "execution_count": 86, + "id": "3efe3bb1", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Fetching contacts from the 'rv-villach-athletinnen' address book...\n" + ] + } + ], + "source": [ + "a,b,c,d = get_athlete_data()\n", + "data_dict = {'Nachname':a,'Vorname':b,'Gender':c,'Jahrgang':d}\n", + "\n", + "df = pd.DataFrame(data_dict)" + ] + }, + { + "cell_type": "code", + "execution_count": 87, + "id": "a65d7693", + "metadata": {}, + "outputs": [], + "source": [ + "def evaluate_class(row):\n", + " gender = row['Gender']\n", + " yob = row['Jahrgang']\n", + " age = dt.datetime.now().year - yob\n", + " \n", + " if age <= 12:\n", + " c1 = 'Sch'\n", + " c2 = 'B'\n", + " elif 12 < age <= 14:\n", + " c1 = 'Sch'\n", + " c2 = 'A'\n", + " elif 14 < age <= 16:\n", + " c1 = 'Jun'\n", + " c2 = 'B'\n", + " elif 16 < age <= 18:\n", + " c1 = 'Jun'\n", + " c2 = 'A'\n", + " elif 18 < age <= 23:\n", + " c1 = 'Sen'\n", + " c2 = 'B'\n", + " elif 23 < age <= 30:\n", + " c1 = 'Sen'\n", + " c2 = 'A'\n", + " \n", + " return f'{c1}-{gender}-{c2}'\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "529f37c2", + "metadata": {}, + "outputs": [], + "source": [ + "df['Klasse'] = df.apply(evaluate_class,axis=1)\n", + "df[f'Ruderpass {dt.datetime.now().year}'] = 0" + ] + }, + { + "cell_type": "code", + "execution_count": 90, + "id": "7ff6f41c", + "metadata": {}, + "outputs": [], + "source": [ + "file_name = 'temp.xlsx'\n", + "\n", + "with pd.ExcelWriter(file_name, engine='openpyxl') as writer:\n", + " \n", + " df_styled = df.style.set_properties(**{'text-align': 'center'})\n", + " # 2 Write to xlsx\n", + " df_styled.to_excel(writer, sheet_name=\"Athlet_innen\",index=False)\n", + "\n", + " # 3 after writing, change other formats\n", + " # --- Access the openpyxl worksheet object ---\n", + " worksheet = writer.sheets[\"Athlet_innen\"]\n", + "\n", + " # 3.2 format the header\n", + " # Define a bold, larger font\n", + " header_font = openpyxl.styles.Font(name='Arial', size=12, bold=True, color=\"000000\")\n", + "\n", + " worksheet.column_dimensions['A'].width = 18*1.63\n", + " worksheet.column_dimensions['B'].width = 18*0.86\n", + " worksheet.column_dimensions['C'].width = 18*0.72\n", + " worksheet.column_dimensions['D'].width = 18*0.91\n", + " worksheet.column_dimensions['E'].width = 18*0.72\n", + " worksheet.column_dimensions['F'].width = 18*1.45\n", + "\n", + " \n", + " # Iterate through the first row (Header)\n", + " # worksheet[1] returns all cells in the first row\n", + " for cell in worksheet[1]:\n", + " cell.font = header_font\n", + " cell.alignment = openpyxl.styles.Alignment(horizontal='center', vertical='center')\n", + " cell.border = openpyxl.styles.Border(bottom=openpyxl.styles.Side(border_style='medium', color='000000'))\n", + "\n", + " # 3.3 freeze the first row\n", + " worksheet.freeze_panes = 'A2' " + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}