From e65da5fd8fae79daa75e85a90c4671b0a0d1166c Mon Sep 17 00:00:00 2001 From: Akira Date: Sat, 6 Sep 2025 06:15:35 +0900 Subject: [PATCH] checkin status tool --- CPLIST/input/team2025.csv | 53 ++ Dockerfile.event_registration | 21 + EVENT_REGISTRATION_README.md | 204 +++++++ check_checkin_status.py | 319 +++++++++++ docker-compose.event-registration.yml | 34 ++ register_event_users.py | 528 ++++++++++++++++++ .../commands/register_teams_from_csv.py | 45 +- run_event_registration.sh | 95 ++++ イベントユーザー登録 | 42 ++ 9 files changed, 1328 insertions(+), 13 deletions(-) create mode 100644 CPLIST/input/team2025.csv create mode 100644 Dockerfile.event_registration create mode 100644 EVENT_REGISTRATION_README.md create mode 100644 check_checkin_status.py create mode 100644 docker-compose.event-registration.yml create mode 100644 register_event_users.py create mode 100755 run_event_registration.sh create mode 100644 イベントユーザー登録 diff --git a/CPLIST/input/team2025.csv b/CPLIST/input/team2025.csv new file mode 100644 index 0000000..a49531c --- /dev/null +++ b/CPLIST/input/team2025.csv @@ -0,0 +1,53 @@ +部門別数,時間,部門,チーム名,メール,password,電話番号,氏名1,誕生日1,氏名2,誕生日2,氏名3,誕生日3,氏名4,誕生日4,氏名5,誕生日5,氏名6,誕生日6,氏名7,誕生日7,, +1,3,一般,いなりずし,takuyuna1123@icloud.com,ko1703,09014701703,児玉優美,1976/12/13,児玉豊久,1973/11/23,田中広美,1975/10/31,,,,,,,,,, +1,5,一般,Go to the peak!,shibashintan@c.vodafone.ne.jp,shi0145,090-8499-0145,柴山晋太郎,1974/12/14,後藤克弘,1968/04/07,二村修,1967/06/22,,,,,,,,,, +2,3,一般,きみこうじ,chibi-kimi.706@ezweb.ne.jp,sa8309,09062518309,齋藤貴美子,1980/07/06,江口浩次,1968/04/19,,,,,,,,,,,, +2,5,一般,ウエストサイド,chikachan-5101414@i.softbank.jp,go7471,09047997471,後藤睦子,1961/5/1,後藤正寿,1959/7/23,大坪照子,1958/11/11,松村芳美,1964/4/28,,,,,,,, +3,3,一般,ベル,kekomura1008@yahoo.co.jp,ka3001,090-3564-3001,川村健一,1969/10/08,曽我部知奈美,1973/12/17,伊藤徳幸,1975/02/06 ,筒井勝児,1976/05/31,,,,,,,, +3,5,一般,ランエンジョン!,baycools16@gmail.com,ka9749,090÷4790÷9749,河合賢次,1972/12/14,中野真樹,1973/01/23,,,,,,,,,,,, +4,3,一般,ぐりと愉快な仲間たち,kayochu.v.mame.526@icloud.com,na6547,090-1564-6547,長屋香代子,1961/10/27,長屋宣宏,1961/5/26,,,,,,,,,,,, +4,5,一般,坂本555,sakamoto180909@yahoo.co.jp,sa4396,090-8480-4396,坂本正憲,1972/5/30,坂本彩子,1976/3/29,坂本瑠璃子,2003/8/23,,,,,,,,,, +5,3,一般,リキとりんごてぃー,apple1977tea@yahoo.co.jp,te1499,08051241499,鄭寛子,1977/6/13,鄭昌彦,1971/5/26,,,,,,,,,,,, +5,5,一般,East Field,ryo1hi@outlook.com,hi0504,070-8564-0504,東野遼一,1983/09/27,東野智子,1977/03/16,,,,,,,,,,,, +6,3,一般,としちんかずちん,kazu-chin1998@docomo.ne.jp,shi9127,080-2616-9127,渋谷和広,1970/8/1,渋谷敏江,1956/6/16,,,,,,,,,,,, +6,5,一般,M sisters with D,m.kiyomi.115@gmail.com,ma3731,090-4869-3731,前田貴代美,1973/01/15,中濱智恵美,1969/06/16,,,,,,,,,,,, +7,3,一般,シマエナガ,c6d6.lpbm5-s@ezweb.ne.jp,shi1925,090-6336-1925,神谷孫斗,1997/03/02,小栗彩瑚,2001/9/21,,,,,,,,,,,, +7,5,一般,さなっく,santa04230722@icloud.com,ya7192,070-5640-7192,山田朋博,1971/04/23,眞田尚亮,1982/11/30,,,,,,,,,,,, +8,3,一般,煮込みラーメン,t.nishioka1575tt@gmail.com,ni9354,080-8523-9354,西岡嵩倫,1999/1/5,西岡影忠,1971/2/2,,,,,,,,,,,, +9,3,一般,そうたとなゆ,hmt.sota@gmail.com,ho6594,090-1109-6594,甫本創太,1991/06/07,後藤菜友,1994/02/22,,,,,,,,,,,, +10,3,一般,KOJ,balccitomatochop@gmail.com,to5670,090-2181-5670,轟原功樹,1978/08/10,田中美樹,1978/09/07,,,,,,,,,,,, +11,3,一般,サウナとビリヤニ,bitter_smile107@yahoo.co.jp,sa9007,090-4760-9007,坂口祐生,1992/1/7,近藤準,1987/1/25,圓山大貴,1993/5/10,,,,,,,,,, +1,3,お試し・一般,ひろ君と愉快な仲間たち,y0126k@yahoo.co.jp,ya7467,090-9902-7467,山脇裕子,1984/1/26,高橋美智子,1975/04/21,樋口博久,1964/01/08,雨宮功治,1962/05/25,広瀬貴士,1978/08/17,,,,,, +2,3,お試し・一般,フクニシ,appleorange100pct@yahoo.co.jp,fu2792,080-6954-2792,福西直之,1986/2/5,福西愛,1986/3/2,,,,,,,,,,,, +3,3,お試し・一般,あやみち,h613-y5m9t-mich@ezweb.ne.jp,ya3144,090-4447-3144,谷許文音,2006/07/26,谷許美千代,1976/03/27,,,,,,,,,,,, +1,3,お試し・男性ソロ,松村覚司,happy.dreams.come.true923@gmail.com,ma3625,090-8186-3625,松村覚司,1967/9/23,,,,,,,,,,,,,, +2,3,お試し・男性ソロ,高野清司,wakano_528@yahoo.co.jp,ta5865,090-5603-5865,高野清司,71歳,,,,,,,,,,,,,, +1,3,お試し・ファミリー,まゆちー,takoyaki_sena@icloud.com,a1246,090-6090-1246,浅田舞子,1986/02/22,浅田真結菜,2014/03/30,森美紀,1988/03/06,森千晴,2017/8/4,,,,,,,, +1,5,お試し・ファミリー,ポエドリ,takagitoshihiro8@yahoo.co.jp,ta4245,090-5866-4245,高木俊裕,1984/03/09,,,,,,,,,,,,,, +2,3,お試し・ファミリー,ガンバルゾー,youkeymr.01@gmail.com,mo6605,090-6080-6605,森祐貴,1985/9/26,浅田直之,1987/12/12,浅田晃汰,2014/01/06,森光喜,2015/4/22,,,,,,,, +2,5,お試し・ファミリー,fun!fun!うごchan,fulayota333@gmail.com,ha7384,090-6599-7384,早川宏美,1975/6/15,,,,,,,,,,,,,, +3,3,お試し・ファミリー,チームT,sphin28420@aim.com,te1882,080-6709-1882,寺田剛,1979/06/04,寺田恭子,1985/01/10,寺田向希,2023/11/08,,,,,,,,,, +1,3,女性ソロ,山下和乃,kazjamster@gmail.com,ya2450,090-4229-2450,山下和乃,2004/4/26,,,,,,,,,,,,,, +1,5,女性ソロ,Best Wishes,thunderhead_56@yahoo.co.jp,ha7226,090-5652-7226,長谷川美貴,1973/5/6,,,,,,,,,,,,,, +1,3,男性ソロ,しーくん,redleif57917913@ezweb.ne.jp,mi6827,090-2946-6827,水門茂,1962/12/24,,,,,,,,,,,,,, +1,5,男性ソロ,風呂の会,1845dondon@gmail.com,a9050,09096369050,浅井貴弘,1984/07/11,,,,,,,,,,,,,, +2,3,男性ソロ,野田達男,tatchi.sat111@docomo.ne.jp,no0873,0901417-0873,野田達男,1950/9/14,,,,,,,,,,,,,, +2,5,男性ソロ,近藤隆,kondo2000gt@yahoo.ne.jp,ko0666,09018300666,近藤隆,1962/6/28,,,,,,,,,,,,,, +3,3,男性ソロ,日吉将大,hiyomasa0034@gmail.com,hi6343,080-2733-6343,日吉将大,1995/09/14,,,,,,,,,,,,,, +3,5,男性ソロ,松野昌紀,matsubottkuri11994730@gmail.com,ma2606,090-1272-2606,松野昌紀,1972/9/30,,,,,,,,,,,,,, +4,3,男性ソロ,東京OLクラブ,abe_1755_31@yahoo.co.jp,a7102,090-2203-7102,阿部昌隆,1956/4/20,,,,,,,,,,,,,, +4,5,男性ソロ,白木稔人,amida48gan@icloud.com,shi6048,090-7302-6048,白木稔人,1972/5/17,,,,,,,,,,,,,, +5,3,男性ソロ,大阪OLC,t.okiura1961@gmail.com,o1141,090-7888-1141,沖浦徹二,1961/4/29,,,,,,,,,,,,,, +5,5,男性ソロ,Best Wishes,jovi_bounce14@yahoo.co.jp,ko0716,090−3284−0716,小林寿郎,1973/10/26,,,,,,,,,,,,,, +6,3,男性ソロ,つるまいOLC,junhagi68@gmail.com,ha1001,080-3159-1001,萩原淳,1968/3/17,,,,,,,,,,,,,, +6,5,男性ソロ,脇屋貴司,takarinkuririn@gmail.com,wa2659,080-3508-2659,脇屋貴司,1983/10/26,,,,,,,,,,,,,, +7,3,男性ソロ,㈱大垣ケーブルテレビ,so-kishida@ogaki-tv.co.jp,ki1207,0584-82-1207,岸田爽,2001/8/12,,,,,,,,,,,,,, +7,5,男性ソロ,前川一彦,yoshino-chuo@docomo.ne.jp,ma2351,090-1074-2351,前川一彦,不明,,,,,,,,,,,,,, +8,3,男性ソロ,㈱大垣ケーブルテレビ,ta-shiba@ogaki-tv.co.jp,shi1207,,芝建,1998/11/9,,,,,,,,,,,,,, +1,3,ファミリー,うぱうぱアイランド,serukasu@gmail.com,i4200,09084584200,伊藤由美子,19920328,伊藤嘉仁,19930825,伊藤嘉利,20220913,,,,,,,,,, +1,5,ファミリー,ながれぼし,h2798723ddwyus@i.softbank.jp,ta8317,090-1782-8317,高田めぐみ,1982/4/28,高田志穂,2013/12/5,,,,,,,,,,,, +2,3,ファミリー,Team117,miki.maki0107@gmail.com,sa3915,090-7678-3915,佐々木孝好,1970/12/20,佐々木享子,1977/8/25,佐々木実希,2012/1/21,佐々木麻妃,2016/7/1,,,,,,,, +2,5,ファミリー,500えん,roumnet@yahoo.co.jp,go6814,090-9890-6814,五百木弘道,1972/4/29,五百木芽彩,2015/3/13,,,,,,,,,,,, +3,3,ファミリー,チームしぇいや,rayrain3000@docomo.ne.jp,ya2905,090-3056-2905,山本龍也,1976/3/14,山本聖也,2009/9/9,山本輝也,2015/6/3,,,,,,,,,, +3,5,ファミリー,チームユズ,livertish_v.g.35@docomo.ne.jp,ko7822,090-7311-7822,小出龍,1983/2/27,小出柚希,2019/1/7,,,,,,,,,,,, +4,3,ファミリー,Y'sファミリー,inukisen@gmail.com,ya1285,09042581285,安田千穂,1984/3/7,安田尚広,1978/1/18,安田雫,2014/9/2,安田葵,2018/5/13,,,,,,,, \ No newline at end of file diff --git a/Dockerfile.event_registration b/Dockerfile.event_registration new file mode 100644 index 0000000..a491fe2 --- /dev/null +++ b/Dockerfile.event_registration @@ -0,0 +1,21 @@ +FROM python:3.10-slim + +WORKDIR /app + +# 必要なパッケージをインストール +RUN apt-get update && apt-get install -y \ + curl \ + && rm -rf /var/lib/apt/lists/* + +# Python依存関係をインストール +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +# アプリケーションコードをコピー +COPY . . + +# スクリプトに実行権限を付与 +RUN chmod +x register_event_users.py + +# デフォルトコマンド +CMD ["python", "register_event_users.py", "--help"] diff --git a/EVENT_REGISTRATION_README.md b/EVENT_REGISTRATION_README.md new file mode 100644 index 0000000..1123fde --- /dev/null +++ b/EVENT_REGISTRATION_README.md @@ -0,0 +1,204 @@ +# イベントユーザー登録システム + +外部システムAPI仕様書.mdを前提に、ユーザーデータCSVから各ユーザーごとにユーザー登録、チーム登録、エントリー登録、イベント参加を行うPythonスクリプトです。 + +## 概要 + +このシステムは以下の処理を自動化します: + +1. **カスタムユーザー登録 API** + - メールアドレスをキーに既存ユーザーを取得 + - 検索がヒットしなければ、ユーザー登録 + - 検索がヒットすれば、パスワードを更新 + - event_codeに指定event_codeを設定 + - zekken_number にゼッケン番号を入力 + - team_name にチーム名を入力 + +2. **チーム登録、メンバー登録** + - 部門・時間・チーム名でチーム登録 + - メンバーを1名ずつ7名まで登録 + - それぞれダミーメールアドレスと名前と生年月日でメンバー登録 + +3. **エントリー登録** + - 指定されたイベントにチームを登録 + +4. **イベント参加** + - 登録したエントリーでイベント参加 + +## CSVファイル形式 + +CSVファイル(`CPLIST/input/team2025.csv`)は以下の項目を持ちます: + +``` +部門別数,時間,部門,チーム名,メール,パスワード,電話番号,氏名1,誕生日1,氏名2,誕生日2,氏名3,誕生日3,氏名4,誕生日4,氏名5,誕生日5,氏名6,誕生日6,氏名7,誕生日7,, +``` + +### 項目説明 + +- **部門別数**: 部門の番号 +- **時間**: 競技時間 +- **部門**: 競技部門名 +- **チーム名**: チーム名 +- **メール**: 代表者メールアドレス +- **パスワード**: パスワード +- **電話番号**: 代表者電話番号 +- **氏名1〜7**: チームメンバーの氏名(最大7名) +- **誕生日1〜7**: チームメンバーの生年月日(YYYY/MM/DD形式) + +## 使用方法 + +### 1. 基本的な実行 + +```bash +# デフォルトイベントコード(大垣2509)で実行 +./run_event_registration.sh + +# 指定したイベントコードで実行 +./run_event_registration.sh "大垣2509" +``` + +### 2. テスト実行(DRY RUN) + +実際のAPI呼び出しを行わずに処理の流れを確認: + +```bash +./run_event_registration.sh "大垣2509" --dry-run +``` + +### 3. カスタムCSVファイルを使用 + +```bash +./run_event_registration.sh "大垣2509" --csv-file CPLIST/input/custom_teams.csv +``` + +### 4. カスタムAPI URLを指定 + +```bash +./run_event_registration.sh "大垣2509" --base-url http://production-server:8000 +``` + +### 5. Pythonスクリプトを直接実行 + +```bash +python register_event_users.py --event_code "大垣2509" --csv_file CPLIST/input/team2025.csv --dry_run +``` + +## Docker Composeでの実行 + +### 環境変数設定 + +```bash +export EVENT_CODE="大垣2509" +export CSV_FILE="CPLIST/input/team2025.csv" +export BASE_URL="http://web:8000" +export DRY_RUN="true" # テスト実行の場合 +``` + +### 実行 + +```bash +docker-compose -f docker-compose.event-registration.yml up --build +``` + +## オプション + +| オプション | 説明 | デフォルト値 | +|-----------|------|-------------| +| `--event_code` | イベントコード | 必須 | +| `--csv_file` | CSVファイルパス | `CPLIST/input/team2025.csv` | +| `--base_url` | APIベースURL | `http://localhost:8000` | +| `--dry_run` | テスト実行フラグ | False | + +## ログ + +- 実行ログは `logs/register_event_users.log` に出力されます +- コンソールにも同時出力されます + +## 処理統計 + +処理完了後、以下の統計情報が表示されます: + +- 処理完了チーム数 +- 作成ユーザー数 +- 更新ユーザー数 +- 登録チーム数 +- 作成エントリー数 +- 参加登録数 +- エラー数とその詳細 + +## 注意事項 + +1. **API認証**: システムが稼働していることを確認してください +2. **CSVファイル**: 必要な項目が正しく入力されていることを確認してください +3. **重複処理**: 同じデータを複数回実行すると重複エラーが発生する可能性があります +4. **メール認証**: 新規ユーザー登録時はメール認証が必要な場合があります + +## トラブルシューティング + +### よくあるエラー + +1. **CSVファイルが見つからない** + ``` + エラー: CSVファイルが見つかりません: CPLIST/input/team2025.csv + ``` + → CSVファイルのパスを確認してください + +2. **API接続エラー** + ``` + エラー: APIサーバーに接続できません + ``` + → BASE_URLが正しいか、サーバーが稼働しているか確認してください + +3. **重複ゼッケン番号エラー** + ``` + チーム登録エラー: このゼッケン番号は既に使用されています + ``` + → 既に登録済みのデータを再実行しようとしています + +### ログの確認 + +```bash +# リアルタイムでログを確認 +tail -f logs/register_event_users.log + +# エラーのみを確認 +grep ERROR logs/register_event_users.log +``` + +## 開発者向け情報 + +### ファイル構成 + +``` +rogaining_srv/ +├── register_event_users.py # メインスクリプト +├── run_event_registration.sh # 実行スクリプト +├── docker-compose.event-registration.yml # Docker Compose設定 +├── Dockerfile.event_registration # Dockerfile +├── CPLIST/input/team2025.csv # CSVデータファイル +└── logs/register_event_users.log # ログファイル +``` + +### API エンドポイント + +使用するAPIエンドポイント: + +- `POST /api/register/` - ユーザー仮登録 +- `POST /api/login/` - ログイン +- `POST /api/register_team` - チーム登録 +- `POST /api/teams/{team_id}/members/` - メンバー追加 +- `POST /api/entry/` - エントリー登録 +- `POST /api/start_from_rogapp` - イベント参加 + +### カスタマイズ + +処理をカスタマイズする場合は、`register_event_users.py`の以下のメソッドを編集してください: + +- `get_or_create_user()` - ユーザー登録ロジック +- `register_team_and_members()` - チーム登録ロジック +- `create_event_entry()` - エントリー登録ロジック +- `participate_in_event()` - イベント参加ロジック + +## ライセンス + +このプロジェクトはロゲイニングシステムの一部です。 diff --git a/check_checkin_status.py b/check_checkin_status.py new file mode 100644 index 0000000..52c6721 --- /dev/null +++ b/check_checkin_status.py @@ -0,0 +1,319 @@ +#!/usr/bin/env python3 +""" +チェックイン機能確認ツール: 総合的にチェックイン機能の状態を調査 +""" + +import subprocess +import requests +import json +from datetime import datetime +import time + +def check_checkin_api_status(): + """ + チェックインAPIの基本動作確認 + """ + print("🔍 チェックインAPI動作確認") + print("=" * 50) + + # 基本的な接続確認 + test_urls = [ + "http://localhost:8100/gifuroge/checkin_from_rogapp", + "http://localhost:8100/api/checkin_from_rogapp" + ] + + for url in test_urls: + try: + # GETリクエストでエンドポイントの存在確認 + response = requests.get(url, timeout=5) + print(f"✅ {url} → HTTP {response.status_code}") + + if response.status_code == 405: + print(f" 💡 405 Method Not Allowed は正常(POSTのみ許可)") + elif response.status_code == 404: + print(f" ❌ 404 Not Found - エンドポイントが見つからない") + + except requests.exceptions.ConnectionError: + print(f"❌ {url} → 接続エラー") + except Exception as e: + print(f"❌ {url} → エラー: {e}") + + print() + +def test_checkin_with_real_data(): + """ + 実際のデータでチェックインテスト + """ + print("🎯 実際のデータでチェックインテスト") + print("-" * 50) + + # 実際のイベントとチームを取得 + try: + result = subprocess.run([ + 'docker', 'compose', 'exec', 'app', 'python', 'manage.py', 'shell', '-c', + """ +from rog.models import NewEvent2, Entry, Team +# 最新のイベント取得 +event = NewEvent2.objects.first() +if event: + print(f"EVENT:{event.event_name}") + # そのイベントのエントリー取得 + entry = Entry.objects.filter(event=event).first() + if entry and entry.team: + print(f"TEAM:{entry.team.team_name}") + print(f"ZEKKEN:{entry.zekken_number}") + # スタート済みかチェック + from rog.models import GpsLog + start_log = GpsLog.objects.filter( + zekken_number=entry.zekken_number, + event_code=event.event_name, + cp_number='START' + ).first() + print(f"STARTED:{bool(start_log)}") + else: + print("TEAM:None") +else: + print("EVENT:None") + """ + ], capture_output=True, text=True) + + lines = result.stdout.strip().split('\n') + event_name = None + team_name = None + zekken_number = None + is_started = False + + for line in lines: + if line.startswith('EVENT:'): + event_name = line.split(':', 1)[1] + elif line.startswith('TEAM:'): + team_name = line.split(':', 1)[1] + elif line.startswith('ZEKKEN:'): + zekken_number = line.split(':', 1)[1] + elif line.startswith('STARTED:'): + is_started = line.split(':', 1)[1] == 'True' + + print(f"📊 取得したテストデータ:") + print(f" イベント: {event_name}") + print(f" チーム: {team_name}") + print(f" ゼッケン: {zekken_number}") + print(f" スタート済み: {is_started}") + + if event_name and team_name and event_name != 'None' and team_name != 'None': + # チェックインテスト実行 + test_data = { + "event_code": event_name, + "team_name": team_name, + "cp_number": "1", + "image": "data:image/jpeg;base64,test", + "buy_flag": False + } + + print(f"\n🚀 チェックインテスト実行:") + print(f" URL: http://localhost:8100/api/checkin_from_rogapp") + print(f" データ: {json.dumps(test_data, ensure_ascii=False, indent=2)}") + + try: + response = requests.post( + "http://localhost:8100/api/checkin_from_rogapp", + json=test_data, + headers={'Content-Type': 'application/json'}, + timeout=10 + ) + + print(f"\n📥 レスポンス:") + print(f" ステータス: HTTP {response.status_code}") + print(f" 内容: {response.text}") + + if response.status_code == 400: + response_data = response.json() + if "スタートしていません" in response_data.get('message', ''): + print(f"\n💡 スタート処理が必要です。start_from_rogapp APIを先に実行してください。") + return test_start_api(event_name, team_name) + + except Exception as e: + print(f"❌ チェックインテストエラー: {e}") + else: + print(f"❌ テストデータが不足しています") + + except Exception as e: + print(f"❌ データ取得エラー: {e}") + +def test_start_api(event_name, team_name): + """ + スタートAPIのテスト + """ + print(f"\n🏁 スタートAPIテスト") + print("-" * 30) + + start_data = { + "event_code": event_name, + "team_name": team_name, + "image": "data:image/jpeg;base64,start_test" + } + + try: + response = requests.post( + "http://localhost:8100/gifuroge/start_from_rogapp", + json=start_data, + headers={'Content-Type': 'application/json'}, + timeout=10 + ) + + print(f"📥 スタートAPIレスポンス:") + print(f" ステータス: HTTP {response.status_code}") + print(f" 内容: {response.text}") + + if response.status_code == 200: + print(f"✅ スタート成功!チェックインを再試行します...") + time.sleep(1) + # チェックインを再試行 + test_checkin_after_start(event_name, team_name) + + except Exception as e: + print(f"❌ スタートAPIエラー: {e}") + +def test_checkin_after_start(event_name, team_name): + """ + スタート後のチェックインテスト + """ + print(f"\n🎯 スタート後チェックインテスト") + print("-" * 30) + + checkin_data = { + "event_code": event_name, + "team_name": team_name, + "cp_number": "1", + "image": "data:image/jpeg;base64,checkin_test", + "buy_flag": False + } + + try: + response = requests.post( + "http://localhost:8100/api/checkin_from_rogapp", + json=checkin_data, + headers={'Content-Type': 'application/json'}, + timeout=10 + ) + + print(f"📥 チェックインレスポンス:") + print(f" ステータス: HTTP {response.status_code}") + print(f" 内容: {response.text}") + + if response.status_code == 200: + print(f"🎉 チェックイン成功!") + elif response.status_code == 400: + print(f"⚠️ チェックイン失敗(400)") + + except Exception as e: + print(f"❌ チェックインエラー: {e}") + +def check_recent_logs(): + """ + 最近のログを確認 + """ + print(f"\n📋 最近のチェックイン関連ログ") + print("-" * 50) + + try: + result = subprocess.run([ + 'docker', 'compose', 'logs', '--tail=30', 'app' + ], capture_output=True, text=True) + + lines = result.stdout.split('\n') + checkin_logs = [] + + for line in lines: + if any(keyword in line.lower() for keyword in ['checkin', 'start', 'gpslog', '502', '400', '405']): + checkin_logs.append(line) + + if checkin_logs: + print("🔍 関連ログ:") + for log in checkin_logs[-10:]: # 最新10件 + print(f" {log}") + else: + print(" 📝 チェックイン関連のログが見つかりませんでした") + + except Exception as e: + print(f"❌ ログ確認エラー: {e}") + +def check_database_status(): + """ + データベースの状態確認 + """ + print(f"\n💾 データベース状態確認") + print("-" * 50) + + try: + result = subprocess.run([ + 'docker', 'compose', 'exec', 'app', 'python', 'manage.py', 'shell', '-c', + """ +from rog.models import GpsLog, NewEvent2, Entry +import datetime + +# 最近のGpsLogエントリー +recent_logs = GpsLog.objects.order_by('-id')[:5] +print(f"RECENT_LOGS:{len(recent_logs)}") +for log in recent_logs: + print(f"LOG:{log.id}|{log.event_code}|{log.zekken_number}|{log.cp_number}|{log.checkin_time}") + +# イベント数 +event_count = NewEvent2.objects.count() +print(f"EVENTS:{event_count}") + +# エントリー数 +entry_count = Entry.objects.count() +print(f"ENTRIES:{entry_count}") + """ + ], capture_output=True, text=True) + + lines = result.stdout.strip().split('\n') + + for line in lines: + if line.startswith('RECENT_LOGS:'): + count = line.split(':', 1)[1] + print(f" 最近のGpsLogエントリー: {count}件") + elif line.startswith('LOG:'): + parts = line.split(':', 1)[1].split('|') + if len(parts) >= 5: + print(f" ID:{parts[0]} イベント:{parts[1]} ゼッケン:{parts[2]} CP:{parts[3]} 時刻:{parts[4]}") + elif line.startswith('EVENTS:'): + count = line.split(':', 1)[1] + print(f" 総イベント数: {count}") + elif line.startswith('ENTRIES:'): + count = line.split(':', 1)[1] + print(f" 総エントリー数: {count}") + + except Exception as e: + print(f"❌ データベース確認エラー: {e}") + +def main(): + """ + メイン実行関数 + """ + print("🚀 チェックイン機能 総合確認ツール") + print(f"実行時刻: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") + print("=" * 60) + + # 1. API基本動作確認 + check_checkin_api_status() + + # 2. データベース状態確認 + check_database_status() + + # 3. 実際のデータでテスト + test_checkin_with_real_data() + + # 4. 最近のログ確認 + check_recent_logs() + + print(f"\n📊 確認完了") + print("=" * 60) + print("💡 次のステップ:") + print(" 1. 502エラーが出る場合 → nginx設定確認") + print(" 2. 405エラーが出る場合 → URLパス確認") + print(" 3. 400エラーが出る場合 → データ確認") + print(" 4. スタート前エラー → start_from_rogapp API実行") + +if __name__ == "__main__": + main() diff --git a/docker-compose.event-registration.yml b/docker-compose.event-registration.yml new file mode 100644 index 0000000..ace6134 --- /dev/null +++ b/docker-compose.event-registration.yml @@ -0,0 +1,34 @@ +version: '3.8' + +services: + event-registration: + build: + context: . + dockerfile: Dockerfile.event_registration + container_name: rogaining_event_registration + volumes: + - ./CPLIST/input:/app/CPLIST/input:ro + - ./logs:/app/logs + environment: + - EVENT_CODE=${EVENT_CODE:-大垣2509} + - CSV_FILE=${CSV_FILE:-CPLIST/input/team2025.csv} + - BASE_URL=${BASE_URL:-http://web:8000} + - DRY_RUN=${DRY_RUN:-false} + networks: + - rogaining_network + depends_on: + - web + command: > + sh -c " + echo 'イベントユーザー登録処理を開始します...' && + python register_event_users.py + --event_code $${EVENT_CODE} + --csv_file $${CSV_FILE} + --base_url $${BASE_URL} + $${DRY_RUN:+--dry_run} + " + + # 既存のサービス(webなど)を参照するためのネットワーク定義 +networks: + rogaining_network: + external: true diff --git a/register_event_users.py b/register_event_users.py new file mode 100644 index 0000000..5d612e8 --- /dev/null +++ b/register_event_users.py @@ -0,0 +1,528 @@ +#!/usr/bin/env python +""" +イベントユーザー登録スクリプト + +外部システムAPI仕様書.mdを前提に、ユーザーデータCSVから、 +各ユーザーごとにユーザー登録、チーム登録、エントリー登録、イベント参加を行う +docker composeで実施するPythonスクリプト + +使用方法: +python register_event_users.py --event_code 大垣2509 + +ユーザーデータのCSVは以下の項目を持つ: +部門別数,時間,部門,チーム名,メール,パスワード,電話番号,氏名1,誕生日1,氏名2,誕生日2,氏名3,誕生日3,氏名4,誕生日4,氏名5,誕生日5,氏名6,誕生日6,氏名7,誕生日7,, +""" + +import os +import sys +import csv +import requests +import argparse +import logging +from datetime import datetime, date +import time +import json +from typing import Dict, List, Optional, Tuple + +# ログ設定 +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s', + handlers=[ + logging.FileHandler('register_event_users.log'), + logging.StreamHandler() + ] +) +logger = logging.getLogger(__name__) + + +class EventUserRegistration: + def __init__(self, event_code: str, base_url: str = "http://localhost:8000", dry_run: bool = False): + """ + イベントユーザー登録クラス + + Args: + event_code: イベントコード(例: 大垣2509) + base_url: APIベースURL + dry_run: テスト実行フラグ + """ + self.event_code = event_code + self.base_url = base_url.rstrip('/') + self.dry_run = dry_run + self.session = requests.Session() + self.admin_token = None + + # 統計情報 + self.stats = { + 'processed_teams': 0, + 'users_created': 0, + 'users_updated': 0, + 'teams_registered': 0, + 'entries_created': 0, + 'participations_created': 0, + 'errors': [] + } + + logger.info(f"Event User Registration initialized for event: {event_code}") + if dry_run: + logger.info("DRY RUN MODE - No actual API calls will be made") + + def get_or_create_user(self, email: str, password: str, firstname: str, lastname: str, + date_of_birth: str, phone: str) -> Tuple[bool, Optional[str], Optional[str]]: + """ + メールアドレスをキーに既存ユーザーを取得、存在しなければ新規作成 + + Args: + email: メールアドレス + password: パスワード + firstname: 名前 + lastname: 姓 + date_of_birth: 生年月日 (YYYY/MM/DD形式) + phone: 電話番号 + + Returns: + Tuple[success, user_id, token] + """ + if self.dry_run: + logger.info(f"[DRY RUN] Would get or create user: {email}") + return True, "dummy_user_id", "dummy_token" + + try: + # まずログインを試行して既存ユーザーかチェック + login_data = { + "identifier": email, + "password": password + } + + response = self.session.post(f"{self.base_url}/login/", json=login_data) + + if response.status_code == 200: + # 既存ユーザーの場合、パスワード更新(実際にはパスワード更新APIが必要) + result = response.json() + token = result.get('token') + user_id = result.get('user', {}).get('id') + + logger.info(f"既存ユーザーでログイン成功: {email}") + self.stats['users_updated'] += 1 + return True, str(user_id), token + + elif response.status_code == 401: + # ユーザーが存在しないか、パスワードが間違っている場合、新規登録を試行 + return self._create_new_user(email, password, firstname, lastname, date_of_birth) + + else: + logger.error(f"ログイン試行でエラー: {response.status_code} - {response.text}") + return False, None, None + + except Exception as e: + logger.error(f"ユーザー認証エラー: {str(e)}") + return False, None, None + + def _create_new_user(self, email: str, password: str, firstname: str, lastname: str, + date_of_birth: str) -> Tuple[bool, Optional[str], Optional[str]]: + """ + 新規ユーザーを作成 + """ + try: + # 生年月日をYYYY-MM-DD形式に変換 + if '/' in date_of_birth: + date_parts = date_of_birth.split('/') + if len(date_parts) == 3: + birth_date = f"{date_parts[0]}-{date_parts[1].zfill(2)}-{date_parts[2].zfill(2)}" + else: + birth_date = "1990-01-01" # デフォルト値 + else: + birth_date = date_of_birth + + # 仮ユーザー登録 + register_data = { + "email": email, + "password": password, + "firstname": firstname, + "lastname": lastname, + "date_of_birth": birth_date, + "female": False, # デフォルト値 + "is_rogaining": True + } + + response = self.session.post(f"{self.base_url}/register/", json=register_data) + + if response.status_code in [200, 201]: + logger.info(f"仮ユーザー登録成功: {email}") + + # 実際のシステムでは、メール認証コードを使って本登録を完了する必要があります + # ここでは簡略化のため、直接ログインを試行します + time.sleep(1) # 少し待機 + + login_data = { + "identifier": email, + "password": password + } + + login_response = self.session.post(f"{self.base_url}/login/", json=login_data) + + if login_response.status_code == 200: + result = login_response.json() + token = result.get('token') + user_id = result.get('user', {}).get('id') + + logger.info(f"新規ユーザーのログイン成功: {email}") + self.stats['users_created'] += 1 + return True, str(user_id), token + else: + logger.warning(f"新規ユーザーのログインに失敗: {email}") + # メール認証が必要な可能性があります + self.stats['users_created'] += 1 + return True, "pending_verification", None + + else: + error_msg = response.text + logger.error(f"ユーザー登録失敗: {email} - {error_msg}") + return False, None, None + + except Exception as e: + logger.error(f"新規ユーザー作成エラー: {str(e)}") + return False, None, None + + def register_team_and_members(self, team_data: Dict, zekken_number: int) -> Tuple[bool, Optional[str]]: + """ + チーム登録とメンバー登録 + + Args: + team_data: チームデータ(CSVの1行分) + zekken_number: ゼッケン番号 + + Returns: + Tuple[success, team_id] + """ + if self.dry_run: + logger.info(f"[DRY RUN] Would register team: {team_data['チーム名']} with zekken: {zekken_number}") + return True, "dummy_team_id" + + try: + # チーム登録データを準備 + register_data = { + "zekken_number": zekken_number, + "event_code": self.event_code, + "team_name": team_data['チーム名'], + "class_name": team_data['部門'], + "password": team_data['パスワード'] + } + + # チーム登録API呼び出し + response = self.session.post(f"{self.base_url}/register_team", json=register_data) + + if response.status_code in [200, 201]: + result = response.json() + if result.get('status') == 'OK': + team_id = result.get('team_id') + logger.info(f"チーム登録成功: {team_data['チーム名']} (zekken: {zekken_number})") + self.stats['teams_registered'] += 1 + + # メンバー登録 + success = self._register_team_members(team_data, team_id) + return success, str(team_id) + else: + logger.error(f"チーム登録エラー: {result.get('message')}") + return False, None + else: + logger.error(f"チーム登録API呼び出し失敗: {response.status_code} - {response.text}") + return False, None + + except Exception as e: + logger.error(f"チーム登録エラー: {str(e)}") + return False, None + + def _register_team_members(self, team_data: Dict, team_id: str) -> bool: + """ + チームメンバーを登録(最大7名) + + Args: + team_data: チームデータ + team_id: チームID + + Returns: + 成功フラグ + """ + if self.dry_run: + logger.info(f"[DRY RUN] Would register team members for team: {team_id}") + return True + + try: + success_count = 0 + + # メンバー1-7を順番に処理 + for i in range(1, 8): + name_key = f'氏名{i}' + birth_key = f'誕生日{i}' + + if name_key in team_data and team_data[name_key].strip(): + name = team_data[name_key].strip() + birth_date = team_data.get(birth_key, '1990/01/01') + + # ダミーメールアドレスを生成 + dummy_email = f"{name.replace(' ', '')}_{team_id}_{i}@dummy.local" + + # メンバー追加データ + member_data = { + "email": dummy_email, + "firstname": name.split()[0] if ' ' in name else name, + "lastname": name.split()[-1] if ' ' in name else "", + "date_of_birth": birth_date.replace('/', '-'), + "female": False # デフォルト値 + } + + # メンバー追加API呼び出し + response = self.session.post( + f"{self.base_url}/teams/{team_id}/members/", + json=member_data + ) + + if response.status_code in [200, 201]: + logger.info(f"メンバー追加成功: {name} -> チーム{team_id}") + success_count += 1 + else: + logger.warning(f"メンバー追加失敗: {name} - {response.text}") + + logger.info(f"チーム{team_id}のメンバー登録完了: {success_count}名") + return success_count > 0 + + except Exception as e: + logger.error(f"メンバー登録エラー: {str(e)}") + return False + + def create_event_entry(self, team_id: str, category_id: int = 1) -> Tuple[bool, Optional[str]]: + """ + イベントエントリー登録 + + Args: + team_id: チームID + category_id: カテゴリID + + Returns: + Tuple[success, entry_id] + """ + if self.dry_run: + logger.info(f"[DRY RUN] Would create event entry for team: {team_id}") + return True, "dummy_entry_id" + + try: + # エントリーデータ準備 + entry_data = { + "team_id": team_id, + "event_code": self.event_code, + "category": category_id, + "entry_date": datetime.now().strftime("%Y-%m-%d") + } + + # エントリー登録API呼び出し + response = self.session.post(f"{self.base_url}/entry/", json=entry_data) + + if response.status_code in [200, 201]: + result = response.json() + entry_id = result.get('id') or result.get('entry_id') + logger.info(f"エントリー登録成功: team_id={team_id}, entry_id={entry_id}") + self.stats['entries_created'] += 1 + return True, str(entry_id) + else: + logger.error(f"エントリー登録失敗: {response.status_code} - {response.text}") + return False, None + + except Exception as e: + logger.error(f"エントリー登録エラー: {str(e)}") + return False, None + + def participate_in_event(self, entry_id: str, zekken_number: int) -> bool: + """ + イベント参加処理 + + Args: + entry_id: エントリーID + zekken_number: ゼッケン番号 + + Returns: + 成功フラグ + """ + if self.dry_run: + logger.info(f"[DRY RUN] Would participate in event: entry_id={entry_id}, zekken={zekken_number}") + return True + + try: + # イベント参加データ準備 + participation_data = { + "entry_id": entry_id, + "event_code": self.event_code, + "zekken_number": zekken_number, + "participation_date": datetime.now().strftime("%Y-%m-%d") + } + + # イベント参加API呼び出し(実際のAPIエンドポイントに合わせて調整が必要) + response = self.session.post(f"{self.base_url}/start_from_rogapp", json=participation_data) + + if response.status_code in [200, 201]: + logger.info(f"イベント参加成功: entry_id={entry_id}, zekken={zekken_number}") + self.stats['participations_created'] += 1 + return True + else: + logger.warning(f"イベント参加API呼び出し結果: {response.status_code} - {response.text}") + # 参加処理は必須ではないため、警告のみでTrueを返す + return True + + except Exception as e: + logger.error(f"イベント参加エラー: {str(e)}") + return True # 参加処理は必須ではないため、エラーでもTrueを返す + + def process_csv_file(self, csv_file_path: str) -> bool: + """ + CSVファイルを処理してユーザー登録からイベント参加まで実行 + + Args: + csv_file_path: CSVファイルパス + + Returns: + 成功フラグ + """ + try: + if not os.path.exists(csv_file_path): + logger.error(f"CSVファイルが見つかりません: {csv_file_path}") + return False + + with open(csv_file_path, 'r', encoding='utf-8') as file: + csv_reader = csv.DictReader(file) + + for row_num, row in enumerate(csv_reader, start=1): + try: + self._process_team_row(row, row_num) + + # API呼び出し間隔を空ける + if not self.dry_run: + time.sleep(0.5) + + except Exception as e: + error_msg = f"行{row_num}の処理でエラー: {str(e)}" + logger.error(error_msg) + self.stats['errors'].append(error_msg) + continue + + return True + + except Exception as e: + logger.error(f"CSVファイル処理エラー: {str(e)}") + return False + + def _process_team_row(self, row: Dict, row_num: int): + """ + CSVの1行(1チーム)を処理 + + Args: + row: CSV行データ + row_num: 行番号 + """ + team_name = row.get('チーム名', '').strip() + email = row.get('メール', '').strip() + password = row.get('password', '').strip() + phone = row.get('電話番号', '').strip() + + if not all([team_name, email, password]): + logger.warning(f"行{row_num}: 必須項目が不足 - チーム名={team_name}, メール={email}") + return + + logger.info(f"行{row_num}の処理開始: チーム={team_name}") + + # ゼッケン番号を生成(行番号ベース、実際の運用では別途管理が必要) + zekken_number = row_num + + # 2-1. カスタムユーザー登録 + # 最初のメンバー(氏名1)をメインユーザーとして使用 + firstname = row.get('氏名1', team_name).strip() + lastname = "" + if ' ' in firstname: + parts = firstname.split(' ', 1) + firstname = parts[0] + lastname = parts[1] + + date_of_birth = row.get('誕生日1', '1990/01/01') + + user_success, user_id, token = self.get_or_create_user( + email, password, firstname, lastname, date_of_birth, phone + ) + + if not user_success: + logger.error(f"行{row_num}: ユーザー登録/取得失敗") + return + + # 2-2. チーム登録、メンバー登録 + team_success, team_id = self.register_team_and_members(row, zekken_number) + + if not team_success: + logger.error(f"行{row_num}: チーム登録失敗") + return + + # 2-3. エントリー登録 + entry_success, entry_id = self.create_event_entry(team_id) + + if not entry_success: + logger.error(f"行{row_num}: エントリー登録失敗") + return + + # 2-4. イベント参加 + participation_success = self.participate_in_event(entry_id, zekken_number) + + if participation_success: + logger.info(f"行{row_num}: 全処理完了 - チーム={team_name}, zekken={zekken_number}") + self.stats['processed_teams'] += 1 + else: + logger.warning(f"行{row_num}: イベント参加処理で警告") + + def print_statistics(self): + """ + 処理統計を出力 + """ + logger.info("=== 処理統計 ===") + logger.info(f"処理完了チーム数: {self.stats['processed_teams']}") + logger.info(f"作成ユーザー数: {self.stats['users_created']}") + logger.info(f"更新ユーザー数: {self.stats['users_updated']}") + logger.info(f"登録チーム数: {self.stats['teams_registered']}") + logger.info(f"作成エントリー数: {self.stats['entries_created']}") + logger.info(f"参加登録数: {self.stats['participations_created']}") + logger.info(f"エラー数: {len(self.stats['errors'])}") + + if self.stats['errors']: + logger.error("エラー詳細:") + for error in self.stats['errors']: + logger.error(f" - {error}") + + +def main(): + parser = argparse.ArgumentParser(description='イベントユーザー登録スクリプト') + parser.add_argument('--event_code', required=True, help='イベントコード(例: 大垣2509)') + parser.add_argument('--csv_file', default='CPLIST/input/team2025.csv', help='CSVファイルパス') + parser.add_argument('--base_url', default='http://localhost:8000', help='APIベースURL') + parser.add_argument('--dry_run', action='store_true', help='テスト実行(実際のAPI呼び出しなし)') + + args = parser.parse_args() + + logger.info(f"イベントユーザー登録処理開始: event_code={args.event_code}") + + # 登録処理実行 + registration = EventUserRegistration( + event_code=args.event_code, + base_url=args.base_url, + dry_run=args.dry_run + ) + + success = registration.process_csv_file(args.csv_file) + + # 統計出力 + registration.print_statistics() + + if success: + logger.info("処理が正常に完了しました") + return 0 + else: + logger.error("処理中にエラーが発生しました") + return 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rog/management/commands/register_teams_from_csv.py b/rog/management/commands/register_teams_from_csv.py index 5254ae4..435019d 100644 --- a/rog/management/commands/register_teams_from_csv.py +++ b/rog/management/commands/register_teams_from_csv.py @@ -125,19 +125,38 @@ class TeamRegistrationProcessor: self.log(f"DRY RUN: Event with code '{self.event_code}' would be searched") # ダミーイベントオブジェクトを作成 class DummyEvent: - def __init__(self): - self.event_name = f"Dummy Event for {self.event_code}" - self.event_code = self.event_code - self.event = DummyEvent() + def __init__(self, event_code): + self.event_name = f"Dummy Event for {event_code}" + self.event_code = event_code + self.event = DummyEvent(self.event_code) return else: raise ValueError(f"Event with code '{self.event_code}' not found") # カテゴリ情報をプリロード - for category in NewCategory.objects.all(): - hours = int(category.duration.total_seconds() // 3600) - key = (category.category_name, hours) - self.categories[key] = category + if not self.dry_run: + for category in NewCategory.objects.all(): + hours = int(category.duration.total_seconds() // 3600) + key = (category.category_name, hours) + self.categories[key] = category + else: + # DRY RUNの場合はダミーカテゴリを作成 + dummy_categories = [ + ('一般', 3), ('一般', 5), ('ファミリー', 3), ('ファミリー', 5), + ('男性ソロ', 3), ('男性ソロ', 5), ('女性ソロ', 3), ('女性ソロ', 5) + ] + for cat_name, hours in dummy_categories: + class DummyCategory: + def __init__(self, name, hours): + self.category_name = name + self.category_number = len(self.categories) + 1 + self.duration = timedelta(hours=hours) + self.num_of_member = 7 + self.family = (name == 'ファミリー') + self.female = (name == '女性ソロ') + self.trial = False + + self.categories[(cat_name, hours)] = DummyCategory(cat_name, hours) self.log(f"利用可能なカテゴリ: {list(self.categories.keys())}") @@ -226,16 +245,16 @@ class TeamRegistrationProcessor: self.log(f"DRY RUN: カテゴリ作成 - {department} ({hours_int}時間)") # ダミーカテゴリオブジェクトを作成 class DummyCategory: - def __init__(self): + def __init__(self, processor): self.category_name = department - self.category_number = len(self.categories) + 1 + self.category_number = len(processor.categories) + 1 self.duration = timedelta(hours=hours_int) self.num_of_member = 7 self.family = (department == 'ファミリー') self.female = (department == '女性ソロ') self.trial = False - category = DummyCategory() + category = DummyCategory(self) else: category = NewCategory.objects.create( category_name=department, @@ -446,7 +465,7 @@ class TeamRegistrationProcessor: lastname=user.lastname, date_of_birth=user.date_of_birth, female=user.female, - is_temporary=True if user.email.startswith('dummy_') else False + is_temporary=True if hasattr(user, 'email') and user.email.startswith('dummy_') else False ) self.log(f"メンバー追加: {user.firstname} to {team.team_name}") self.stats['members_created'] += 1 @@ -510,7 +529,7 @@ class TeamRegistrationProcessor: entry_member = EntryMember.objects.create( entry=entry, member=member, - is_temporary=member.is_temporary + is_temporary=getattr(member, 'is_temporary', False) ) self.log(f"参加登録: {member.user.firstname}") self.stats['participations_created'] += 1 diff --git a/run_event_registration.sh b/run_event_registration.sh new file mode 100755 index 0000000..b55553d --- /dev/null +++ b/run_event_registration.sh @@ -0,0 +1,95 @@ +#!/bin/bash + +# イベントユーザー登録実行スクリプト +# +# 使用方法: +# ./run_event_registration.sh [EVENT_CODE] [OPTIONS] +# +# 例: +# ./run_event_registration.sh 大垣2509 +# ./run_event_registration.sh 大垣2509 --dry-run +# ./run_event_registration.sh 大垣2509 --csv-file CPLIST/input/custom_teams.csv + +set -e + +# デフォルト値 +EVENT_CODE=${1:-"大垣2509"} +CSV_FILE="CPLIST/input/team2025.csv" +BASE_URL="http://localhost:8000" +DRY_RUN="" + +# コマンドライン引数を解析 +shift +while [[ $# -gt 0 ]]; do + case $1 in + --dry-run) + DRY_RUN="true" + shift + ;; + --csv-file) + CSV_FILE="$2" + shift 2 + ;; + --base-url) + BASE_URL="$2" + shift 2 + ;; + --help) + echo "使用方法: $0 [EVENT_CODE] [OPTIONS]" + echo "" + echo "オプション:" + echo " --dry-run テスト実行(実際のAPI呼び出しなし)" + echo " --csv-file FILE CSVファイルパス(デフォルト: CPLIST/input/team2025.csv)" + echo " --base-url URL APIベースURL(デフォルト: http://localhost:8000)" + echo " --help このヘルプを表示" + echo "" + echo "例:" + echo " $0 大垣2509" + echo " $0 大垣2509 --dry-run" + echo " $0 大垣2509 --csv-file CPLIST/input/custom_teams.csv" + exit 0 + ;; + *) + echo "不明なオプション: $1" + echo "ヘルプを表示するには --help を使用してください" + exit 1 + ;; + esac +done + +echo "=== イベントユーザー登録処理 ===" +echo "イベントコード: $EVENT_CODE" +echo "CSVファイル: $CSV_FILE" +echo "APIベースURL: $BASE_URL" +echo "テスト実行: ${DRY_RUN:-false}" +echo "================================" + +# CSVファイルの存在確認 +if [ ! -f "$CSV_FILE" ]; then + echo "エラー: CSVファイルが見つかりません: $CSV_FILE" + exit 1 +fi + +# Docker Composeファイルの存在確認 +if [ ! -f "docker-compose.event-registration.yml" ]; then + echo "エラー: docker-compose.event-registration.yml が見つかりません" + exit 1 +fi + +# ログディレクトリを作成 +mkdir -p logs + +# 環境変数を設定してDocker Composeを実行 +export EVENT_CODE="$EVENT_CODE" +export CSV_FILE="$CSV_FILE" +export BASE_URL="$BASE_URL" +export DRY_RUN="$DRY_RUN" + +echo "Docker Composeでイベントユーザー登録処理を開始します..." + +# Docker Composeを実行 +docker-compose -f docker-compose.event-registration.yml up --build --remove-orphans + +echo "" +echo "=== 処理完了 ===" +echo "ログファイルを確認してください: logs/register_event_users.log" diff --git a/イベントユーザー登録 b/イベントユーザー登録 new file mode 100644 index 0000000..4dea23f --- /dev/null +++ b/イベントユーザー登録 @@ -0,0 +1,42 @@ + +外部システムAPI仕様書.md を前提に、ユーザーデータcsvから、 +各ユーザーごとにユーザー登録、チーム登録、エントリー登録、イベント参加を行う +docker compose で実施するPythonスクリプトを作成しなさい。 + + +ユーザーデータのCSVは以下の項目を持つ。 + +部門別数,時間,部門,チーム名,メール,パスワード,電話番号,氏名1,誕生日1,氏名2,誕生日2,氏名3,誕生日3,氏名4,誕生日4,氏名5,誕生日5,氏名6,誕生日6,氏名7,誕生日7,, + + +1. 起動パラメータで、event_code=大垣2509 を指定する. + +2. CSV(CPLIST/input/team2025.csv)を読みこみ、各行ごとに下記の処理を行う。 + +2-1. カスタムユーザー登録 API + +# メールアドレスをキーに既存ユーザーを取得 + 検索がヒットしなければ、ユーザー登録する。 + 検索がヒットすれば、パスワードを更新する。 + + + + event_codeに指定event_codeを設定 + zekken_number に zekken を入力 + team_name に team名を入れる + +2-2. チーム登録、メンバー登録 + +# 部門・時間・チーム名でチーム登録 +# メンバーを1名ずつ7名まで登録 +## それぞれダミーメアドと名前と生年月日でメンバー登録 + +2-3. エントリー登録 + +# 指定されたイベントにチームを9/6で登録する。 + +2-4. イベント参加 + +# 登録したエントリーでイベント参加する。 + +