diff --git a/.github/workflows/deploy-docker-gce b/.github/workflows/deploy-docker-gce new file mode 100644 index 0000000..2d2d98e --- /dev/null +++ b/.github/workflows/deploy-docker-gce @@ -0,0 +1,42 @@ +name: Deploy to Google Compute Engine + +on: + push: + branches: + - dev # Replace with your branch + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - name: Build and push Docker image + uses: actions/checkout@v3 + with: + context: . + file: ./Dockerfile + push: true + tags: ${{ secrets.DOCKER_HUB_USERNAME }}/snap_up_thsr:latest + + - name: Setup Google Cloud SDK + uses: google-github-actions/setup-gcloud@master + with: + project_id: ${{ secrets.GCP_PROJECT_ID }} + service_account_key: ${{ secrets.GCP_SA_KEY }} + export_default_credentials: true + + - name: Deploy to GCE + run: | + gcloud compute ssh user@instance -- "cd snap_up_thsr && \ + git pull && \ + docker run --network=${{ secrets.LIVE_NETWORK }} \ + -p 8080:8000 \ + -e REDIS_HOST=${{ secrets.REDIS_HOST }} \ + -e DB_HOST=${{ secrets.DB_HOST }} \ + -e DB_USER=${{ secrets.DB_USER }} \ + -e DB_PASSWORD=${{ secrets.DB_PASSWORD }} \ + -e DB_NAME=${{ secrets.DB_NAME }} \ + -d \ + --restart=always \ + --name snap_up_thsr \ + ${{ secrets.DOCKER_HUB_USERNAME }}/snap_up_thsr:latest diff --git a/.gitignore b/.gitignore index 5eae5fd..f2e887c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,4 @@ __pycache__/ # projects requirements/dev.txt *.log -recognize_img.py - -.github/ +/src/static diff --git a/Dockerfile b/Dockerfile index aeee53a..0cd4edf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,4 +10,4 @@ RUN apt update && \ apt install -y libpq5 procps && \ pip install -r /requirements/live.txt -CMD ["gunicorn", "--timeout=300", "--workers=2", "--threads=8", "--keep-alive=60", "src.wsgi:application"] \ No newline at end of file +CMD ["gunicorn", "--timeout=300", "--workers=2", "--threads=8", "--keep-alive=60", "src.wsgi:application"] diff --git a/docker-compose.yml b/docker-compose.yml index 3ff438b..5dfccee 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,6 +3,7 @@ services: image: redis:alpine ports: - "8684:6379" + db: image: postgres:latest restart: always @@ -26,6 +27,6 @@ services: - ./requirements:/requirements ports: - "8686:8000" - command: bash -c "pip freeze > /requirements/live.txt && gunicorn --timeout=300 --workers=2 --threads=8 --keep-alive=60 src.wsgi:application" + command: bash -c "pip freeze > /requirements/live.txt && tail -f /dev/null" environment: DEPLOY: dev diff --git a/requirements/live.txt b/requirements/live.txt index a6a7114..84605fc 100644 --- a/requirements/live.txt +++ b/requirements/live.txt @@ -8,6 +8,7 @@ coloredlogs==15.0.1 ddddocr==1.4.11 Django==4.2 flatbuffers==23.5.26 +gunicorn==21.2.0 humanfriendly==10.0 idna==3.6 mpmath==1.3.0 diff --git a/requirements/local.txt b/requirements/local.txt index 898943c..e987e44 100644 --- a/requirements/local.txt +++ b/requirements/local.txt @@ -7,4 +7,7 @@ redis phonenumbers requests beautifulsoup4 -ddddocr \ No newline at end of file +ddddocr + +# live +gunicorn \ No newline at end of file diff --git a/src/booking/migrations/0001_initial.py b/src/booking/migrations/0001_initial.py index 388213f..56b3b7c 100644 --- a/src/booking/migrations/0001_initial.py +++ b/src/booking/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2 on 2023-10-07 10:49 +# Generated by Django 4.2 on 2024-02-10 17:32 from django.db import migrations, models @@ -11,67 +11,30 @@ class Migration(migrations.Migration): ] operations = [ - migrations.CreateModel( - name='BookingLog', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('updated_at', models.DateTimeField(auto_now=True)), - ('booking_request_id', models.PositiveBigIntegerField()), - ('status', models.SmallIntegerField()), - ('err_msg', models.TextField()), - ('ticket_id', models.CharField(max_length=10)), - ], - ), - migrations.CreateModel( - name='BookingQueue', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('updated_at', models.DateTimeField(auto_now=True)), - ('booking_request_id', models.PositiveBigIntegerField()), - ('booking_date', models.DateField()), - ('retry_times', models.PositiveSmallIntegerField()), - ('max_retry_times', models.PositiveSmallIntegerField()), - ], - options={ - 'abstract': False, - }, - ), migrations.CreateModel( name='BookingRequest', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('created_at', models.DateTimeField(auto_now_add=True)), ('updated_at', models.DateTimeField(auto_now=True)), - ('user_email', models.EmailField(max_length=254)), + ('status', models.PositiveSmallIntegerField(choices=[(0, 'Not Yet'), (1, 'Pending'), (2, 'Processing'), (3, 'Completed'), (-1, 'Expired'), (-2, 'Deleted')], default=1)), + ('train_id', models.CharField(blank=True, max_length=10)), ('depart_station', models.PositiveSmallIntegerField(choices=[(1, '南港'), (2, '台北'), (3, '板橋'), (4, '桃園'), (5, '新竹'), (6, '苗栗'), (7, '台中'), (8, '彰化'), (9, '雲林'), (10, '嘉義'), (11, '台南'), (12, '左營')], default=1)), ('dest_station', models.PositiveSmallIntegerField(choices=[(1, '南港'), (2, '台北'), (3, '板橋'), (4, '桃園'), (5, '新竹'), (6, '苗栗'), (7, '台中'), (8, '彰化'), (9, '雲林'), (10, '嘉義'), (11, '台南'), (12, '左營')], default=12)), ('type_of_trip', models.PositiveSmallIntegerField(choices=[(0, 'One Way'), (1, 'Round Trip')], default=0)), - ('booking_method', models.PositiveSmallIntegerField(choices=[(0, 'radio31'), (1, 'radio33')], default=0)), + ('booking_method', models.PositiveSmallIntegerField(choices=[(0, 'Time'), (1, 'Train No')], default=0)), ('seat_prefer', models.PositiveSmallIntegerField(choices=[(0, 'No Prefer'), (1, 'Prefer Window'), (2, 'Prefer Aisle')], default=0)), - ('adult_num', models.PositiveSmallIntegerField(choices=[(0, 'Zero'), (1, 'One'), (2, 'Two'), (3, 'Three'), (4, 'Four'), (5, 'Five'), (6, 'Six'), (7, 'Seven'), (8, 'Eight'), (9, 'Nine'), (10, 'Ten')], default=1)), - ('child_num', models.PositiveSmallIntegerField(choices=[(0, 'Zero'), (1, 'One'), (2, 'Two'), (3, 'Three'), (4, 'Four'), (5, 'Five'), (6, 'Six'), (7, 'Seven'), (8, 'Eight'), (9, 'Nine'), (10, 'Ten')], default=0)), - ('disabled_num', models.PositiveSmallIntegerField(choices=[(0, 'Zero'), (1, 'One'), (2, 'Two'), (3, 'Three'), (4, 'Four'), (5, 'Five'), (6, 'Six'), (7, 'Seven'), (8, 'Eight'), (9, 'Nine'), (10, 'Ten')], default=0)), - ('elder_num', models.PositiveSmallIntegerField(choices=[(0, 'Zero'), (1, 'One'), (2, 'Two'), (3, 'Three'), (4, 'Four'), (5, 'Five'), (6, 'Six'), (7, 'Seven'), (8, 'Eight'), (9, 'Nine'), (10, 'Ten')], default=0)), - ('college_num', models.PositiveSmallIntegerField(choices=[(0, 'Zero'), (1, 'One'), (2, 'Two'), (3, 'Three'), (4, 'Four'), (5, 'Five'), (6, 'Six'), (7, 'Seven'), (8, 'Eight'), (9, 'Nine'), (10, 'Ten')], default=0)), - ('depart_date', models.DateField(blank=True)), + ('adult_num', models.PositiveSmallIntegerField(choices=[(0, '0'), (1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5'), (6, '6'), (7, '7'), (8, '8'), (9, '9'), (10, '10')], default=1)), + ('child_num', models.PositiveSmallIntegerField(choices=[(0, '0'), (1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5'), (6, '6'), (7, '7'), (8, '8'), (9, '9'), (10, '10')], default=0)), + ('disabled_num', models.PositiveSmallIntegerField(choices=[(0, '0'), (1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5'), (6, '6'), (7, '7'), (8, '8'), (9, '9'), (10, '10')], default=0)), + ('elder_num', models.PositiveSmallIntegerField(choices=[(0, '0'), (1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5'), (6, '6'), (7, '7'), (8, '8'), (9, '9'), (10, '10')], default=0)), + ('college_num', models.PositiveSmallIntegerField(choices=[(0, '0'), (1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5'), (6, '6'), (7, '7'), (8, '8'), (9, '9'), (10, '10')], default=0)), + ('depart_date', models.DateField()), ('earliest_depart_time', models.CharField(blank=True, choices=[('', ''), ('500A', '05:00'), ('530A', '05:30'), ('600A', '06:00'), ('630A', '06:30'), ('700A', '07:00'), ('730A', '07:30'), ('800A', '08:00'), ('830A', '08:30'), ('900A', '09:00'), ('930A', '09:30'), ('1000A', '10:00'), ('1030A', '10:30'), ('1100A', '11:00'), ('1130A', '11:30'), ('1200N', '12:00'), ('1230P', '12:30'), ('100P', '13:00'), ('130P', '13:30'), ('200P', '14:00'), ('230P', '14:30'), ('300P', '15:00'), ('330P', '15:30'), ('400P', '16:00'), ('430P', '16:30'), ('500P', '17:00'), ('530P', '17:30'), ('600P', '18:00'), ('630P', '18:30'), ('700P', '19:00'), ('730P', '19:30'), ('800P', '20:00'), ('830P', '20:30'), ('900P', '21:00'), ('930P', '21:30'), ('1000P', '22:00'), ('1030P', '22:30'), ('1100P', '23:00'), ('1130P', '23:30'), ('1201A', '23:59')], default='', max_length=10)), ('latest_arrival_time', models.CharField(blank=True, choices=[('', ''), ('500A', '05:00'), ('530A', '05:30'), ('600A', '06:00'), ('630A', '06:30'), ('700A', '07:00'), ('730A', '07:30'), ('800A', '08:00'), ('830A', '08:30'), ('900A', '09:00'), ('930A', '09:30'), ('1000A', '10:00'), ('1030A', '10:30'), ('1100A', '11:00'), ('1130A', '11:30'), ('1200N', '12:00'), ('1230P', '12:30'), ('100P', '13:00'), ('130P', '13:30'), ('200P', '14:00'), ('230P', '14:30'), ('300P', '15:00'), ('330P', '15:30'), ('400P', '16:00'), ('430P', '16:30'), ('500P', '17:00'), ('530P', '17:30'), ('600P', '18:00'), ('630P', '18:30'), ('700P', '19:00'), ('730P', '19:30'), ('800P', '20:00'), ('830P', '20:30'), ('900P', '21:00'), ('930P', '21:30'), ('1000P', '22:00'), ('1030P', '22:30'), ('1100P', '23:00'), ('1130P', '23:30'), ('1201A', '23:59')], default='1201A', max_length=10)), - ('train_id', models.CharField(blank=True, max_length=10)), - ('deleted_at', models.DateTimeField(blank=True)), - ], - ), - migrations.CreateModel( - name='BookingResult', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('updated_at', models.DateTimeField(auto_now=True)), - ('user_email', models.EmailField(max_length=254)), - ('booking_request_id', models.PositiveBigIntegerField()), - ('status', models.PositiveSmallIntegerField(choices=[(1, 'Success'), (-1, 'Fail')])), - ('thsr_ticket_id', models.PositiveBigIntegerField()), + ('passenger_ids', models.JSONField(blank=True, default=list, null=True)), + ('deleted_at', models.DateTimeField(blank=True, null=True)), + ('error_msg', models.CharField(blank=True, max_length=255)), ], ), migrations.CreateModel( @@ -81,34 +44,18 @@ class Migration(migrations.Migration): ('created_at', models.DateTimeField(auto_now_add=True)), ('updated_at', models.DateTimeField(auto_now=True)), ('ticket_id', models.CharField(blank=True, max_length=10)), + ('total_price', models.CharField(blank=True, max_length=10)), ('payment_deadline', models.CharField(blank=True, max_length=10)), - ('depart_time', models.DateTimeField(blank=True)), - ('arrival_time', models.DateTimeField(blank=True)), - ('depart_station', models.CharField(blank=True, max_length=10)), - ('arrival_station', models.CharField(blank=True, max_length=10)), + ('train_id', models.CharField(blank=True, max_length=10)), + ('seat_num', models.CharField(blank=True, max_length=50)), + ('date', models.CharField(blank=True, max_length=10)), + ('depart_time', models.CharField(blank=True, max_length=255)), + ('arrival_time', models.CharField(blank=True, max_length=255)), + ('depart_station', models.PositiveSmallIntegerField(choices=[(1, '南港'), (2, '台北'), (3, '板橋'), (4, '桃園'), (5, '新竹'), (6, '苗栗'), (7, '台中'), (8, '彰化'), (9, '雲林'), (10, '嘉義'), (11, '台南'), (12, '左營')])), + ('arrival_station', models.PositiveSmallIntegerField(choices=[(1, '南港'), (2, '台北'), (3, '板橋'), (4, '桃園'), (5, '新竹'), (6, '苗栗'), (7, '台中'), (8, '彰化'), (9, '雲林'), (10, '嘉義'), (11, '台南'), (12, '左營')])), ], options={ 'abstract': False, }, ), - migrations.AddIndex( - model_name='bookingresult', - index=models.Index(fields=['user_email'], name='booking_boo_user_em_08d164_idx'), - ), - migrations.AddIndex( - model_name='bookingresult', - index=models.Index(fields=['booking_request_id'], name='booking_boo_booking_03208c_idx'), - ), - migrations.AddIndex( - model_name='bookingresult', - index=models.Index(fields=['thsr_ticket_id'], name='booking_boo_thsr_ti_915693_idx'), - ), - migrations.AddIndex( - model_name='bookingrequest', - index=models.Index(fields=['user_email'], name='booking_boo_user_em_d76ad1_idx'), - ), - migrations.AddIndex( - model_name='bookinglog', - index=models.Index(fields=['booking_request_id'], name='booking_boo_booking_3e6357_idx'), - ), ] diff --git a/src/booking/migrations/0002_bookingrequest_thsr_ticket_id_thsrticket_date_and_more.py b/src/booking/migrations/0002_bookingrequest_thsr_ticket_id_thsrticket_date_and_more.py deleted file mode 100644 index 387e85a..0000000 --- a/src/booking/migrations/0002_bookingrequest_thsr_ticket_id_thsrticket_date_and_more.py +++ /dev/null @@ -1,73 +0,0 @@ -# Generated by Django 4.2 on 2023-11-07 16:38 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('booking', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='bookingrequest', - name='thsr_ticket_id', - field=models.PositiveBigIntegerField(null=True), - ), - migrations.AddField( - model_name='thsrticket', - name='date', - field=models.CharField(blank=True, max_length=10), - ), - migrations.AddField( - model_name='thsrticket', - name='seat_num', - field=models.CharField(blank=True, max_length=50), - ), - migrations.AddField( - model_name='thsrticket', - name='total_price', - field=models.CharField(blank=True, max_length=10), - ), - migrations.AddField( - model_name='thsrticket', - name='train_id', - field=models.CharField(blank=True, max_length=10), - ), - migrations.AlterField( - model_name='bookingrequest', - name='adult_num', - field=models.PositiveSmallIntegerField(choices=[(0, '0'), (1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5'), (6, '6'), (7, '7'), (8, '8'), (9, '9'), (10, '10')], default=1), - ), - migrations.AlterField( - model_name='bookingrequest', - name='child_num', - field=models.PositiveSmallIntegerField(choices=[(0, '0'), (1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5'), (6, '6'), (7, '7'), (8, '8'), (9, '9'), (10, '10')], default=0), - ), - migrations.AlterField( - model_name='bookingrequest', - name='college_num', - field=models.PositiveSmallIntegerField(choices=[(0, '0'), (1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5'), (6, '6'), (7, '7'), (8, '8'), (9, '9'), (10, '10')], default=0), - ), - migrations.AlterField( - model_name='bookingrequest', - name='disabled_num', - field=models.PositiveSmallIntegerField(choices=[(0, '0'), (1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5'), (6, '6'), (7, '7'), (8, '8'), (9, '9'), (10, '10')], default=0), - ), - migrations.AlterField( - model_name='bookingrequest', - name='elder_num', - field=models.PositiveSmallIntegerField(choices=[(0, '0'), (1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5'), (6, '6'), (7, '7'), (8, '8'), (9, '9'), (10, '10')], default=0), - ), - migrations.AlterField( - model_name='thsrticket', - name='arrival_station', - field=models.PositiveSmallIntegerField(choices=[(1, '南港'), (2, '台北'), (3, '板橋'), (4, '桃園'), (5, '新竹'), (6, '苗栗'), (7, '台中'), (8, '彰化'), (9, '雲林'), (10, '嘉義'), (11, '台南'), (12, '左營')]), - ), - migrations.AlterField( - model_name='thsrticket', - name='depart_station', - field=models.PositiveSmallIntegerField(choices=[(1, '南港'), (2, '台北'), (3, '板橋'), (4, '桃園'), (5, '新竹'), (6, '苗栗'), (7, '台中'), (8, '彰化'), (9, '雲林'), (10, '嘉義'), (11, '台南'), (12, '左營')]), - ), - ] diff --git a/src/booking/migrations/0002_initial.py b/src/booking/migrations/0002_initial.py new file mode 100644 index 0000000..2b767e9 --- /dev/null +++ b/src/booking/migrations/0002_initial.py @@ -0,0 +1,37 @@ +# Generated by Django 4.2 on 2024-02-10 17:32 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('booking', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='thsrticket', + name='user', + field=models.ForeignKey(db_constraint=False, on_delete=django.db.models.deletion.DO_NOTHING, to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='bookingrequest', + name='thsr_ticket', + field=models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='booking.thsrticket', verbose_name='THSR Ticket ID'), + ), + migrations.AddField( + model_name='bookingrequest', + name='user', + field=models.ForeignKey(db_constraint=False, on_delete=django.db.models.deletion.DO_NOTHING, to=settings.AUTH_USER_MODEL), + ), + migrations.AddIndex( + model_name='bookingrequest', + index=models.Index(fields=['status', '-depart_date'], name='booking_boo_status_9e3d6f_idx'), + ), + ] diff --git a/src/booking/migrations/0003_bookingrequest_passenger_ids_bookingrequest_status_and_more.py b/src/booking/migrations/0003_bookingrequest_passenger_ids_bookingrequest_status_and_more.py deleted file mode 100644 index 22bd40d..0000000 --- a/src/booking/migrations/0003_bookingrequest_passenger_ids_bookingrequest_status_and_more.py +++ /dev/null @@ -1,27 +0,0 @@ -# Generated by Django 4.2 on 2024-01-06 15:41 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('booking', '0002_bookingrequest_thsr_ticket_id_thsrticket_date_and_more'), - ] - - operations = [ - migrations.AddField( - model_name='bookingrequest', - name='passenger_ids', - field=models.JSONField(default=list), - ), - migrations.AddField( - model_name='bookingrequest', - name='status', - field=models.PositiveSmallIntegerField(choices=[(0, 'Not Yet'), (1, 'Pending'), (2, 'Processing'), (3, 'Completed'), (-1, 'Expired'), (-2, 'Deleted')], default=0), - ), - migrations.AddIndex( - model_name='bookingrequest', - index=models.Index(fields=['status'], name='booking_boo_status_c40eaf_idx'), - ), - ] diff --git a/src/booking/migrations/0004_alter_bookingrequest_deleted_at_and_more.py b/src/booking/migrations/0004_alter_bookingrequest_deleted_at_and_more.py deleted file mode 100644 index fcac589..0000000 --- a/src/booking/migrations/0004_alter_bookingrequest_deleted_at_and_more.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 4.2 on 2024-01-06 15:56 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('booking', '0003_bookingrequest_passenger_ids_bookingrequest_status_and_more'), - ] - - operations = [ - migrations.AlterField( - model_name='bookingrequest', - name='deleted_at', - field=models.DateTimeField(blank=True, null=True), - ), - migrations.AlterField( - model_name='bookingrequest', - name='thsr_ticket_id', - field=models.PositiveBigIntegerField(blank=True, null=True), - ), - ] diff --git a/src/booking/migrations/0005_alter_bookingrequest_booking_method.py b/src/booking/migrations/0005_alter_bookingrequest_booking_method.py deleted file mode 100644 index ed7a5e6..0000000 --- a/src/booking/migrations/0005_alter_bookingrequest_booking_method.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.2 on 2024-01-06 16:04 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('booking', '0004_alter_bookingrequest_deleted_at_and_more'), - ] - - operations = [ - migrations.AlterField( - model_name='bookingrequest', - name='booking_method', - field=models.CharField(choices=[('radio31', 'Time'), ('radio33', 'Train No')], default='radio31', max_length=255), - ), - ] diff --git a/src/booking/migrations/0006_alter_thsrticket_arrival_time_and_more.py b/src/booking/migrations/0006_alter_thsrticket_arrival_time_and_more.py deleted file mode 100644 index 40d4c66..0000000 --- a/src/booking/migrations/0006_alter_thsrticket_arrival_time_and_more.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 4.2 on 2024-01-06 17:45 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('booking', '0005_alter_bookingrequest_booking_method'), - ] - - operations = [ - migrations.AlterField( - model_name='thsrticket', - name='arrival_time', - field=models.CharField(blank=True, max_length=255), - ), - migrations.AlterField( - model_name='thsrticket', - name='depart_time', - field=models.CharField(blank=True, max_length=255), - ), - ] diff --git a/src/booking/migrations/0007_delete_bookinglog_delete_bookingqueue_and_more.py b/src/booking/migrations/0007_delete_bookinglog_delete_bookingqueue_and_more.py deleted file mode 100644 index 54299a3..0000000 --- a/src/booking/migrations/0007_delete_bookinglog_delete_bookingqueue_and_more.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 4.2 on 2024-01-07 13:06 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('booking', '0006_alter_thsrticket_arrival_time_and_more'), - ] - - operations = [ - migrations.DeleteModel( - name='BookingLog', - ), - migrations.DeleteModel( - name='BookingQueue', - ), - migrations.DeleteModel( - name='BookingResult', - ), - ] diff --git a/src/booking/migrations/0008_remove_bookingrequest_booking_boo_status_c40eaf_idx_and_more.py b/src/booking/migrations/0008_remove_bookingrequest_booking_boo_status_c40eaf_idx_and_more.py deleted file mode 100644 index 555e051..0000000 --- a/src/booking/migrations/0008_remove_bookingrequest_booking_boo_status_c40eaf_idx_and_more.py +++ /dev/null @@ -1,21 +0,0 @@ -# Generated by Django 4.2 on 2024-01-07 13:06 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('booking', '0007_delete_bookinglog_delete_bookingqueue_and_more'), - ] - - operations = [ - migrations.RemoveIndex( - model_name='bookingrequest', - name='booking_boo_status_c40eaf_idx', - ), - migrations.AddIndex( - model_name='bookingrequest', - index=models.Index(fields=['status', '-depart_date'], name='booking_boo_status_9e3d6f_idx'), - ), - ] diff --git a/src/booking/migrations/0009_remove_bookingrequest_thsr_ticket_id_and_more.py b/src/booking/migrations/0009_remove_bookingrequest_thsr_ticket_id_and_more.py deleted file mode 100644 index a824eb2..0000000 --- a/src/booking/migrations/0009_remove_bookingrequest_thsr_ticket_id_and_more.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 4.2 on 2024-01-07 14:06 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('booking', '0008_remove_bookingrequest_booking_boo_status_c40eaf_idx_and_more'), - ] - - operations = [ - migrations.RemoveField( - model_name='bookingrequest', - name='thsr_ticket_id', - ), - migrations.AddField( - model_name='bookingrequest', - name='thsr_ticket', - field=models.OneToOneField(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='booking.thsrticket', verbose_name='THSR Ticket ID'), - ), - ] diff --git a/src/booking/migrations/0010_alter_bookingrequest_thsr_ticket.py b/src/booking/migrations/0010_alter_bookingrequest_thsr_ticket.py deleted file mode 100644 index 451e97e..0000000 --- a/src/booking/migrations/0010_alter_bookingrequest_thsr_ticket.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 4.2 on 2024-01-07 14:08 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('booking', '0009_remove_bookingrequest_thsr_ticket_id_and_more'), - ] - - operations = [ - migrations.AlterField( - model_name='bookingrequest', - name='thsr_ticket', - field=models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='booking.thsrticket', verbose_name='THSR Ticket ID'), - ), - ] diff --git a/src/booking/migrations/0011_alter_bookingrequest_booking_method.py b/src/booking/migrations/0011_alter_bookingrequest_booking_method.py deleted file mode 100644 index 88f1bb1..0000000 --- a/src/booking/migrations/0011_alter_bookingrequest_booking_method.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.2 on 2024-01-08 16:49 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('booking', '0010_alter_bookingrequest_thsr_ticket'), - ] - - operations = [ - migrations.AlterField( - model_name='bookingrequest', - name='booking_method', - field=models.CharField(choices=[(0, 'Time'), (1, 'Train No')], default=0, max_length=255), - ), - ] diff --git a/src/booking/migrations/0012_alter_bookingrequest_booking_method.py b/src/booking/migrations/0012_alter_bookingrequest_booking_method.py deleted file mode 100644 index 3ff8a47..0000000 --- a/src/booking/migrations/0012_alter_bookingrequest_booking_method.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.2 on 2024-01-08 16:50 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('booking', '0011_alter_bookingrequest_booking_method'), - ] - - operations = [ - migrations.AlterField( - model_name='bookingrequest', - name='booking_method', - field=models.PositiveSmallIntegerField(choices=[(0, 'Time'), (1, 'Train No')], default=0), - ), - ] diff --git a/src/booking/migrations/0013_bookingrequest_error_msg.py b/src/booking/migrations/0013_bookingrequest_error_msg.py deleted file mode 100644 index 8ba045a..0000000 --- a/src/booking/migrations/0013_bookingrequest_error_msg.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.2 on 2024-02-03 10:38 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('booking', '0012_alter_bookingrequest_booking_method'), - ] - - operations = [ - migrations.AddField( - model_name='bookingrequest', - name='error_msg', - field=models.CharField(blank=True, max_length=255), - ), - ] diff --git a/src/booking/migrations/0014_alter_bookingrequest_depart_date_and_more.py b/src/booking/migrations/0014_alter_bookingrequest_depart_date_and_more.py deleted file mode 100644 index dc24bfb..0000000 --- a/src/booking/migrations/0014_alter_bookingrequest_depart_date_and_more.py +++ /dev/null @@ -1,28 +0,0 @@ -# Generated by Django 4.2 on 2024-02-03 16:56 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('booking', '0013_bookingrequest_error_msg'), - ] - - operations = [ - migrations.AlterField( - model_name='bookingrequest', - name='depart_date', - field=models.DateField(), - ), - migrations.AlterField( - model_name='bookingrequest', - name='passenger_ids', - field=models.JSONField(blank=True, default=list, null=True), - ), - migrations.AlterField( - model_name='bookingrequest', - name='status', - field=models.PositiveSmallIntegerField(choices=[(0, 'Not Yet'), (1, 'Pending'), (2, 'Processing'), (3, 'Completed'), (-1, 'Expired'), (-2, 'Deleted')], default=1), - ), - ] diff --git a/src/booking/migrations/0015_remove_bookingrequest_booking_boo_user_em_d76ad1_idx_and_more.py b/src/booking/migrations/0015_remove_bookingrequest_booking_boo_user_em_d76ad1_idx_and_more.py deleted file mode 100644 index ad4754d..0000000 --- a/src/booking/migrations/0015_remove_bookingrequest_booking_boo_user_em_d76ad1_idx_and_more.py +++ /dev/null @@ -1,30 +0,0 @@ -# Generated by Django 4.2 on 2024-02-09 12:19 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('booking', '0014_alter_bookingrequest_depart_date_and_more'), - ] - - operations = [ - migrations.RemoveIndex( - model_name='bookingrequest', - name='booking_boo_user_em_d76ad1_idx', - ), - migrations.RemoveField( - model_name='bookingrequest', - name='user_email', - ), - migrations.AddField( - model_name='bookingrequest', - name='user', - field=models.ForeignKey(db_constraint=False, default=1, on_delete=django.db.models.deletion.DO_NOTHING, to=settings.AUTH_USER_MODEL), - preserve_default=False, - ), - ] diff --git a/src/booking/models.py b/src/booking/models.py index 11155e7..b3a574b 100644 --- a/src/booking/models.py +++ b/src/booking/models.py @@ -19,6 +19,11 @@ class THSRTicket(BasisModel): + user = models.ForeignKey( + User, + on_delete=models.DO_NOTHING, + db_constraint=False, + ) ticket_id = models.CharField(max_length=10, blank=True) total_price = models.CharField(max_length=10, blank=True) payment_deadline = models.CharField(max_length=10, blank=True) @@ -30,6 +35,9 @@ class THSRTicket(BasisModel): depart_station = models.PositiveSmallIntegerField(choices=Station.choices) arrival_station = models.PositiveSmallIntegerField(choices=Station.choices) + def __str__(self) -> str: + return self.ticket_id + class BookingRequest(BasisModel): class Status(models.IntegerChoices): diff --git a/src/booking/tasks.py b/src/booking/tasks.py index 22d028a..e89e5bf 100644 --- a/src/booking/tasks.py +++ b/src/booking/tasks.py @@ -82,6 +82,9 @@ def booking_task(booking_request: BookingRequest): thsr_ticket = PageParser.get_booked_ticket_info(complete_booking_page) with transaction.atomic(): thsr_ticket.save() + if booking_request.booking_method: + booking_request.train_id = thsr_ticket.train_id + booking_request.thsr_ticket = thsr_ticket booking_request.status = BookingRequest.Status.COMPLETED booking_request.error_msg = '' diff --git a/src/src/fixtures/auth_group.json b/src/src/fixtures/auth_group.json new file mode 100644 index 0000000..fc555e0 --- /dev/null +++ b/src/src/fixtures/auth_group.json @@ -0,0 +1,12 @@ +[ + { + "fields": { + "name": "normal_user", + "permissions": [ + 26, 28, 29, 30, 31, 32, 36 + ] + }, + "model": "auth.Group", + "pk": 1 + } +] \ No newline at end of file diff --git a/src/src/management/commands/setup.py b/src/src/management/commands/setup.py new file mode 100644 index 0000000..b808e3d --- /dev/null +++ b/src/src/management/commands/setup.py @@ -0,0 +1,13 @@ +import glob + +from django.core.management import call_command +from django.core.management.base import BaseCommand + + +def find_all_fixtures(wildcard: str) -> list[str]: + return glob.glob(wildcard, recursive=True) + + +class Command(BaseCommand): + def handle(self, *args, **options): + call_command('loaddata', *find_all_fixtures('*/fixtures/*')) diff --git a/src/src/settings/__init__.py b/src/src/settings/__init__.py index 77a9c3b..21e8dff 100644 --- a/src/src/settings/__init__.py +++ b/src/src/settings/__init__.py @@ -149,6 +149,7 @@ # https://docs.djangoproject.com/en/4.2/howto/static-files/ STATIC_URL = 'static/' +STATIC_ROOT = '/src/static/' # Default primary key field type # https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field diff --git a/src/src/urls.py b/src/src/urls.py index 3a6b005..63d16ce 100644 --- a/src/src/urls.py +++ b/src/src/urls.py @@ -15,10 +15,11 @@ 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin +from django.contrib.staticfiles.urls import staticfiles_urlpatterns from django.urls import include, path urlpatterns = [ path('admin/', admin.site.urls), path('api/user/', include('user.urls')), path('api/booking/', include('booking.urls')), -] +] + staticfiles_urlpatterns() diff --git a/src/user/migrations/0001_initial.py b/src/user/migrations/0001_initial.py index 36e306c..97ef9e7 100644 --- a/src/user/migrations/0001_initial.py +++ b/src/user/migrations/0001_initial.py @@ -1,6 +1,7 @@ -# Generated by Django 4.2 on 2023-10-07 19:27 +# Generated by Django 4.2 on 2024-02-10 17:32 from django.db import migrations, models +import django.db.models.deletion class Migration(migrations.Migration): @@ -8,6 +9,7 @@ class Migration(migrations.Migration): initial = True dependencies = [ + ('auth', '0012_alter_user_first_name_max_length'), ] operations = [ @@ -16,7 +18,7 @@ class Migration(migrations.Migration): fields=[ ('created_at', models.DateTimeField(auto_now_add=True)), ('updated_at', models.DateTimeField(auto_now=True)), - ('id', models.CharField(editable=False, max_length=8, primary_key=True, serialize=False)), + ('code', models.CharField(max_length=8, primary_key=True, serialize=False)), ('is_used', models.BooleanField(default=False)), ], options={ @@ -27,21 +29,28 @@ class Migration(migrations.Migration): name='User', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('password', models.CharField(max_length=128, verbose_name='password')), + ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), + ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), ('created_at', models.DateTimeField(auto_now_add=True)), ('updated_at', models.DateTimeField(auto_now=True)), - ('email', models.EmailField(max_length=254)), - ('password', models.CharField(max_length=255)), - ('invite_code', models.CharField(max_length=8)), - ('personal_id', models.CharField(blank=True, max_length=10)), + ('email', models.EmailField(max_length=254, unique=True)), + ('is_active', models.BooleanField(default=True)), + ('is_staff', models.BooleanField(default=False)), + ('personal_id', models.CharField(blank=True, max_length=10, verbose_name='Personal ID')), ('phone', models.CharField(blank=True, max_length=10)), + ('use_tgo_account', models.BooleanField(default=False, help_text='TGO account is your personal ID')), + ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')), + ('invite_code', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='user.invitecode')), + ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')), ], ), migrations.AddConstraint( model_name='user', - constraint=models.UniqueConstraint(fields=('email',), name='uniq_email'), + constraint=models.UniqueConstraint(models.F('email'), name='uniq_email'), ), migrations.AddConstraint( model_name='user', - constraint=models.UniqueConstraint(fields=('invite_code',), name='uniq_invite_code'), + constraint=models.UniqueConstraint(models.F('invite_code'), name='uniq_invite_code'), ), ] diff --git a/src/user/migrations/0002_user_use_tgo_account.py b/src/user/migrations/0002_user_use_tgo_account.py deleted file mode 100644 index 1165146..0000000 --- a/src/user/migrations/0002_user_use_tgo_account.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.2 on 2024-01-07 16:17 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('user', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='user', - name='use_tgo_account', - field=models.BooleanField(default=False, help_text='TGO Account is your personal_id'), - ), - ] diff --git a/src/user/migrations/0003_alter_user_use_tgo_account.py b/src/user/migrations/0003_alter_user_use_tgo_account.py deleted file mode 100644 index 6b11e50..0000000 --- a/src/user/migrations/0003_alter_user_use_tgo_account.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.2 on 2024-01-08 16:49 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('user', '0002_user_use_tgo_account'), - ] - - operations = [ - migrations.AlterField( - model_name='user', - name='use_tgo_account', - field=models.BooleanField(default=False, help_text='TGO account is your personal ID'), - ), - ] diff --git a/src/user/migrations/0004_remove_user_uniq_email_remove_user_uniq_invite_code_and_more.py b/src/user/migrations/0004_remove_user_uniq_email_remove_user_uniq_invite_code_and_more.py deleted file mode 100644 index 1b9d9c5..0000000 --- a/src/user/migrations/0004_remove_user_uniq_email_remove_user_uniq_invite_code_and_more.py +++ /dev/null @@ -1,70 +0,0 @@ -# Generated by Django 4.2 on 2024-02-09 12:19 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('auth', '0012_alter_user_first_name_max_length'), - ('user', '0003_alter_user_use_tgo_account'), - ] - - operations = [ - migrations.RemoveConstraint( - model_name='user', - name='uniq_email', - ), - migrations.RemoveConstraint( - model_name='user', - name='uniq_invite_code', - ), - migrations.AddField( - model_name='user', - name='groups', - field=models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups'), - ), - migrations.AddField( - model_name='user', - name='is_active', - field=models.BooleanField(default=True), - ), - migrations.AddField( - model_name='user', - name='is_staff', - field=models.BooleanField(default=False), - ), - migrations.AddField( - model_name='user', - name='is_superuser', - field=models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status'), - ), - migrations.AddField( - model_name='user', - name='last_login', - field=models.DateTimeField(blank=True, null=True, verbose_name='last login'), - ), - migrations.AddField( - model_name='user', - name='user_permissions', - field=models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions'), - ), - migrations.AlterField( - model_name='user', - name='email', - field=models.EmailField(max_length=254, unique=True), - ), - migrations.AlterField( - model_name='user', - name='password', - field=models.CharField(max_length=128, verbose_name='password'), - ), - migrations.AddConstraint( - model_name='user', - constraint=models.UniqueConstraint(models.F('email'), name='uniq_email'), - ), - migrations.AddConstraint( - model_name='user', - constraint=models.UniqueConstraint(models.F('invite_code'), name='uniq_invite_code'), - ), - ] diff --git a/src/user/migrations/0005_rename_id_invitecode_code_alter_user_personal_id.py b/src/user/migrations/0005_rename_id_invitecode_code_alter_user_personal_id.py deleted file mode 100644 index af783cf..0000000 --- a/src/user/migrations/0005_rename_id_invitecode_code_alter_user_personal_id.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 4.2 on 2024-02-09 12:51 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('user', '0004_remove_user_uniq_email_remove_user_uniq_invite_code_and_more'), - ] - - operations = [ - migrations.RenameField( - model_name='invitecode', - old_name='id', - new_name='code', - ), - migrations.AlterField( - model_name='user', - name='personal_id', - field=models.CharField(blank=True, max_length=10, verbose_name='Personal ID'), - ), - ] diff --git a/src/user/migrations/0006_alter_invitecode_code_alter_user_invite_code.py b/src/user/migrations/0006_alter_invitecode_code_alter_user_invite_code.py deleted file mode 100644 index 171e77f..0000000 --- a/src/user/migrations/0006_alter_invitecode_code_alter_user_invite_code.py +++ /dev/null @@ -1,24 +0,0 @@ -# Generated by Django 4.2 on 2024-02-09 13:13 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('user', '0005_rename_id_invitecode_code_alter_user_personal_id'), - ] - - operations = [ - migrations.AlterField( - model_name='invitecode', - name='code', - field=models.CharField(max_length=8, primary_key=True, serialize=False), - ), - migrations.AlterField( - model_name='user', - name='invite_code', - field=models.ForeignKey(db_constraint=False, on_delete=django.db.models.deletion.DO_NOTHING, to='user.invitecode'), - ), - ] diff --git a/src/user/migrations/0007_alter_user_invite_code.py b/src/user/migrations/0007_alter_user_invite_code.py deleted file mode 100644 index 0d5f0fd..0000000 --- a/src/user/migrations/0007_alter_user_invite_code.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 4.2 on 2024-02-09 13:14 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('user', '0006_alter_invitecode_code_alter_user_invite_code'), - ] - - operations = [ - migrations.AlterField( - model_name='user', - name='invite_code', - field=models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='user.invitecode'), - ), - ]