Author SHA1 Message Date
Dniel97 7066651549 Merge branch 'develop' into fork_develop 2024-03-12 18:34:04 +01:00
Hay1tsme 84fa139357 idac: add missing await, fixes #111 2024-03-12 10:14:03 -04:00
Kevin Trocolli b63c2c2d12 dbutils: add autocreate option to revision 2024-03-11 21:24:57 -04:00
Hay1tsme 6557cac55b ongeki: add support for bright memory act 2 final 2024-03-07 15:20:02 -05:00
Kevin Trocolli c4deff9d1c add database downgrading 2024-03-04 00:50:51 -05:00
Midorica bc2b883fa9 sao: quick fix to the documentation 2024-03-03 14:23:19 -05:00
Midorica 86f419278d sao: adjust documentation 2024-03-03 12:25:25 -05:00
Midorica 3fe8bc8c62 sao: fixing default party 2024-03-02 19:44:16 -05:00
Midorica 3557578bcd sao: quick fixes to profile and rewards 2024-03-02 19:38:34 -05:00
Kevin Trocolli 6f654f8ba9 mai2: remove redundant method (fixes #103) 2024-03-02 18:00:14 -05:00
Kevin Trocolli 3559d56ccf cm: add awaits (fixes #104) 2024-03-02 17:55:41 -05:00
Kevin Trocolli e69149632f frontend: fix namechange and password change failing 2024-03-02 17:52:01 -05:00
Kevin Trocolli bd97428166 frontend: fix account and owner creation (fixes #108) 2024-03-02 17:48:48 -05:00
Kevin Trocolli 84c059ed75 idac: add missing await to handle_user_updatespecialmoderesult_request (closes #109) 2024-03-02 17:28:19 -05:00
zaphkito 91f49f52cc fix coroutine CardMakerReader.read_*** was never awaited (#105)
Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/105
Co-authored-by: zaphkito <zaphkito@noreply.gitea.tendokyu.moe>
Co-committed-by: zaphkito <zaphkito@noreply.gitea.tendokyu.moe>
2024-03-02 22:25:54 +00:00
Hay1tsme f708b8ea4f wacca: fix lily handle_user_status_update_request 2024-02-27 20:42:20 -05:00
Midorica b83399cef4 cxb: hotfix to classic rev 2024-02-26 18:35:34 -05:00
Kevin Trocolli 43d0edf036 docs: add note about memcached 2024-02-26 00:18:31 -05:00
Kevin Trocolli 4363b8321b mucha: UTC_SERVER_TIME -> SERVER_TIME_UTC 2024-02-24 16:49:02 -05:00
Kevin Trocolli b7f56c20a7 wacca: fix version string printing 2024-02-17 00:21:37 -05:00
Hay1tsme b462a2720a fix database config field protocol 2024-02-14 16:56:40 -05:00
Hay1tsme 89c2b324dc aimedb: add last login time update to register endpoints 2024-02-12 15:58:02 -05:00
Hay1tsme 4149944d56 aimedb: update card last login time properly 2024-02-12 15:53:28 -05:00
Hay1tsme d4e00781c8 ongeki: Fix error loading user music (#100) 2024-02-12 11:40:24 -05:00
Hay1tsme 50f42f850a idac: fix database issues 2024-02-09 10:48:39 -05:00
Kevin Trocolli d38207cdc3 fix billing server not working on some games 2024-02-09 09:56:38 -05:00
Midorica b0f603cbd8 Merge pull request 'SAO: Adding assets for the reader & edited game specific info' (#99) from Midorica/artemis:develop into develop
Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/99
2024-02-02 20:16:04 +00:00
Midorica 864b749f20 sao: adding reader assets 2024-02-02 15:10:36 -05:00
Kevin Trocolli 9844b7ebdb add license 2024-01-29 02:06:59 -05:00
Hay1tsme 77dfec0483 docs: inf 2024-01-25 16:29:53 -05:00
Hay1tsme c7aa3f2479 docs: i suck at typing 2024-01-25 16:09:34 -05:00
Hay1tsme 9f67079614 docs: fix typos 2024-01-25 15:24:21 -05:00
Hay1tsme d2177bdbed docs: add windows install guide 2024-01-25 15:12:26 -05:00
Hay1tsme ce5888227e idz: fix userdb 2024-01-23 11:31:09 -05:00
Hay1tsme 83b981917e sao: add logout_ticket_unpurchased, get_quest_hierarchy_progress_degrees_ranking_list and get_quest_popular_hero_log_ranking_list 2024-01-22 17:42:58 -05:00
Hay1tsme 3a710c671e sao: fix data issues 2024-01-22 16:45:09 -05:00
Hay1tsme 348edef0f5 idac: add missing await 2024-01-22 16:35:43 -05:00
Hay1tsme 60e9cd2edd sao: fix bad find and replace 2024-01-22 16:30:32 -05:00
Hay1tsme 404496191d mucha: remove print statement 2024-01-22 16:25:51 -05:00
Hay1tsme 8864b2625d fix proxy ports 2024-01-22 16:21:49 -05:00
Hay1tsme 200bfe7d84 mucha: oops 2024-01-22 15:55:10 -05:00
Hay1tsme 6ed80ecbab fix ongeki and sao 2024-01-22 15:49:06 -05:00
Hay1tsme 9a021d4005 mucha: add shop info 2024-01-22 15:32:43 -05:00
Hay1tsme 66c9548dd2 mucha: move to starlette 2024-01-22 15:03:59 -05:00
Hay1tsme 029be55cc0 mucha: fix handlers 2024-01-22 14:59:53 -05:00
Hay1tsme 5c9570d421 allnet: fix placeid formatting 2024-01-22 14:47:36 -05:00
Hay1tsme 8d416d7633 allnet: add exception handling if get_allnet_info fails 2024-01-22 14:44:21 -05:00
Hay1tsme a15ad77f20 csb: fix get_allnet_info 2024-01-22 14:42:13 -05:00
Hay1tsme 384924335c allnet: populate title registry when launching standalone 2024-01-22 14:42:02 -05:00
Midorica 58c7d3f22d readme: fixing typo for maimai 2024-01-18 14:28:32 -05:00
Midorica 1cced47c1d Merge pull request 'Modifying readme to add game version names' (#95) from Midorica/artemis:develop into develop
Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/95
2024-01-18 18:36:29 +00:00
Midorica 4b2bce9d12 fixing the order of the games in the readme 2024-01-18 13:35:34 -05:00
Midorica 220ba8ba54 modifying readme for game versions 2024-01-18 13:13:36 -05:00
Kevin Trocolli 1c3f52974d cardmaker: add missing await (thanks galexion!) 2024-01-16 19:19:25 -05:00
Kevin Trocolli de013766f6 cardmaker: fix method not allowed 2024-01-16 02:47:59 -05:00
Kevin Trocolli a4262b9285 update install guides 2024-01-14 18:40:14 -05:00
Kevin Trocolli f41eb907ef update prod.md 2024-01-14 17:46:52 -05:00
Kevin Trocolli a3b1d07c73 update nginx example config 2024-01-14 17:42:58 -05:00
Kevin Trocolli 7cf8b4fd5f aimedb: allow listen address override 2024-01-14 16:48:41 -05:00
Kevin Trocolli e36989e7cc billing: fix overzealous find and replace 2024-01-14 16:43:25 -05:00
Kevin Trocolli 1003651fb4 add alembic to requirements.txt 2024-01-14 03:34:45 -05:00
Kevin Trocolli 97e5c29cf5 frontend: utf16 -> utf8 2024-01-13 17:15:02 -05:00
Kevin Trocolli cdc1b302f2 docs: fix inaccurate config description 2024-01-13 01:34:57 -05:00
Kevin Trocolli ff26485c93 update config documentation 2024-01-13 01:32:19 -05:00
Hay1tsme e80b0671c2 frontend: add charset=utf16 2024-01-12 18:03:44 -05:00
Hay1tsme ae09c2ad48 chuni: add frontend 2024-01-12 18:03:11 -05:00
Kevin Trocolli 9a7d5bc689 fix logging 2024-01-11 21:01:51 -05:00
Kevin Trocolli fc3f0900b3 dbutils: add create-revision command 2024-01-11 20:48:27 -05:00
Kevin Trocolli 19fd008598 fix legacy upgrade script 2024-01-11 20:39:29 -05:00
Kevin Trocolli ba7cb07208 update default config value 2024-01-11 20:34:53 -05:00
Kevin Trocolli 31969221e2 sao: change handle_c12a to async 2024-01-11 20:25:30 -05:00
Kevin Trocolli df4c667adf Merge branch 'starlette_cleanup' into develop 2024-01-11 20:24:59 -05:00
Hay1tsme 72bac55353 update docs 2024-01-11 12:36:34 -05:00
Hay1tsme bb752563cc aimedb: add enable toggle 2024-01-11 12:25:35 -05:00
Hay1tsme a676e42a59 fix old value being in config 2024-01-11 12:16:45 -05:00
Hay1tsme 6dd46a5aa7 fix default config typo 2024-01-11 12:09:19 -05:00
Hay1tsme fb36cc9b07 configuration changes, update docs 2024-01-11 12:08:22 -05:00
Hay1tsme 3bfc9cc845 sao: stub give_free_ticket 2024-01-10 12:51:40 -05:00
Kevin Trocolli 06e7288cad ongeki: fix frontend page 2024-01-09 21:16:22 -05:00
Kevin Trocolli d01ceab92f idac: remove hanging "'s" on frontend if the person viewing the page doesn't have a profile 2024-01-09 21:03:58 -05:00
Kevin Trocolli 0a56207e90 frontend: fix cab list on arcade page 2024-01-09 20:08:10 -05:00
Kevin Trocolli d672edb266 fix searching for an arcade by serial 2024-01-09 19:45:39 -05:00
Kevin Trocolli 805b8f5b3e allnet: fix error parsing dli files 2024-01-09 19:10:54 -05:00
Kevin Trocolli 8a99f94c93 aimedb: fix felica lookups failing 2024-01-09 19:10:39 -05:00
Kevin Trocolli 5e6efbd092 wacca: fix network BAD 2024-01-09 19:10:24 -05:00
Kevin Trocolli be0e407ebe wacca: fix hash 2024-01-09 18:49:43 -05:00
Hay1tsme c680c2d4e9 readd get_title_port_ssl 2024-01-09 17:49:18 -05:00
Hay1tsme 261d09aaef dbutils: add legacy migration 2024-01-09 17:11:49 -05:00
Hay1tsme 2c1958eb04 fix SDDT v5 rollback script 2024-01-09 16:23:08 -05:00
Hay1tsme 37304500a5 fix SDDT v5 rollback and v6 upgrade scripts 2024-01-09 16:22:43 -05:00
Hay1tsme e6dad1cb34 ongeki: fix v6 upgrade script 2024-01-09 16:08:48 -05:00
Hay1tsme 2d95e29f3c remove unused imports 2024-01-09 15:59:58 -05:00
Hay1tsme f8c77e69ed remove unused table 2024-01-09 15:56:49 -05:00
Hay1tsme 9dab26b122 port frontend changes from different project 2024-01-09 15:54:34 -05:00
Hay1tsme e27ac4b81f fix dockerfile 2024-01-09 14:46:43 -05:00
Hay1tsme 05586df08a move to async database 2024-01-09 14:42:17 -05:00
Hay1tsme edd3ce8ead move to alembic 2024-01-09 13:57:59 -05:00
Hay1tsme 07cbbcc377 idac: fix matching 2024-01-09 12:52:53 -05:00
Hay1tsme 4bc77a8ef6 cxb: impl JSONResponseNoASCII 2024-01-09 12:44:48 -05:00
Hay1tsme 1c22c6bec0 idac: add echo server 2024-01-09 12:41:47 -05:00
Hay1tsme 7b49a8ab58 add JSONResponseNoASCII 2024-01-09 12:41:32 -05:00
Hay1tsme f65aa4d60a idz: add socket servers 2024-01-09 12:21:31 -05:00
Hay1tsme 4b9db8be3b add uvicorn to requirements 2024-01-09 11:49:22 -05:00
Hay1tsme 5c124a7d61 chuni: remove semicolon 2024-01-09 11:48:28 -05:00
Hay1tsme b0536e45ed chuni: remove semicolon 2024-01-09 11:43:43 -05:00
Hay1tsme 08c831ff8c add missing credit to changelog 2024-01-09 10:35:50 -05:00
Hay1tsme 0c3924a8f0 aimedb: fix lookup with banned or locked access code 2024-01-09 10:33:48 -05:00
zaphkito 4550cb2af5 delete "ADD config config" (#83)
this is because everywhere about docker build write to create and use configs/config folder, not config, if we follow docker installation guide, there will not exist config folder in artemis root. Even if the folder exists, the folder will not be mapped inside the container, then we will get a build error about config not exist
in docker-compose.yml
```
  app:
    hostname: ma.app
    build: .
    volumes:
      - ./aime:/app/aime
      - ./configs/config:/app/config
```

in INSTALL_DOCKER.md

- Create 'aime', 'configs', 'AimeDB', and 'logs' folder in ARTEMiS root folder (where all source files exist)
- Inside configs folder, create 'config' folder, and copy all .yaml files from example_config to config (thats all files without nginx_example.conf)
- Edit .yaml files inside configs/config to suit your server needs
- Edit core.yaml inside configs/config

I checked this file history
in https://gitea.tendokyu.moe/Hay1tsme/artemis/commit/d1259509ad2bad2b43d2cf5164841775b10502f2, phantomlan already delete this, but don't know why it come back between https://gitea.tendokyu.moe/Hay1tsme/artemis/commit/040742a9a4e00efa162f55450a370a79ece91d53 and https://gitea.tendokyu.moe/Hay1tsme/artemis/commit/565dc38e9a4becf3ea4ddeeaf268d1648cb7eb6c, maybe git bug? However, now delete it again

Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/83
Co-authored-by: zaphkito <zaphkito@noreply.gitea.tendokyu.moe>
Co-committed-by: zaphkito <zaphkito@noreply.gitea.tendokyu.moe>
2024-01-09 15:31:03 +00:00
Kevin Trocolli 4933ad72f2 adb: change warning to debug 2024-01-09 03:17:23 -05:00
Kevin Trocolli cc68b7f6c6 adb: fix timeout issue 2024-01-09 03:16:31 -05:00
Kevin Trocolli 14fa0f5e8e begin move 2024-01-09 03:07:04 -05:00
Kevin Trocolli b056ff218d Update changelog 2024-01-08 21:25:45 -05:00
Kevin Trocolli 01591a0456 chuni: revert changes to udpHolePunchUri and reflectorUri 2024-01-08 21:23:10 -05:00
Kevin Trocolli b4b40869c1 chuni: add roomId to handle_get_matching_state_api_request, update changelog 2024-01-08 20:21:27 -05:00
Hay1tsme c9dfbc77c4 Merge pull request 'Fix issue in handle_get_user_music_api_request for Chunithm where songs would not always return all scores' (#92) from Kumubou/artemis:develop into develop
Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/92
2024-01-09 01:20:46 +00:00
Hay1tsme 1b3e43b918 chuni: Imrpove GetGameSetting request handling for different versions 2024-01-08 18:30:03 -05:00
Hay1tsme f5c77f04fa update changelog 2024-01-08 18:23:15 -05:00
Hay1tsme 27bf51f9f8 chuni: add matching config, stun turn stuff 2024-01-08 18:22:09 -05:00
Hay1tsme 343424e26a update changelog 2024-01-08 18:00:06 -05:00
Kumubou 5f33b2d3e4 Fix issue in handle_get_user_music_api_request where songs would not always return all scores 2024-01-03 22:05:24 +00:00
Midorica 19baf05d7b cxb: fixing get_allnet_info 2023-12-29 13:59:53 -05:00
Midorica 32419faf01 Update docs/game_specific_info.md
Removing unused option details for cxb
2023-12-29 03:20:44 +00:00
Midorica bf7d709b49 chuni: fixing the network encryption for Sun Plus 2023-12-15 22:22:36 -05:00
Midorica 37b1f41b44 fixing the upgrade & downgrade script for chunithm 2023-12-15 22:21:05 -05:00
Midorica 7b8611cee3 Merge pull request 'Chunithm Sun Plus, Int support' (#78) from EmmyHeart/artemis-sp:develop into develop
Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/78
2023-12-16 03:20:02 +00:00
EmmyHeart d0f8568e17 Fixed Rival Music API not returning everything due to iteration issues 2023-12-13 23:28:00 +00:00
EmmyHeart fd0fefa48b Added Sun Plus to example config
my bad
2023-12-13 12:28:28 +00:00
EmmyHeart b5462276f5 Last remnant. Goodbye, rank scaling. 2023-12-13 07:35:07 +00:00
EmmyHeart 626ea58f75 Updated game specific info for Sun Plus
Also removed some old info about rank scaling, since it got YEETed
2023-12-13 07:34:37 +00:00
EmmyHeart 40e6e42c87 Updated readme.md 2023-12-13 07:33:01 +00:00
EmmyHeart a2d238857c Fixed CM compatibility with new Chuni URL structure 2023-12-13 06:37:30 +00:00
EmmyHeart a6b315185d Incremented schema version 2023-12-13 06:35:55 +00:00
EmmyHeart 9b9d1f664d Rollback for Sun Plus changed
should hopefully never need to use this
2023-12-13 06:34:32 +00:00
EmmyHeart b6d1f2cd3a Updated playlog and best tables for Sun Plus
Lord have mercy, this is my first schema update
2023-12-13 06:33:06 +00:00
EmmyHeart 0060122613 Recognize Chunithm Int code 2023-12-13 06:09:02 +00:00
EmmyHeart 97963adf38 Updated matchnaming URLs to use game codes 2023-12-13 06:07:40 +00:00
EmmyHeart 1bfe3584b1 Updated matchmaking URLs to reflect game codes 2023-12-13 06:06:16 +00:00
EmmyHeart ec4ae98beb Updated matchnaming URLs to utilize game codes 2023-12-13 06:05:46 +00:00
EmmyHeart a0dc8421eb Updated schema for changes in Sun Plus
isClear and isSuccess are now integers to represent different clear types, although more research is needed into what those types mean.
2023-12-13 06:04:21 +00:00
EmmyHeart ed731e7407 Added Sun Plus support 2023-12-13 06:02:32 +00:00
EmmyHeart 15204f8d8a Added Sun Plus support, and Int workaround
Int versions of Chunithm use nearly the same endpoints, just with C3Exp at the end. We can treat them the same as the regular versions of the game for now by simply removing the C3Exp portion of the endpoints and running our current logic. Note that later we should treat Int and JP as separate versions
2023-12-13 06:01:31 +00:00
EmmyHeart 32362dbe1e Added const support for both International and Sun Plus 2023-12-13 05:58:22 +00:00
EmmyHeart 59db7ad44a Fixed a null condition when importing from Aqua 2023-12-13 05:56:40 +00:00
Kevin Trocolli 5491266a85 sao: fix https 2023-12-10 18:35:59 -05:00
Kevin Trocolli 283cf41bce chuni: bandaid fix for if a user or team is named 'true' or 'false', fixes #65 2023-12-10 17:41:05 -05:00
Kevin Trocolli 26cdc6c10f maidx: ignore guest upserts, fixes #74 2023-12-10 17:36:29 -05:00
Kevin Trocolli c1412ca9a8 sao: fix title server port 2023-12-10 17:27:50 -05:00
Hay1tsme 21492fbfb3 wacca: hotfix handle_housing_start_request 2023-12-07 18:53:51 -05:00
Hay1tsme 82c5ae3ad7 wacca: fix housing/start on lilyr and above 2023-12-07 16:07:17 -05:00
Hay1tsme 262155f83f ongeki: fix handle_upsert_client_setting_api_request 2023-12-04 11:40:20 -05:00
Hay1tsme 936316f129 ongeki: fix put_client_setting_data 2023-12-04 11:34:58 -05:00
Kevin Trocolli 104a483f4c maimai: fixes for finale 2023-12-02 22:30:55 -05:00
Hay1tsme 29a1dac983 Merge pull request 'Fixed typo in game_specific_info.md' (#73) from AkaiiKitsune/artemis:akaiikitsune-typo into develop
Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/73
2023-12-03 02:13:56 +00:00
Kevin Trocolli 8c0ebbd21b mai: fix pre-dx 2023-12-02 21:01:55 -05:00
Kevin Trocolli d024b2eeb8 billing: fixes 2023-12-02 21:01:33 -05:00
Hay1tsme ed2d306dee adb: add configurable auth id lifetime 2023-11-30 18:22:01 -05:00
Hay1tsme ffc0f2fa5e add keychip ID to auth key 2023-11-30 18:17:40 -05:00
Hay1tsme a1569bca9d fix typing for create_sega_auth_key 2023-11-30 18:14:20 -05:00
Hay1tsme cc86d4509e adb: fix for when user_id is None 2023-11-30 18:10:22 -05:00
Kevin Trocolli 216fa49f8b aimedb: implement auth keys 2023-11-30 02:07:24 -05:00
Kevin Trocolli 662fd05d24 ongeki: bump schema ver, fix error if events lookup fails 2023-11-29 18:56:57 -05:00
Hay1tsme 46f61325cb aimedb: soft impl of auth ids 2023-11-29 18:01:19 -05:00
Hay1tsme e7fb9ce07d mai2: fix get_allnet_info 2023-11-29 11:39:19 -05:00
Farewell_ fbc0e489bc Fixed typo in game_specific_info.md
I suck at git; The Maimai version table has been fixed as suggested.
2023-11-29 11:34:15 +00:00
Hay1tsme 6774716e06 add sega auth key encode/decode in Utils, requires pyjwt 2023-11-27 16:39:50 -05:00
Midorica 2efdf79b87 Merge pull request 'fixup technical challenge event' (#71) from phantomlan/artemis:develop into develop
Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/71
2023-11-25 23:24:00 +00:00
phantomlan cf0c34cafb fixup technical challenge event 2023-11-26 00:12:23 +01:00
Midorica 5fd966eaad cxb: adding non-omni music list support 2023-11-25 16:03:26 -05:00
Midorica cdd67ffbc3 cxb: fix data handlers for s1 & add coupons for s2 2023-11-25 15:41:38 -05:00
Midorica 7fb98118b2 cxb: fixing index and rss2 /data handler 2023-11-25 13:23:39 -05:00
Kevin Trocolli fe25359e8e chuni: add userRecentPlayerList check in upsertuserall 2023-11-25 01:00:49 -05:00
Kevin Trocolli 468c99c3c2 add gitattributes to hopefully stop git from clowing our CSV, TXT and JSON data files 2023-11-25 00:43:48 -05:00
Kevin Trocolli 6504f120ad chuni: bandaid fixes for air 2023-11-25 00:31:15 -05:00
Kevin Trocolli d769285d89 Merge branch 'develop' of https://gitea.tendokyu.moe/Hay1tsme/artemis into develop 2023-11-24 10:36:47 -05:00
Kevin Trocolli ad61bb3d9b mai2: fis issue with saving and loading charges 2023-11-24 10:36:46 -05:00
Hay1tsme e941c6a606 add host field to allnet response for some games to fix an issue with nginx 2023-11-20 11:54:13 -05:00
Kevin Trocolli 8bd361d3e3 wacca: fix some logging 2023-11-19 12:15:57 -05:00
Kevin Trocolli 0eee2e92a8 wacca: fix bad items being given 2023-11-19 11:43:46 -05:00
Kevin Trocolli b4a0d331d4 wacca: fix housing/start for unregistered serials 2023-11-19 11:28:42 -05:00
Kevin Trocolli d467070ba7 wacca: fix handle_user_status_create_request for lily 2023-11-19 01:18:09 -05:00
Kevin Trocolli e7f35db3a4 fix comparability with python 8.7 - 3.10 2023-11-19 01:05:34 -05:00
Kevin Trocolli 0422a2bfd4 wacca: fix lily using wrong handler for hosuing/start 2023-11-19 01:05:16 -05:00
Hay1tsme 05be10dabc wacca: add request validation, fix HousingStartRequestV2 2023-11-17 11:37:11 -05:00
Hay1tsme 9a017f75e9 wacca: add traceback printing 2023-11-17 10:57:12 -05:00
Hay1tsme 69cd79003c wacca: fix exception handling 2023-11-17 10:45:18 -05:00
Midorica d3b01e03c5 Merge pull request 'Hotfix for mission events' (#68) from phantomlan/artemis:develop into develop
Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/68
2023-11-15 14:30:33 +00:00
phantomlan a7e0099294 Merge branch 'develop' of https://gitea.tendokyu.moe/phantomlan/artemis into develop 2023-11-15 15:14:23 +01:00
phantomlan dcebc5c21a update item.py put_mission_point 2023-11-15 15:11:39 +01:00
phantomlan 04c708be8c update item.py put_mission_point 2023-11-15 15:09:57 +01:00
Kevin Trocolli 67c9ac5ef9 sao: noop get_m_res_earn_campaign_shops 2023-11-15 00:46:51 -05:00
Hay1tsme 328f64ad8a sao: hotfix 2023-11-14 22:11:24 -05:00
Hay1tsme e0aeb2ac21 sao: fix temp responses 2023-11-14 22:08:09 -05:00
Hay1tsme 3d8ffaa098 sao: fix csc fields not being integers 2023-11-14 21:24:33 -05:00
Hay1tsme 7eb095cdb4 soa: fix get_m_gasha_medal_shops 2023-11-14 21:18:22 -05:00
Hay1tsme 9c49a4f54a sao: fix get_m_res_earn_campaign_shops 2023-11-14 21:07:58 -05:00
Hay1tsme dffa11f420 sao: fix get_m_gasha_medal_shops 2023-11-14 20:51:51 -05:00
Kevin Trocolli 1ba14da90c sao: gasha medal shop handler classes 2023-11-14 13:20:05 -05:00
Hay1tsme 0003ca4412 sao: fix bad handlers 2023-11-13 17:39:45 -05:00
Hay1tsme 0ca041c042 sao: fix date formatting in YuiMedalShopData 2023-11-13 17:36:22 -05:00
Hay1tsme 25528203fe sao: fix encoder helpers 2023-11-13 17:31:23 -05:00
Hay1tsme a06d1aaf8c sao: fix helpers 2023-11-13 17:24:22 -05:00
Hay1tsme e035806b41 sao: fix yui shops 2023-11-13 17:17:27 -05:00
Hay1tsme a9f72cec69 sao: add shop data tables 2023-11-13 14:45:20 -05:00
Hay1tsme 22cf3f83a6 remove randbytes 2023-11-13 13:47:17 -05:00
Hay1tsme ee45c55f66 sao: stub get_shop_resource_sales_data_list 2023-11-13 12:53:40 -05:00
Hay1tsme 2c275d1130 idac: add logging to setup 2023-11-13 12:14:34 -05:00
Midorica b19288fb7e idac: removing public urls 2023-11-13 12:06:14 -05:00
Midorica a83edee657 Merge pull request 'Initial D THE ARCADE support added' (#41) from Dniel97/artemis:idac into develop
Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/41
2023-11-13 16:35:53 +00:00
Dniel97 d1a7b898a7 idac: hotfix for title port and changelog 2023-11-13 17:32:39 +01:00
Dniel97 e561f8f15d idac: updated to latest develop branch, minified timeRelease json 2023-11-13 17:27:14 +01:00
Midorica c9a20b2433 ongeki: fixing render_POST 2023-11-13 10:47:39 -05:00
Midorica 1034a505f0 fixing get_allnet_info for cxb, sao and ongeki 2023-11-13 10:43:38 -05:00
Dniel97 565dc38e9a Merge branch 'develop' into idac 2023-11-13 16:18:04 +01:00
Midorica 1a4dc88c8a cxb: cleanup of config 2023-11-13 10:12:52 -05:00
Midorica 005adfae38 Merge pull request 'Add Support for Missing API Calls in ONGEKI' (#61) from phantomlan/artemis:develop into develop
Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/61
2023-11-13 03:15:47 +00:00
phantomlan 80ae372ccf fix rollback 2023-11-13 04:05:13 +01:00
phantomlan e461ffe587 add more info 2023-11-13 03:38:30 +01:00
phantomlan b56a5f020b add rollback sql
move GP support to table in DB
small fixes
2023-11-13 03:26:09 +01:00
phantomlan d663b1ef7c fix foreign key issue 2023-11-13 03:03:04 +01:00
phantomlan 31d39ffb37 merge conflict fix 2023-11-13 02:01:56 +00:00
phantomlan 530016ef84 i ate one ) 2023-11-13 02:01:56 +00:00
phantomlan f81c53558e - Add ClientTestmode upsert
- Add ClientSetting upsert
- Add endDate for Events
- Add Upgrade Schema
- Small bugfixes for events
2023-11-13 02:01:56 +00:00
phantomlan d2e2c14074 update Event Ranking, Tech Challenge, and Music Ranking 2023-11-13 02:01:56 +00:00
phantomlan 1897e8002d add RewardList support
add PresentList support
add reading rewards to read.py
add Ranking Music List support
2023-11-13 02:01:56 +00:00
phantomlan 4da886a083 - Add Ranking Event Support
- Add Technical Challenge Event Support
- Fix Event Enumeration for EVT_TYPES as Enum starts with 1, to be in spec with what game expects, also add missing Max EVT_TYPE
- Add documentation on how to properly configure and run Events for ONGEKI
2023-11-13 02:01:56 +00:00
Kevin Trocolli 4bedf71d3d sao: fix trial_tower_play_end 2023-11-12 20:02:08 -05:00
Kevin Trocolli 84b44d2a02 sao: add logging to synthesize_enhancement_equipment 2023-11-12 19:55:10 -05:00
Kevin Trocolli b516da2e6e sao: add logging to synthesize_enhancement_hero_log 2023-11-12 19:53:36 -05:00
Kevin Trocolli a767646361 sao: make synthesize_enhancement_hero_log similar to synthesize_enhancement_equipment 2023-11-12 19:48:03 -05:00
Kevin Trocolli 3596f0f34c sao: fix synthesize_enhancement_equipment 2023-11-12 19:45:39 -05:00
Kevin Trocolli ab3b6a9814 sao: fix SaoSynthesizeEnhancementHeroLogRequest 2023-11-12 19:24:08 -05:00
Kevin Trocolli c384a8d1f5 sao: properly initialize material_common_reward_user_data_count 2023-11-12 19:22:46 -05:00
Kevin Trocolli 9bc76279f1 sao: fix episode_play_end 2023-11-12 18:46:38 -05:00
Kevin Trocolli 9026c25fcc sao: fix both unanalyzed log fixed requests 2023-11-12 17:35:06 -05:00
Kevin Trocolli ff48438b85 sao: fix change_party 2023-11-12 17:26:21 -05:00
Midorica e1a70d1a06 sao: fix dict lengths of multiple response handlers 2023-11-12 16:13:04 -05:00
Midorica 1ff0e4e2c6 sao: fix episode_play_end again 2023-11-11 11:10:57 -05:00
Kevin Trocolli c23ab1438e sao: remove unused imports 2023-11-11 01:13:09 -05:00
Kevin Trocolli 773729dc0c sao: fix episode_play_end 2023-11-11 01:11:41 -05:00
Midorica 0e739b2077 adding SSL support for SAO 2023-11-10 23:20:30 -05:00
Midorica c4f2232457 fixing threading profile loading on CXB 2023-11-10 20:32:24 -05:00
Hay1tsme 9fdd96b717 sao: fix synthesize_enhancement_equipment 2023-11-10 18:01:16 -05:00
Hay1tsme c370542761 sao: fix req header 2023-11-10 15:52:55 -05:00
Kevin Trocolli a299ba98ac sao: fix erronius length errors 2023-11-09 23:37:40 -05:00
Kevin Trocolli 44755d4d0f sao: begin implementing request helpers 2023-11-09 23:29:06 -05:00
Kevin Trocolli 3d62b9d372 sao: add SaoResponseHeader 2023-11-09 22:36:33 -05:00
Kevin Trocolli 18bf250fd7 sao: fix length calculation 2023-11-09 21:23:19 -05:00
Kevin Trocolli 0fa8fe06f0 sao: fix crypt maybe 2023-11-09 21:17:18 -05:00
Kevin Trocolli 4cd1181ef7 sao: fix generic handler 2023-11-09 21:09:55 -05:00
Kevin Trocolli 8d190ce7f0 sao: fix padding 2023-11-09 21:05:30 -05:00
Kevin Trocolli 81d588cbc7 sao: crypt fixes 2023-11-09 21:00:51 -05:00
Kevin Trocolli e6801c1c46 sao: add logging 2023-11-09 20:56:33 -05:00
Kevin Trocolli 840db275fa sao: add encrtped response 2023-11-09 20:56:03 -05:00
Midorica 8769c99f4a fixing ongeki handler 2023-11-09 19:34:04 -05:00
Hay1tsme 3c06f46644 sao: add decoder helpers, hash checks 2023-11-09 18:11:58 -05:00
Hay1tsme 95234a421c sao: fix header 2023-11-09 13:47:50 -05:00
Hay1tsme c425ca1ea8 sao: hotfix 2023-11-09 13:41:56 -05:00
Hay1tsme b0ebcaf0cf sao: parse header. add crypt 2023-11-09 13:16:32 -05:00
Hay1tsme 8560c05928 sao: remove hostname/port config, fix allnet uri 2023-11-09 11:55:49 -05:00
Hay1tsme 580a9faae8 sao: fix allnet 2023-11-09 11:51:50 -05:00
Hay1tsme 9537331d1c sao: fix endpoint 2023-11-09 11:32:04 -05:00
Midorica 4047a38370 adding encryption version check for Ongeki 2023-11-09 00:10:19 -05:00
Midorica eaf64dbd50 Merge branch 'develop' of https://gitea.tendokyu.moe/Hay1tsme/artemis into develop 2023-11-09 00:06:24 -05:00
Midorica e769404e16 fixing TLS support for ongeki 2023-11-09 00:06:15 -05:00
Kevin Trocolli eb10bc2560 idz: fix news url 2023-11-08 23:54:35 -05:00
Midorica 4b22bd734e fixing handle_data for Crossbeats 2023-11-08 23:36:26 -05:00
Hay1tsme 94c326a27d ongeki: add option to use https for red and beyond 2023-11-08 21:42:53 -05:00
Kevin TrocolliandHay1tsme cb8eaae2c0 Per-version URI/Host (#66)
Allows setting allnet uri/host response based on things like version, config files, and other factors to accommodate a wider range of potential setups under the same roof. This DOES require all titles to adopt a new structure but it's documented and should hopefully be somewhat intuitive.

Co-authored-by: Hay1tsme <kevin@hay1ts.me>
Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/66
Co-authored-by: Kevin Trocolli <pitok236@gmail.com>
Co-committed-by: Kevin Trocolli <pitok236@gmail.com>
2023-11-09 02:17:48 +00:00
Midorica c2a330f42c Merge pull request 'fix: dockerfile fixes' (#60) from Rylie/artemis:fix/docker into develop
Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/60
2023-11-08 20:53:00 +00:00
Midorica fbd1d7cb1c fixing CXB render_POST 2023-11-06 23:35:02 -05:00
Midorica fbd12fd6e2 fixing get_energy for CXB 2023-11-06 21:54:06 -05:00
Midorica 40e6c018e9 fixing again the render_POST for CXB 2023-11-06 21:04:13 -05:00
Dniel97 4c3852d6d4 IDAC: Added round event "Season 2 2nd" 2023-11-06 19:54:13 +01:00
Dniel97 acac2c4670 IDAC: time trial should display car time now 2023-11-06 18:11:30 +01:00
UncleJim 1224baeade Experimental online match API support and car use countting fix (#5)
Reviewed-on: https://gitea.tendokyu.moe/Dniel97/artemis/pulls/5
Co-authored-by: UncleJim <unclejim@noreply.gitea.tendokyu.moe>
Co-committed-by: UncleJim <unclejim@noreply.gitea.tendokyu.moe>
2023-11-06 15:32:40 +00:00
Rylie 040742a9a4 fix(docker): rename log to logs for consistency 2023-11-05 11:10:01 +07:00
Rylie b4a0736f7b fix(docker): add pkg-config for docker build process 2023-11-05 11:09:52 +07:00
Kevin Trocolli a7b0b1be49 allnet: fix dli report logging 2023-11-04 12:41:47 -04:00
Kevin Trocolli dde397a96c allnet: fix event type for handle_dlorder_report 2023-11-01 20:09:14 -04:00
Kevin Trocolli f99bf7d1ed allnet: add DLI_STATUS 2023-11-01 20:08:20 -04:00
Kevin Trocolli bd3e1918aa allnet: further dl report logging 2023-11-01 01:17:23 -04:00
Kevin Trocolli ffc0a07f6d allnet: fix dl report message typo 2023-11-01 01:02:09 -04:00
Kevin Trocolli ab640760a9 allnet: add event logging to download report 2023-11-01 00:53:04 -04:00
Midorica a8f06ee266 Merge pull request 'Aime Locks/Bans and Chunithm Improvements' (#47) from EmmyHeart/artemis:develop into develop
Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/47
2023-10-27 17:25:35 +00:00
UncleJim 3f192bd84a Proper store name and region handling (#4)
Now the code will read store name from `aime.arcade` table instead of putting `self.core_cfg.server.name` into it braindead-ly

Reviewed-on: https://gitea.tendokyu.moe/Dniel97/artemis/pulls/4
Co-authored-by: UncleJim <unclejim@noreply.gitea.tendokyu.moe>
Co-committed-by: UncleJim <unclejim@noreply.gitea.tendokyu.moe>
2023-10-27 11:05:55 +00:00
Hay1tsme 4b83d3f316 Merge pull request 'wacca: name unknown fields, rename incorrect fields.' (#56) from Yellowberry/artemis:wacca_notice_fix into develop
Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/56
2023-10-27 02:06:38 +00:00
Midorica 1b5c335f4e Merge pull request 'Chunithm: Fix getUserMusic duplicate songs and fix missing song diffs' (#54) from DSRLIN/artemis-bugfix:develop into develop
Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/54
2023-10-27 01:51:43 +00:00
Zsolt Zitting 680223dba2 wacca: name unknown fields, rename incorrect fields. 2023-10-26 14:25:04 -07:00
UncleJim 4fc4d98a74 Always return matching state to keep players out of looping back to matching screen (#6)
Reviewed-on: https://gitea.tendokyu.moe/Dniel97/artemis/pulls/6
Co-authored-by: UncleJim <unclejim@noreply.gitea.tendokyu.moe>
Co-committed-by: UncleJim <unclejim@noreply.gitea.tendokyu.moe>
2023-10-26 10:21:01 +00:00
DSRLIN 3259552c29 update bug 2023-10-26 05:38:33 +00:00
DSRLIN b5ce13d1f1 fix chuni songlist duplicate songs and missing diff 2023-10-26 05:37:11 +00:00
Midorica be86448b23 Merge pull request 'Updates and Fixes for Dockerfile and docker-compose, and docker installation guide' (#51) from phantomlan/artemis:develop into develop
Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/51
2023-10-22 14:22:41 +00:00
phantomlan 01182087e0 Merge branch 'docker-and-docs' into develop 2023-10-21 20:38:14 +02:00
phantomlan e9637c94de update dx.py 2023-10-21 20:35:46 +02:00
phantomlan 37a6502dc9 Merge branch 'docker-and-docs' into develop 2023-10-21 20:04:16 +02:00
phantomlan d1259509ad update pull request 2023-10-21 19:57:45 +02:00
phantomlan 7f1ff60b9d Update docs/INSTALL_DOCKER.md 2023-10-21 15:54:17 +00:00
phantomlan 12d0a3f927 - prettier docker guide
- update docker-compose to reflect 1 level higher config folder
2023-10-21 17:47:23 +02:00
phantomlan 5420076c8e - update docker-compose database charset and collation to utf8mb4
- update TODO list in docker guide
- update readme.md
2023-10-21 17:33:58 +02:00
phantomlan a3d2955fce - update docker-compose.yml
- update mysqldb to mariadb-alpine
- update mysql healthcheck to also include Password
- update memcached to alpine counterpart
- update phpmyadmin port to not collide with ARTEMiS main app
- add commented out options for DB Persistency

- update Dockerfile
- add read.py to Dockerfile

- add docs/INSTALL_DOCKER.md guide
2023-10-21 17:22:58 +02:00
EmmyHeart 990d60cf27 Forgot to remove rank scale option from the example config, as it does literally nothing now lol 2023-10-20 04:25:08 +00:00
EmmyHeart 21cb37001b Stubbed Team Course functions as they do not currently do anything 2023-10-20 03:31:36 +00:00
EmmyHeart 32903d979e Added code for song rankings using romVersion, and ensuring romVersion is set on playlog upsert 2023-10-20 03:29:05 +00:00
EmmyHeart 3f8c62044c Optimized rival music list, added ranking API, and began work on Team Courses (need help) 2023-10-20 03:26:51 +00:00
EmmyHeart 719ae9cfb1 Added checks for if Aime card is locked or banned, and pass that status to the game 2023-10-20 03:25:12 +00:00
EmmyHeart 8fcd227b33 Added functions for checking if Aime card is locked or banned 2023-10-20 03:24:25 +00:00
Dniel97 b5e3bf6f80 IDAC: Hotfix for UTF-8 encoding 2023-10-19 19:04:06 +02:00
Dniel97 81f7106264 IDAC: avatar gacha updated (HUGE PAIN), config fixes 2023-10-19 18:52:10 +02:00
Midorica 54c77c047e fixing duplicated is_cab value from machine table 2023-10-18 18:44:03 -04:00
Midorica 93b8b86b55 Adding base handler & config for HTTPS title support 2023-10-17 13:12:08 -04:00
Midorica eaa2652647 Merge pull request 'Chunithm Fixes and Maintenance for all!' (#46) from EmmyHeart/artemis:develop into develop
Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/46
2023-10-17 17:00:08 +00:00
Midorica 46f83b9925 Merge pull request 'maimai DX FESTiVAL PLUS support' (#44) from Dniel97/artemis:mai2_festival_plus into develop
Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/44
2023-10-16 20:00:08 +00:00
Dniel97 862907b82a mai2: Fixed cards not showing up 2023-10-16 21:36:26 +02:00
EmmyHeart 8c114532e8 Updated config documentation with IP enforcement and reboot times 2023-10-16 13:30:10 +00:00
EmmyHeart 300cd10abf Updated example config with reboot time
You can leave this option out to disable reboot times, and the games will use the prior mechanism of maintenance always being 4~ hours before current time
2023-10-16 13:23:56 +00:00
EmmyHeart 4f0a5f60ab Added config for reboot time support 2023-10-16 13:22:18 +00:00
EmmyHeart 9cff321857 Added reboot time support 2023-10-16 13:21:07 +00:00
EmmyHeart 8d289ca066 Added reboot time support 2023-10-16 13:20:37 +00:00
EmmyHeart e18b87ee5c Added reboot time support 2023-10-16 13:20:00 +00:00
EmmyHeart 540d7fc2c2 Added reboot time support 2023-10-16 13:18:23 +00:00
EmmyHeart 3ef40fe85e Removed Team Rank Scaling and fixed RIval Music Data. Also cleaned up extraneous functions 2023-10-16 13:15:39 +00:00
EmmyHeart 35a7525f74 Removed extraneous function 2023-10-16 13:14:11 +00:00
EmmyHeart d49997f832 Team Rank Scaling is dead, long live Team Rank Scaling 2023-10-16 13:09:53 +00:00
EmmyHeart c78a62de14 Fixed Rival Music retrieval 2023-10-16 13:09:11 +00:00
EmmyHeart 480551f942 Fixed logic error leading to strict IP checking always being enabled 2023-10-16 13:07:05 +00:00
Dniel97 d6e4db48f4 Added maimai DX FESTiVAL PLUS support
- Added Card Maker support for FESTiVAL PLUS
- Bumped SDEZ database to version 8
- Updated docs for FESTiVAL PLUS
2023-10-15 19:04:15 +02:00
Dniel97 346b74e51b Merge branch 'develop' into fork_develop 2023-10-15 18:06:07 +02:00
Midorica aa9d48ccc9 fixed the diva profile again 2023-10-10 18:37:18 -04:00
Midorica dc02d60690 Merge branch 'develop' of https://gitea.tendokyu.moe/Hay1tsme/artemis into develop 2023-10-10 18:25:01 -04:00
Midorica 6d592dcbc7 fixing skin issue with diva profile 2023-10-10 18:24:54 -04:00
Dniel97 3ee1801ee6 IDAC: Hotfix for play stamp and time trials 2023-10-10 17:58:20 +02:00
Dniel97 31188ccce6 IDAC: Hotfix to block amdaemon_emu users without correct access code 2023-10-10 16:06:58 +02:00
Midorica ab10f27cb4 Merge pull request 'Fixed typo with game_cfg/game_config' (#42) from EmmyHeart/artemis:develop into develop
Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/42
2023-10-09 12:38:46 +00:00
EmmyHeart 0a12e93593 news_msg config option doesn't actually return anything. Fixed! 2023-10-09 06:47:55 +00:00
EmmyHeart bad106ceba Fixed typo with game_cfg/game_config
This resulted in an exception on Plost and earlier, leading to games not actually working.
2023-10-09 06:35:14 +00:00
Midorica 7fc5544c15 adding a SAO note to documentation 2023-10-08 15:52:41 -04:00
Dniel97 d55ada2538 IDAC: Improvements
- Fixed play stamp event name not shown
- Fixed broken cars such as: LEVIN SR (AE85), SKYLINE 25GT TURBO (ER34), S2000 (AP1), GR SUPRA (DB42), SWIFT Sport (ZC33S), LANCER RS EVOLUTION Ⅴ (CP9A), LANCER GSR EVOLUTION Ⅵ TMEDITION (CP9A)
- Fixed bunta/special mode not properly updating
- Fixed frontend (for real this time)
2023-10-08 19:56:04 +02:00
Midorica bfaadff9f6 pushing news support customization for chunithm 2023-10-07 12:31:08 -04:00
Midorica 1996f3f356 fix for chunithm song loading after 600 scores 2023-10-07 12:11:24 -04:00
Midorica 56ddd3b1cc fix yet again to the md file 2023-10-07 12:07:14 -04:00
Midorica 41fcadfd55 quick fix to markdown file 2023-10-07 12:04:33 -04:00
Midorica 06d95c8c5f Adding details under the game specific info doc 2023-10-07 11:59:01 -04:00
Kevin Trocolli b5ccd67940 db: add memcache toggle 2023-10-05 22:16:50 -04:00
Midorica 1f65cfd2eb Merge pull request 'Added Team and Rival support to Chunithm' (#24) from EmmyHeart/artemis:develop into develop
Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/24
2023-10-06 01:48:50 +00:00
EmmyHeart 9681f86e33 Chunithm SQL documentation
Figured I would outline all of the neat SQL tricks you can do with this build, as well as properly document the features.
2023-10-05 07:56:46 +00:00
Dniel97 8ccb7f08f2 IDAC: Fixed frontend user_id not found 2023-10-03 17:00:59 +02:00
Dniel97 0e664e03f9 IDAC: Updated docs, added TA Data
Known issue: after selecting Season 1, the TA Data for Season 2 will not be shown
2023-10-03 16:50:52 +02:00
Hay1tsme d641705273 pokken: fix last_play_event_id 2023-10-02 15:12:29 -04:00
Kevin Trocolli 3d13eb1698 pokken: add coalesce 2023-10-01 23:49:47 -04:00
Kevin Trocolli 33e0288e5e pokken: pokemon data save/load 2023-10-01 22:38:56 -04:00
Dniel97 ee5f13a3bb IDAC: Added changelog, fixed doc 2023-10-01 22:29:50 +02:00
Dniel97 4ba01cdf20 IDAC: Fixed time trial events config, added new events 2023-10-01 22:17:06 +02:00
Dniel97 7033234b23 IDAC: Added better doc, fixed timetrial event 2023-10-01 21:41:08 +02:00
Dniel97 e0265485ff Initial D THE ARCADE S2 support added 2023-10-01 03:54:23 +02:00
Dniel97 38c1c31cf5 Merge branch 'develop' into fork_develop 2023-09-25 22:48:53 +02:00
Midorica 91791813dc Merge pull request 'ONGEKI Rival Functionality' (#36) from 2TT/artemis:develop into develop
Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/36
2023-09-23 16:08:15 +00:00
Kevin Trocolli 1497bf4a95 frontend: fixes to searching 2023-09-19 02:42:13 -04:00
Kevin Trocolli aa17f99252 frontend: add placeholders, arcade search by IP 2023-09-19 02:31:29 -04:00
Kevin Trocolli 50de0916d4 allnet: minor tweeks to mirrior realnet better 2023-09-19 02:15:22 -04:00
Midorica 2affd0aae9 Merge pull request 'Fix wrong id being used to check for Chunithm WORLD'S END charts' (#33) from ASleepyCat/artemis:fix-worlds-end-id into develop
Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/33
2023-09-12 04:36:59 +00:00
ASleepyCat 4a916cb4d1 Fix reading WORLD'S END charts for SDBT 2023-09-10 12:29:19 +10:00
ASleepyCat 6c98f5f0a7 Fix wrong id being used to check for WORLD'S END charts 2023-09-10 12:29:19 +10:00
Midorica 090b3148d8 adding encryption support for ongeki 2023-09-09 12:03:42 -04:00
Wanich Keatkajonjumroen ed46ea33e3 Added version select in session, removed get_profile_data_ignore_version, renamed scripts file 2023-09-09 06:55:18 +09:00
Dniel97 08927db100 Merge branch 'develop' into fork_develop 2023-09-07 15:09:36 +02:00
Kevin Trocolli 238e39f415 adb: properly handle an incorrect adb status value 2023-09-06 22:47:37 -04:00
Hay1tsme 5499d38bb4 mucha: streamline mucha_postprocess (thanks Bottersnike!) 2023-09-05 17:32:51 -04:00
2TT d584b93ca5 Merge branch 'develop' into develop 2023-09-02 06:39:37 +00:00
Wanich Keatkajonjumroen d5d2803cc0 forgot a print command, see previous commit 2023-09-02 07:50:09 +09:00
Wanich Keatkajonjumroen 16d801aff5 Rival Delete functionality 2023-09-02 07:40:57 +09:00
Wanich Keatkajonjumroen 147d7adaaf Frontend for adding rivals, versionless backend function to support 2023-09-02 06:21:02 +09:00
Wanich Keatkajonjumroen 1f545aed41 removed print statements 2023-09-02 05:04:59 +09:00
Kevin Trocolli 3a6cfedcca maimai: fix net deliver paths 2023-08-31 01:24:41 -04:00
Hay1tsme 7a6272dcc5 Merge branch 'develop' of https://gitea.tendokyu.moe/Hay1tsme/artemis into develop 2023-08-30 11:19:14 -04:00
Hay1tsme 136e47d1e6 reader: series -> game 2023-08-30 11:19:13 -04:00
Wanich Keatkajonjumroen eaf9e0cf09 removed temp file 2023-08-30 13:53:55 +09:00
Wanich Keatkajonjumroen 0d7409906a fixed backend ongeki rival functionality 2023-08-30 13:53:45 +09:00
Wanich Keatkajonjumroen 5cccc9224a geki version display 2023-08-30 13:53:41 +09:00
Wanich Keatkajonjumroen 2a52e391d6 Ongeki template start 2023-08-30 13:53:31 +09:00
Kevin Trocolli dac655b4ae adb: add catch for uninitialized amlib requests 2023-08-27 19:18:22 -04:00
Kevin Trocolli 37e2da2051 maimai: fix usbdl endpoints 2023-08-27 11:53:29 -04:00
Dniel97 9d74d60c14 Merge remote-tracking branch 'origin/develop' into fork_develop 2023-08-21 10:33:25 +02:00
Kevin Trocolli d4ea3bc12a billing: float5 hotfix 2023-08-21 01:53:27 -04:00
Kevin Trocolli d8b0e2ea2a billing: add classes and validation, fix response 2023-08-21 01:50:59 -04:00
Kevin Trocolli 984949d902 allnet: partial DFI implementation 2023-08-21 00:10:25 -04:00
Kevin Trocolli 2e8d99e5fa allnet: add ip check config option 2023-08-20 23:25:50 -04:00
Kevin Trocolli fd6cadf2da adb: hotfix 2023-08-20 19:56:16 -04:00
Kevin Trocolli 71489c1272 adb: fix log_ex 2023-08-20 19:55:26 -04:00
Dniel97 3773c57de1 Merge remote-tracking branch 'origin/develop' into fork_develop 2023-08-20 14:22:58 +02:00
Kevin Trocolli 8ea82ffe1a adb: add from_req 2023-08-19 01:35:37 -04:00
Kevin Trocolli 904ea10920 cm: remove print, fix default config 2023-08-19 01:35:15 -04:00
Dniel97 8a8c0e023e Merge branch 'develop' into fork_develop 2023-08-16 11:02:22 +02:00
Kevin Trocolli cf7cc0997a mucha: add other request/response structures 2023-08-15 23:19:48 -04:00
Hay1tsme 92567504f4 adb: fix for felica_lookup_ex, for #32 2023-08-15 10:43:49 -04:00
Hay1tsme fd50a7ee68 aimedb_redux (#30)
Update AimeDB from new [documentation](https://minori.tendokyu.moe/docs/allnet/aimedb/) of the protocol.
Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/30
2023-08-14 03:32:03 +00:00
Hay1tsme 9e3a51a57a allnet: add IP checking 2023-08-08 12:35:38 -04:00
Hay1tsme 4744e8cf5f add ip checking config options 2023-08-08 10:24:28 -04:00
Hay1tsme 88a1462304 logger: change from warn to warning 2023-08-08 10:17:56 -04:00
Hay1tsme 2e277e7791 add arcade ip column 2023-08-08 10:17:38 -04:00
Kevin Trocolli 757fdc5c57 mai2: add check for Mai-Encoding headers 2023-08-01 02:34:40 -04:00
Kevin Trocolli 23bcb5cc13 Merge branch 'develop' of https://gitea.tendokyu.moe/Hay1tsme/artemis into develop 2023-07-25 09:18:47 -04:00
Kevin Trocolli 9f0c181593 add handler for /mucha_front in addition to /mucha 2023-07-25 09:18:45 -04:00
Midorica 5a4baba102 Diva: Adding threading to score loading 2023-07-24 13:19:54 -04:00
Kevin Trocolli fc947d36a5 mai2: fix get user music for dx and up 2023-07-24 01:32:56 -04:00
Kevin Trocolli 156b4e4ede mai2: fix get user music for dx and up 2023-07-24 00:49:08 -04:00
Kevin Trocolli 6c89a97fe3 frontend: add management pages 2023-07-23 22:21:49 -04:00
Kevin Trocolli b943807904 core: add columns to machine table, bump to v5 2023-07-23 22:21:41 -04:00
Kevin Trocolli f417be671b pokken: fix typo 2023-07-23 12:47:37 -04:00
Kevin Trocolli 20335aaebe add download report api 2023-07-23 12:47:10 -04:00
Dniel97 097181008b Merge remote-tracking branch 'origin/develop' into fork_develop 2023-07-16 23:41:38 +02:00
Kevin Trocolli 5f586379ca Merge branch 'develop' 2023-07-16 17:25:18 -04:00
Kevin Trocolli 63d81a2704 changelog: fix typos 2023-07-16 17:24:07 -04:00
Kevin Trocolli 718229b267 Update changelog 2023-07-16 17:21:45 -04:00
Kevin Trocolli 7c78975431 mai2: update example config 2023-07-16 17:00:52 -04:00
Kevin Trocolli 14a315a673 replace except with except Exception 2023-07-16 16:58:34 -04:00
Kevin Trocolli 343fe4357c mai2: add image validation via Pillow 2023-07-16 16:58:18 -04:00
Kevin Trocolli d0e43140ba mai2: fix ghost saving, add memorial photo upload 2023-07-16 16:06:34 -04:00
Dniel97 859bf4bf5d Merge remote-tracking branch 'origin/develop' into fork_develop 2023-07-16 19:07:56 +02:00
Midorica c6e7100f51 Merge pull request 'O.N.G.E.K.I.: Card Maker fixes, improvements and bug fixes' (#25) from Dniel97/artemis:cardmaker_ongeki_fix into develop
Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/25
2023-07-16 17:06:44 +00:00
Midorica b0ca37815b Merge pull request 'maimai DX: Fixes' (#27) from Dniel97/artemis:mai2_fixes into develop
Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/27
2023-07-16 17:00:32 +00:00
Dniel97 f39317301b mai2: fixed update script, added mai2 heredity, fixed cards import 2023-07-15 22:51:54 +02:00
Dniel97 389784ce82 Merge remote-tracking branch 'origin/develop' into fork_develop 2023-07-15 22:47:05 +02:00
Kevin Trocolli 2f13596885 fix db ignoring port in config, createing database no longer runs over version 2023-07-15 00:15:14 -04:00
Dniel97 6a41dac46c ongeki: card maker config added, small fixes, improved credits
- Changed the credits config to the default 370 instead of 360
- Added `start_date` to the events to show new events
- Fixed Card Maker Gachas to only allow "Select Gacha" once
- Fixed the `get_profile_rating_log` database query
2023-07-12 11:25:46 +02:00
Kevin Trocolli 85b73e634d mucha: add DownloadState 2023-07-12 00:41:53 -04:00
EmmyHeart 3c7ceabf4e And again 2023-07-11 10:04:25 +00:00
EmmyHeart 1bc8648e35 I knew I forgot something (fixed config) 2023-07-11 09:56:09 +00:00
EmmyHeart eecd3a829d Added value for team rank scaling, and documented it a bit 2023-07-11 09:40:49 +00:00
EmmyHeart b42e8ab76c Added function for pulling a song via the DB unique ID instead of the native song ID 2023-07-11 09:16:11 +00:00
EmmyHeart 043ff17008 Add team support, rivals, and test function for getting playcounts 2023-07-11 09:14:53 +00:00
EmmyHeart c01d3f49f5 Added call for getting rival's music lists 2023-07-11 09:13:19 +00:00
EmmyHeart 75842b5a88 Add team support, implement team upsert, add rivals 2023-07-11 09:12:34 +00:00
Midorica 09c4f8cda4 Async request to CXB profile loading 2023-07-08 18:44:02 -04:00
Dniel97 36d338e618 Merge remote-tracking branch 'origin/develop' into fork_develop 2023-07-08 17:38:41 +02:00
Kevin Trocolli 03cf535ff6 make threading optional 2023-07-08 00:34:55 -04:00
Kevin Trocolli 6c155a5e48 database: add static variables to prevent having multiple sessions 2023-07-08 00:01:52 -04:00
Midorica 737312ca3d Threading support to main twisted reactor 2023-07-07 21:50:24 -04:00
Hay1tsme 1edec7dba2 sao: add response debug logging 2023-07-05 12:35:00 -04:00
Hay1tsme d60f827000 fix typing across multiple games, fixes #23 2023-07-05 10:47:43 -04:00
Midorica da422e602b fixing trial_tower_play_end_unanalyzed_log_fixed for SAO 2023-07-02 15:50:42 -04:00
Midorica d276ac8598 Merge branch 'develop' of https://gitea.tendokyu.moe/Hay1tsme/artemis into develop 2023-07-02 14:25:36 -04:00
Midorica 84e880e94f fixing unanalyzed reward request for SAO 2023-07-02 14:25:24 -04:00
Kevin Trocolli 432177957a pokken: save most profile data 2023-07-02 02:42:49 -04:00
Kevin Trocolli a89247cdd6 wacca: add note about VIP rewards 2023-07-02 02:33:45 -04:00
Kevin Trocolli f279adb894 mai2: add consecutive day login count, update db to v7, fix reader, courses, and docs 2023-07-01 21:51:18 -04:00
Kevin Trocolli a680699939 Merge branch 'finale' into develop 2023-07-01 02:59:12 -04:00
Kevin Trocolli d204954447 mai2: add missing finale endpoints 2023-07-01 02:40:07 -04:00
Kevin Trocolli 042440c76e mai2: fix handle_get_user_preview_api_request 2023-07-01 02:27:26 -04:00
Kevin Trocolli c4c0566cd5 mai2: fix userWebOption 2023-07-01 02:19:19 -04:00
Kevin Trocolli 3e9cec3a20 mai2: put_recent_rating final fix 2023-07-01 02:11:37 -04:00
Kevin Trocolli 8f9584c3d2 mai2: hotfix put_recent_rating 2023-07-01 02:07:19 -04:00
Kevin Trocolli b29cb0fbaa mai2: fix put_recent_rating 2023-07-01 02:06:00 -04:00
Kevin Trocolli d9a92f5865 mai2: 4th round of fixes 2023-07-01 02:04:30 -04:00
Kevin Trocolli 9859ab4fdb mai2: fix playlog saving 2023-07-01 01:59:19 -04:00
Kevin Trocolli d89eb61e62 mai2: fixes round 3 2023-07-01 01:56:52 -04:00
Kevin Trocolli dc8c27046e mai2: more finale fixes 2023-07-01 01:42:38 -04:00
Kevin Trocolli 3e461f4d71 mai2: finale fixes 2023-07-01 01:41:34 -04:00
Kevin Trocolli 2c6902a546 mai2: fix typos 2023-07-01 01:12:15 -04:00
Kevin Trocolli 318b73dd57 finale: finish porting request data from aqua 2023-07-01 01:08:54 -04:00
Kevin Trocolli 9d33091bb8 allnet: use parse_qsl 2023-06-30 01:34:46 -04:00
Kevin Trocolli 8b43d554fc allnet: make use of urllib.parse where applicable 2023-06-30 01:19:17 -04:00
Kevin Trocolli 610ef70bad allnet: add Alive get and post handlers 2023-06-30 00:32:52 -04:00
Kevin Trocolli 60b3bc7750 Merge branch 'develop' of https://gitea.tendokyu.moe/Hay1tsme/artemis into develop 2023-06-30 00:26:10 -04:00
Kevin Trocolli 4ea83f6025 allnet: add handler for LoaderStateRecorder 2023-06-30 00:26:07 -04:00
Midorica 20389011e9 Adding proper hero unlock after stage clear on SAO 2023-06-28 12:54:16 -04:00
Midorica e446816b9a fixing issue where SaoItemData was not working 2023-06-28 08:24:53 -04:00
Midorica 9dd2b4d524 Adding dummy hero QR code scanning for SAO 2023-06-28 00:18:02 -04:00
Midorica b60cf6258d Dummy defrag match handler for SAO 2023-06-27 21:32:46 -04:00
Kevin Trocolli 127e6f8aa8 mai2: add finale databases 2023-06-27 00:32:35 -04:00
Midorica 5155353360 fixing chapter progression after chapter 2 on SAO 2023-06-26 19:30:03 -04:00
Kevin Trocolli e3d38dacde mai2: fix movies 2023-06-25 19:10:34 -04:00
Kevin Trocolli 0c6d9a36ce mai2: add movie server endpoints 2023-06-25 18:43:00 -04:00
Kevin Trocolli b1968fe320 Merge branch 'develop' into finale 2023-06-25 18:35:12 -04:00
Midorica 03f91d18c9 fixing hero party saving for SAO 2023-06-25 14:40:34 -04:00
Midorica 17508f09b2 fixed episode VP saving & hero level in DB for SAO 2023-06-25 13:47:31 -04:00
Midorica aae4afe7b8 Adding debug logging to SAO 2023-06-25 11:59:17 -04:00
Kevin Trocolli 514f786e2d pokken: Switch to using external STUN server 2023-06-25 01:09:23 -04:00
Midorica ec9ad1ebb0 fixing stage progression for SAO 2023-06-25 00:08:50 -04:00
Midorica 08ebb5c907 another quick fix for SAO tower stage 2023-06-24 20:42:00 -04:00
Midorica 571b92d0cd forgot one line, see previous commit 2023-06-24 20:33:30 -04:00
Midorica 01b5282899 small fix about next tower stage progression for SAO 2023-06-24 20:31:14 -04:00
Midorica 391edd3354 Tower progression now working for SAO 2023-06-24 20:09:37 -04:00
Midorica d5bff0e891 Stage progression done for SAO 2023-06-24 18:48:48 -04:00
Kevin Trocolli 402e753469 wacca: fix tabbing error in util_put_items 2023-06-24 15:09:38 -04:00
Kevin Trocolli 154ccbdae5 Merge branch 'develop' of https://gitea.tendokyu.moe/Hay1tsme/artemis into develop 2023-06-24 13:14:42 -04:00
Kevin Trocolli 858b101a36 dbutils: add command to show versions 2023-06-24 13:14:40 -04:00
Midorica 1d10e798a5 Fixed few issues for SAO & removed static hex ranges 2023-06-24 12:29:28 -04:00
Kevin Trocolli 3c385f505b pokken: add requirement for autobahn, add stun, turn and admission servers 2023-06-23 00:30:25 -04:00
Kevin Trocolli b12938bcd8 pokken: add partial profile save logic 2023-06-14 03:00:52 -04:00
Kevin Trocolli 1b2f5e3709 mai2: fix logic in handle_get_user_music_api_request 2023-06-13 22:50:57 -04:00
Kevin Trocolli 65686fb615 mai2: add loggin to handle_get_user_music_api_request 2023-06-13 22:35:09 -04:00
Kevin Trocolli f56332141e mai2: fix old server (finale isn't ready yet) 2023-06-13 22:16:30 -04:00
Kevin Trocolli 5a35b1c823 mai2: GetUserMusicApi hotfix 2023-06-13 22:10:35 -04:00
Kevin Trocolli 5ca16f2067 mai2: fix GetUserMusicApi pagination 2023-06-13 22:07:48 -04:00
Midorica a0b25e2b7b Adding rare drops saving to SAO 2023-06-03 11:42:50 -04:00
Midorica 84fc002cdb Adding trial tower support for SAO 2023-06-02 13:53:49 -04:00
Midorica 3bd03c592e Item progression and synthesize of hero and equipment done 2023-06-01 13:19:48 -04:00
Midorica cf6cfdbd3b adding partial synthetize system for SAO 2023-05-31 21:58:30 -04:00
Kevin Trocolli db77e61b79 allnet: add event logging 2023-05-30 21:52:21 -04:00
Kevin Trocolli ac9e71ee2f hotfix allnet logging 2023-05-30 21:46:26 -04:00
Kevin Trocolli 20865dc495 allnet: add logging 2023-05-30 21:45:37 -04:00
Kevin Trocolli 37d24b3b4d mucha: now respects log level set in core.yaml 2023-05-30 21:32:27 -04:00
Kevin Trocolli 2418abacce title: convert version to int to match POST endpoint 2023-05-30 21:31:09 -04:00
Kevin Trocolli 5c3f812caf cxb: fix missing parameters on render_POST 2023-05-30 21:30:34 -04:00
Midorica 4854bcfcad Merge pull request 'Added individual Card Maker versions and maimai DX card/passes working' (#21) from Dniel97/artemis:cardmaker_maimai into develop
Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/21
2023-05-30 23:59:44 +00:00
Midorica bf6d126f8a Equipments saving for SAO now completed 2023-05-30 18:03:52 -04:00
Midorica e466ddce55 Adding SAO rewards saving for heroes 2023-05-30 14:29:50 -04:00
Dniel97 ad820ed091 cm: Added individual Card Maker version and maimai DX passes working 2023-05-30 12:14:18 +02:00
Dniel97 960a0e3fd9 Merge branch 'develop' into fork_develop 2023-05-30 12:08:36 +02:00
Midorica a2fe11d654 Fixing level calculation saving & loading on SAO 2023-05-29 20:57:02 -04:00
Midorica 2b4ac06389 adding more profile & hero saving stuff to SAO 2023-05-29 19:21:26 -04:00
Midorica d8af7be4a4 Adding SAO item table and adding party saving 2023-05-29 16:51:41 -04:00
Midorica 84cb786bde Adding some structs for SAO for later use 2023-05-29 11:10:32 -04:00
Kevin Trocolli 05dee87a9a allnet: update default values, add debug log for unknown but allowed auths 2023-05-26 21:41:16 -04:00
Midorica 049dc40a8b small typo of the documentation 2023-05-26 14:04:49 -04:00
Midorica cab1d6814a added game specifics for SAO 2023-05-26 13:57:16 -04:00
Midorica 72594fef31 adding partial Sword Art Online Arcade support 2023-05-26 13:45:20 -04:00
Kevin Trocolli 7ed294e9f7 delivery: remove period from version 2023-05-24 01:08:53 -04:00
Hay1tsme b9fd4f294d wacca: fix type mismatch in user/music/unlock 2023-05-22 12:33:43 -04:00
Hay1tsme 5ddfb88182 wacca: fix user/music/unlock error when using tickets. 2023-05-22 12:24:16 -04:00
Hay1tsme 4da8622977 frontend: user page fixes, add card display 2023-05-20 15:32:02 -04:00
Kevin Trocolli 97892d6a7d idz: try-catch for userdb request decryption 2023-05-18 21:20:28 -04:00
Kevin Trocolli 02078080a8 index: additional logging for malformed return data 2023-05-12 22:12:03 -04:00
Kevin Trocolli 61e3a2c930 index: remove hanging debug log call 2023-05-12 22:06:19 -04:00
Kevin Trocolli 8ae0aba89c mai2: update default config 2023-05-12 22:05:05 -04:00
Kevin Trocolli 49166c1a7b mai2: fix handle_get_game_setting_api_request 2023-05-11 09:52:18 -04:00
Midorica 013e83420b Merge pull request 'CHUNITHM SUN support (with basic matchmaking)' (#20) from Dniel97/artemis:chuni_sun into develop
Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/20
2023-05-11 13:44:30 +00:00
Dniel97 0dce7e7849 docs: fixed opt typo 2023-05-11 15:33:29 +02:00
Raymonf f959236af0 SUN encryption support 2023-05-10 17:20:13 -04:00
Dniel97 b85a65204f chuni: added SUN support, matchmaking, fixed bugs, added docs
- Added CHUNITHM SUN support
- Added first matchmaking support with CPU spawning and messages
- Fixed wrong `next_idx` calculations
- Added `startDate` to events to spawn the correct items
- Fixed login bonus per version
- Added information to docs
2023-05-10 21:32:35 +02:00
Dniel97 0ab539173a Merge branch 'develop' into fork_develop 2023-05-10 12:49:01 +02:00
Kevin Trocolli 42ed222095 mai2: add gamesetting urls 2023-05-10 02:31:30 -04:00
Kevin Trocolli d172e5582b fixup allnet response for res class 2 2023-05-09 03:53:31 -04:00
Kevin Trocolli 9766e3ab78 mai2: hardcode reboot time 2023-05-07 02:16:50 -04:00
Kevin Trocolli b34b441ba8 mai2: reimplement pre-dx versions 2023-05-06 19:04:10 -04:00
Kevin Trocolli 8149f09a40 mai2: stub music reader 2023-05-05 00:37:05 -04:00
Kevin Trocolli cad523dfce mai2: add patch reader 2023-05-05 00:36:07 -04:00
Kevin Trocolli 8b9771b5af mai2: implement event reader for pre-dx games 2023-05-05 00:24:47 -04:00
Kevin Trocolli 989c080657 mai2: further documentation clarification 2023-05-04 20:25:14 -04:00
Kevin Trocolli dcff8adbab mai2: update documentation 2023-05-04 20:22:41 -04:00
Kevin Trocolli e3b1addce6 mai2: fix up version comments 2023-05-04 20:12:31 -04:00
Kevin Trocolli b6f43d887a Merge branch 'develop' into finale 2023-05-04 20:12:02 -04:00
Kevin Trocolli efd8f86e48 re-add docker files for #19 2023-05-04 09:46:16 -04:00
Kevin Trocolli d0242b456d mai2: fix for dx 1.00 2023-05-03 22:29:08 -04:00
Kevin Trocolli 7bb8c2c80c billing: handle malformed requests 2023-05-03 03:26:39 -04:00
Kevin Trocolli 6d1855a6bc billing: handle malformed requests 2023-05-03 03:25:55 -04:00
Kevin Trocolli 8d94d25893 mai2: add version seperators 2023-05-03 03:25:29 -04:00
Kevin Trocolli ae6dcb68df Merge branch 'develop' into finale 2023-05-02 23:56:10 -04:00
Kevin Trocolli 3b6fc6618c fix naomitest 2023-05-02 23:55:57 -04:00
Kevin Trocolli deeac1d8db add finale handler, pre-dx game codes 2023-04-30 22:19:31 -04:00
Midorica 6ad5194bb8 Merge pull request 'Project Diva Arcade: Added Clear Status calculation + small improvements' (#18) from Dniel97/artemis:diva_clear_set into develop
Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/18
2023-04-30 23:18:19 +00:00
Dniel97 a0793aa13a diva: added clear set calculation + small improvements 2023-04-30 23:31:13 +02:00
Dniel97 7364181de1 Merge branch 'develop' into fork_develop 2023-04-30 20:39:35 +02:00
Hay1tsme 9d8762d3da Update 'readme.md' 2023-04-29 21:18:28 -04:00
Hay1tsme fe4dfe369b Update 'readme.md' 2023-04-30 01:18:00 +00:00
Kevin Trocolli 02040300b8 Merge branch 'develop' 2023-04-23 21:05:25 -04:00
Kevin Trocolli 238d437519 reformat with black in preperation for merge to master 2023-04-23 21:04:52 -04:00
Kevin Trocolli 9d23d59e43 add changelog 2023-04-23 21:04:15 -04:00
Kevin Trocolli f4ee4238d9 update readme 2023-04-23 20:51:23 -04:00
Kevin Trocolli b498e82bf8 dli: remove dot from version 2023-04-23 19:08:45 -04:00
Kevin Trocolli 0668488ccf update core example config 2023-04-23 19:06:44 -04:00
Kevin Trocolli 47f4aaddf8 allnet: add download order infrastructure 2023-04-23 19:00:30 -04:00
Kevin Trocolli 26c4bcb466 idz: Add requests, fix load_config_b 2023-04-23 13:26:44 -04:00
Kevin Trocolli d8c3ed5c01 Add support for initial d zero 2023-04-23 04:38:28 -04:00
Hay1tsme 58a088b9a4 wacca: add debug log for ticket use 2023-04-21 10:51:44 -04:00
Hay1tsme 190c41e03e wacca: added play mode counter for time free 2023-04-21 10:51:30 -04:00
Kevin Trocolli a30967e8d7 wacca: fix time free not saving, add counter to profile table 2023-04-20 09:46:18 -04:00
Kevin Trocolli 00b127361b wacca: enable time play 2023-04-20 02:27:09 -04:00
Kevin Trocolli 241f29e29c wacca: add a comment 2023-04-20 02:02:42 -04:00
Kevin Trocolli 4d6afd757f wacca: add helpers for gacha, event and friend info, fix settings not being applied correctly 2023-04-20 00:54:16 -04:00
Hay1tsme 68b0894e47 wacca: fix first play of the day calculation 2023-04-19 16:12:35 -04:00
Midorica 017ef1e224 Merge pull request 'maimai DX FESTiVAL support' (#17) from Dniel97/artemis:maimai_dx_festival into develop
Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/17
2023-04-19 18:13:31 +00:00
Hay1tsme 15433b681c mai2: fix logging in put_card 2023-04-19 11:26:33 -04:00
Hay1tsme b0042bc776 docs: update in accordance with new dbutils 2023-04-19 10:50:40 -04:00
Kevin Trocolli 469ead7a84 wacca: add previously disabled gates, for #15 2023-04-18 02:52:41 -04:00
Kevin Trocolli 0dc96f33e1 database: don't set schema version if autoupdate fails 2023-04-15 03:13:14 -04:00
Kevin Trocolli 4102ba21fc database: remove print 2023-04-15 03:07:15 -04:00
Kevin Trocolli 83d2151b6b dbutils: fix config loading incorrectly 2023-04-15 03:06:11 -04:00
Kevin Trocolli 9895068125 database: fix autoupdate 2023-04-15 01:31:52 -04:00
Kevin Trocolli 4419310086 fix schema versions for diva and ongeki 2023-04-15 01:31:40 -04:00
Kevin Trocolli a416fb09e1 dbutils: version can now be left black to auto-upgrade to latest 2023-04-15 00:13:04 -04:00
Kevin Trocolli baa885f674 Utils: exclude malformed game folders 2023-04-15 00:12:45 -04:00
Kevin Trocolli 0d5567c990 wacca: fix v4 upgrade scripts 2023-04-15 00:12:28 -04:00
Kevin Trocolli b1f9be0121 wacca: fix crash on 4th page of Reverse Gate, partially fixes #5 2023-04-14 23:47:31 -04:00
Kevin Trocolli dc3e3e1fb3 pokken: add constants, add stats to profile table 2023-04-14 02:51:28 -04:00
Kevin Trocolli 71c43a4a57 pokken: add_profile_points stub 2023-04-12 02:39:56 -04:00
Kevin Trocolli bd356af272 pokken: restructure database 2023-04-12 02:34:29 -04:00
Hay1tsme 68e25b9c5e pokken: add frontend stub 2023-04-11 11:40:05 -04:00
Kevin Trocolli 780a96ec15 Merge branch 'develop' 2023-03-19 23:33:01 -04:00
Kevin Trocolli b8b93a8d51 Merge branch 'develop' 2023-03-18 23:56:23 -04:00
Hay1tsme a0e24c6742 Merge branch 'develop' 2023-03-03 17:07:58 -05:00
Hay1tsme 90024ddbd9 Merge branch 'develop' 2023-03-03 13:19:55 -05:00
Hay1tsme be00ad8e96 wacca: add lily to list of items given on profile create, fixes #4 2023-03-01 23:55:29 -05:00
Hay1tsme e2129b45b7 Merge branch 'develop' 2023-03-01 23:41:42 -05:00
Hay1tsme 670747cf48 add platform_system to requirements.txt 2023-02-24 13:35:37 -05:00
Hay1tsme 83f09e180e add protobuf to requirements, fixes #2 2023-02-22 10:01:42 -05:00
Hay1tsme a83b717821 carry over database functions from megaime 2023-02-21 14:05:55 -05:00
400 changed files with 73524 additions and 5234 deletions
+3
View File
@@ -0,0 +1,3 @@
*.csv binary
*.txt binary
*.json binary
+1
View File
@@ -158,5 +158,6 @@ cert/*
!cert/server.pem
config/*
deliver/*
*.gz
dbdump-*.json
+21
View File
@@ -0,0 +1,21 @@
FROM python:3.9.15-slim-bullseye
RUN apt update && apt install default-libmysqlclient-dev build-essential libtk nodejs npm pkg-config -y
WORKDIR /app
COPY requirements.txt requirements.txt
RUN pip3 install -r requirements.txt
RUN npm i -g nodemon
COPY entrypoint.sh entrypoint.sh
RUN chmod +x entrypoint.sh
COPY index.py index.py
COPY dbutils.py dbutils.py
COPY read.py read.py
ADD core core
ADD titles titles
ADD logs logs
ADD cert cert
ENTRYPOINT [ "/app/entrypoint.sh" ]
+13
View File
@@ -0,0 +1,13 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.
+213
View File
@@ -0,0 +1,213 @@
# Changelog
Documenting updates to ARTEMiS, to be updated every time the master branch is pushed to.
## 20240302
### SAO
+ Fixing new profile creation with right heroes and start VP
+ Fix to the Unanalyzed Log responses returning the wrong rewards
+ Documentation revised
## 20240226
### CXB
+ Fixing paths for rev.py
+ Changed encoding for handle_data_item_list_icon_request
## 20240202
### SAO
+ Added reader assets and edited the game specific documentation
## 20240118
### System
+ Added game version names to the readme
## 20240109
### System
+ Removed `ADD config config` from dockerfile [#83](https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/83) (Thanks zaphkito!)
### Aimedb
+ Fixed an error that resulted from trying to scan a banned or locked card
## 20240108
### System
+ Change how the underlying system handles URLs
+ This can now allow for things like version-specific, or even keychip-specific URLs
+ Specific changes to games are noted below
+ Fix docker files [#60](https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/60) (Thanks Rylie!)
+ Fix support for python 3.8 - 3.10
### Aimedb
+ Add support for SegaAuth key in games that support it (for now only Chunithm)
+ This is a JWT that is sent to games, by Aimedb, that the games send to their game server, to verify that the access code the game is sending to the server was obtained via aimedb.
+ Requires a base64-encoded secret to be set in the `core.yaml`
### Chunithm
+ Fix Air support
+ Add saving for userRecentPlayerList
+ Add support for SegaAuthKey
+ Fix a bug arising if a user set their name to be 'true' or 'false'
+ Add support for Sun+ [#78](https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/78) (Thanks EmmyHeart!)
+ Add `matching` section to `chuni.yaml`
+ ~~Change `udpHolePunchUri` and `reflectorUri` to be STUN and TURN servers~~ Reverted
+ Imrpove `GetGameSetting` request handling for different versions
+ Fix issue where songs would not always return all scores [#92](https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/92) (Thanks Kumubou!)
### maimai DX
+ Fix user charges failing to save
### maimai
+ Made it functional
### CXB
+ Improvements to request dispatching
+ Add support for non-omnimix music lists
### IDZ
+ Fix news urls in accordance with the system change to URLs
### Initial D THE ARCADE
+ Added support for Initial D THE ARCADE S2
+ Story mode progress added
+ Bunta Challenge/Touhou Project modes added
+ Time Trials added
+ Leaderboards added, but doesn't refresh sometimes
+ Theory of Street mode added (with CPUs)
+ Play Stamp/Timetrial events added
+ Frontend to download profile added
+ Importer to import profiles added
### ONGEKI
+ Now supports HTTPS on a per-version basis
+ Merg PR [#61](https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/61) (Thanks phantomlan!)
+ Add Ranking Event Support
+ Add reward list support
+ Add version segregation to Event Ranking, Tech Challenge, and Music Ranking
+ Now stores ClientTestmode and ClientSetting data
+ Fix mission points not adding correctly [#68](https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/68) (Thanks phantomlan!)
+ Fix tech challenge [#70](https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/70) (Thanks phantomlan!)
### SAO
+ Change endpoint in accordance with the system change to URLs
+ Update request header class to be more accurate
+ Encrypted requests are now supported
+ Change to using handler classes instead of raw structs for simplicity
### Wacca
+ Fix a server error causing a seperate error that casued issues
+ Add better error printing
+ Add better request validation
+ Fix HousingStartV2
+ Fix Lily's housing/get handler
## 20231107
### CXB
+ Hotfix `render_POST` sometimes failing to read the request body on large requests
## 20231106
### CXB
+ Hotfix `render_POST` function signature signature
+ Hotfix `handle_action_addenergy_request` hard failing if `get_energy` returns None
## 20231015
### maimai DX
+ Added support for FESTiVAL PLUS
### Card Maker
+ Added support for maimai DX FESTiVAL PLUS
## 20230716
### General
+ Docker files added (#19)
+ Added support for threading
+ This comes with the caviat that enabling it will not allow you to use Ctrl + C to stop the server.
### Webui
+ Small improvements
+ Add card display
### Allnet
+ Billing format validation
+ Fix naomitest.html endpoint
+ Add event logging for auths and billing
+ LoaderStateRecorder endpoint handler added
### Mucha
+ Fixed log level always being "Info"
+ Add stub handler for DownloadState
### Sword Art Online
+ Support added
### Crossbeats
+ Added threading to profile loading
+ This should cause a noticeable speed-up
### Card Maker
+ DX Passes fixed
+ Various improvements
### Diva
+ Added clear status calculation
+ Various minor fixes and improvements
### Maimai
+ Added support for memorial photo uploads
+ Added support for the following versions
+ Festival
+ FiNALE
+ Various bug fixes and improvements
### Wacca
+ Fixed an error that sometimes occoured when trying to unlock songs (#22)
### Pokken
+ Profile saving added (loading TBA)
+ Use external STUN server for matching by default
+ Matching still not working
## 2023042300
### Wacca
+ Time free now works properly
+ Fix reverse gate mission causing a fatal error
+ Other misc. fixes
+ Latest DB: 5
### Pokken
+ Added preliminary support
+ Nothing saves currently, but the game will boot and function properly.
### Initial D Zero
+ Added preliminary support
+ Nothing saves currently, but the game will boot and function for the most part.
### Mai2
+ Added support for Festival
+ Lasted DB Version: 4
### Ongeki
+ Misc fixes
+ Lasted DB Version: 4
### Diva
+ Misc fixes
+ Lasted DB Version: 4
### Chuni
+ Fix network encryption
+ Add `handle_remove_token_api_request` for event mode
### Allnet
+ Added download order support
+ It is up to the sysop to provide the INI file, and host the files.
+ ONLY for use with cabs. It's not checked currently, which it's why it's default disabled
+ YMMV, use at your own risk
+ When running develop mode, games that are not recognised will still be able to authenticate.
### Database
+ Add autoupgrade command
+ Invoke to automatically upgrade all schemas to their latest versions
+ `version` arg no longer required, leave it blank to update the game schema to latest if it isn't already
### Misc
+ Update example nginx config file
+2 -2
View File
@@ -1,6 +1,6 @@
from core.config import CoreConfig
from core.allnet import AllnetServlet
from core.aimedb import AimedbFactory
from core.allnet import AllnetServlet, BillingServlet
from core.aimedb import AimedbServlette
from core.title import TitleServlet
from core.utils import Utils
from core.mucha import MuchaServlet
+6
View File
@@ -0,0 +1,6 @@
from .base import ADBBaseRequest, ADBBaseResponse, ADBHeader, ADBHeaderException, PortalRegStatus, LogStatus, ADBStatus
from .base import CompanyCodes, ReaderFwVer, CMD_CODE_GOODBYE, HEADER_SIZE
from .lookup import ADBLookupRequest, ADBLookupResponse, ADBLookupExResponse
from .campaign import ADBCampaignClearRequest, ADBCampaignClearResponse, ADBCampaignResponse, ADBOldCampaignRequest, ADBOldCampaignResponse
from .felica import ADBFelicaLookupRequest, ADBFelicaLookupResponse, ADBFelicaLookup2Request, ADBFelicaLookup2Response
from .log import ADBLogExRequest, ADBLogRequest, ADBStatusLogRequest, ADBLogExResponse
+170
View File
@@ -0,0 +1,170 @@
import struct
from construct import Struct, Int16ul, Int32ul, PaddedString
from enum import Enum
import re
from typing import Union, Final
class LogStatus(Enum):
NONE = 0
START = 1
CONTINUE = 2
END = 3
OTHER = 4
class PortalRegStatus(Enum):
NO_REG = 0
PORTAL = 1
SEGA_ID = 2
class ADBStatus(Enum):
UNKNOWN = 0
GOOD = 1
BAD_AMIE_ID = 2
ALREADY_REG = 3
BAN_SYS_USER = 4
BAN_SYS = 5
BAN_USER = 6
BAN_GEN = 7
LOCK_SYS_USER = 8
LOCK_SYS = 9
LOCK_USER = 10
class CompanyCodes(Enum):
NONE = 0
SEGA = 1
BAMCO = 2
KONAMI = 3
TAITO = 4
class ReaderFwVer(Enum): # Newer readers use a singly byte value
NONE = 0
TN32_10 = 1
TN32_12 = 2
OTHER = 9
def __str__(self) -> str:
if self == self.TN32_10:
return "TN32MSEC003S F/W Ver1.0"
elif self == self.TN32_12:
return "TN32MSEC003S F/W Ver1.2"
elif self == self.NONE:
return "Not Specified"
elif self == self.OTHER:
return "Unknown/Other"
else:
raise ValueError(f"Bad ReaderFwVer value {self.value}")
@classmethod
def from_byte(self, byte: bytes) -> Union["ReaderFwVer", int]:
try:
i = int.from_bytes(byte, 'little')
try:
return ReaderFwVer(i)
except ValueError:
return i
except TypeError:
return 0
class ADBHeaderException(Exception):
pass
HEADER_SIZE: Final[int] = 0x20
CMD_CODE_GOODBYE: Final[int] = 0x66
# everything is LE
class ADBHeader:
def __init__(self, magic: int, protocol_ver: int, cmd: int, length: int, status: int, game_id: Union[str, bytes], store_id: int, keychip_id: Union[str, bytes]) -> None:
self.magic = magic # u16
self.protocol_ver = protocol_ver # u16
self.cmd = cmd # u16
self.length = length # u16
try:
self.status = ADBStatus(status) # u16
except ValueError as e:
raise ADBHeaderException(f"Status is incorrect! {e}")
self.game_id = game_id # 4 char + \x00
self.store_id = store_id # u32
self.keychip_id = keychip_id# 11 char + \x00
if type(self.game_id) == bytes:
self.game_id = self.game_id.decode()
if type(self.keychip_id) == bytes:
self.keychip_id = self.keychip_id.decode()
self.game_id = self.game_id.replace("\0", "")
self.keychip_id = self.keychip_id.replace("\0", "")
if self.cmd != CMD_CODE_GOODBYE: # Games for some reason send no data with goodbye
self.validate()
@classmethod
def from_data(cls, data: bytes) -> "ADBHeader":
magic, protocol_ver, cmd, length, status, game_id, store_id, keychip_id = struct.unpack_from("<5H6sI12s", data)
head = cls(magic, protocol_ver, cmd, length, status, game_id, store_id, keychip_id)
if head.length > len(data):
raise ADBHeaderException(f"Length is incorrect! Expect {head.length}, got {len(data)}")
return head
def validate(self) -> bool:
if self.magic != 0xa13e:
raise ADBHeaderException(f"Magic {self.magic} != 0xa13e")
if self.protocol_ver < 0x1000:
raise ADBHeaderException(f"Protocol version {hex(self.protocol_ver)} is invalid!")
if re.fullmatch(r"^S[0-9A-Z]{3}[P]?$", self.game_id) is None:
raise ADBHeaderException(f"Game ID {self.game_id} is invalid!")
if self.store_id == 0:
raise ADBHeaderException(f"Store ID cannot be 0!")
if re.fullmatch(r"^A[0-9]{2}[E|X][0-9]{2}[A-HJ-NP-Z][0-9]{4}$", self.keychip_id) is None:
raise ADBHeaderException(f"Keychip ID {self.keychip_id} is invalid!")
return True
def make(self) -> bytes:
resp_struct = Struct(
"magic" / Int16ul,
"unknown" / Int16ul,
"response_code" / Int16ul,
"length" / Int16ul,
"status" / Int16ul,
"game_id" / PaddedString(6, 'utf_8'),
"store_id" / Int32ul,
"keychip_id" / PaddedString(12, 'utf_8'),
)
return resp_struct.build(dict(
magic=self.magic,
unknown=self.protocol_ver,
response_code=self.cmd,
length=self.length,
status=self.status.value,
game_id = self.game_id,
store_id = self.store_id,
keychip_id = self.keychip_id,
))
class ADBBaseRequest:
def __init__(self, data: bytes) -> None:
self.head = ADBHeader.from_data(data)
class ADBBaseResponse:
def __init__(self, code: int = 0, length: int = 0x20, status: int = 1, game_id: str = "SXXX", store_id: int = 1, keychip_id: str = "A69E01A8888", protocol_ver: int = 0x3087) -> None:
self.head = ADBHeader(0xa13e, protocol_ver, code, length, status, game_id, store_id, keychip_id)
@classmethod
def from_req(cls, req: ADBHeader, cmd: int, length: int = 0x20, status: int = 1) -> "ADBBaseResponse":
return cls(cmd, length, status, req.game_id, req.store_id, req.keychip_id, req.protocol_ver)
def append_padding(self, data: bytes):
"""Appends 0s to the end of the data until it's at the correct size"""
padding_size = self.head.length - len(data)
data += bytes(padding_size)
return data
def make(self) -> bytes:
return self.head.make()
+132
View File
@@ -0,0 +1,132 @@
from construct import Struct, Int16ul, Padding, Bytes, Int32ul, Int32sl
from .base import *
class Campaign:
def __init__(self) -> None:
self.id = 0
self.name = ""
self.announce_date = 0
self.start_date = 0
self.end_date = 0
self.distrib_start_date = 0
self.distrib_end_date = 0
def make(self) -> bytes:
name_padding = bytes(128 - len(self.name))
return Struct(
"id" / Int32ul,
"name" / Bytes(128),
"announce_date" / Int32ul,
"start_date" / Int32ul,
"end_date" / Int32ul,
"distrib_start_date" / Int32ul,
"distrib_end_date" / Int32ul,
Padding(8),
).build(dict(
id = self.id,
name = self.name.encode() + name_padding,
announce_date = self.announce_date,
start_date = self.start_date,
end_date = self.end_date,
distrib_start_date = self.distrib_start_date,
distrib_end_date = self.distrib_end_date,
))
class CampaignClear:
def __init__(self) -> None:
self.id = 0
self.entry_flag = 0
self.clear_flag = 0
def make(self) -> bytes:
return Struct(
"id" / Int32ul,
"entry_flag" / Int32ul,
"clear_flag" / Int32ul,
Padding(4),
).build(dict(
id = self.id,
entry_flag = self.entry_flag,
clear_flag = self.clear_flag,
))
class ADBCampaignResponse(ADBBaseResponse):
def __init__(self, game_id: str = "SXXX", store_id: int = 1, keychip_id: str = "A69E01A8888", code: int = 0x0C, length: int = 0x200, status: int = 1) -> None:
super().__init__(code, length, status, game_id, store_id, keychip_id)
self.campaigns = [Campaign(), Campaign(), Campaign()]
@classmethod
def from_req(cls, req: ADBHeader) -> "ADBCampaignResponse":
c = cls(req.game_id, req.store_id, req.keychip_id)
c.head.protocol_ver = req.protocol_ver
return c
def make(self) -> bytes:
body = b""
for c in self.campaigns:
body += c.make()
self.head.length = HEADER_SIZE + len(body)
return self.head.make() + body
class ADBOldCampaignRequest(ADBBaseRequest):
def __init__(self, data: bytes) -> None:
super().__init__(data)
self.campaign_id = struct.unpack_from("<I", data, 0x20)
class ADBOldCampaignResponse(ADBBaseResponse):
def __init__(self, game_id: str = "SXXX", store_id: int = 1, keychip_id: str = "A69E01A8888", code: int = 0x0C, length: int = 0x30, status: int = 1) -> None:
super().__init__(code, length, status, game_id, store_id, keychip_id)
self.info0 = 0
self.info1 = 0
self.info2 = 0
self.info3 = 0
@classmethod
def from_req(cls, req: ADBHeader) -> "ADBCampaignResponse":
c = cls(req.game_id, req.store_id, req.keychip_id)
c.head.protocol_ver = req.protocol_ver
return c
def make(self) -> bytes:
resp_struct = Struct(
"info0" / Int32sl,
"info1" / Int32sl,
"info2" / Int32sl,
"info3" / Int32sl,
).build(
info0 = self.info0,
info1 = self.info1,
info2 = self.info2,
info3 = self.info3,
)
self.head.length = HEADER_SIZE + len(resp_struct)
return self.head.make() + resp_struct
class ADBCampaignClearRequest(ADBBaseRequest):
def __init__(self, data: bytes) -> None:
super().__init__(data)
self.aime_id = struct.unpack_from("<i", data, 0x20)
class ADBCampaignClearResponse(ADBBaseResponse):
def __init__(self, game_id: str = "SXXX", store_id: int = 1, keychip_id: str = "A69E01A8888", code: int = 0x0E, length: int = 0x50, status: int = 1) -> None:
super().__init__(code, length, status, game_id, store_id, keychip_id)
self.campaign_clear_status = [CampaignClear(), CampaignClear(), CampaignClear()]
@classmethod
def from_req(cls, req: ADBHeader) -> "ADBCampaignResponse":
c = cls(req.game_id, req.store_id, req.keychip_id)
c.head.protocol_ver = req.protocol_ver
return c
def make(self) -> bytes:
body = b""
for c in self.campaign_clear_status:
body += c.make()
self.head.length = HEADER_SIZE + len(body)
return self.head.make() + body
+85
View File
@@ -0,0 +1,85 @@
from construct import Struct, Int32sl, Padding, Int8ub, Int16sl
from typing import Union
from .base import *
class ADBFelicaLookupRequest(ADBBaseRequest):
def __init__(self, data: bytes) -> None:
super().__init__(data)
idm, pmm = struct.unpack_from(">QQ", data, 0x20)
self.idm = hex(idm)[2:].upper()
self.pmm = hex(pmm)[2:].upper()
class ADBFelicaLookupResponse(ADBBaseResponse):
def __init__(self, access_code: str = None, game_id: str = "SXXX", store_id: int = 1, keychip_id: str = "A69E01A8888", code: int = 0x03, length: int = 0x30, status: int = 1) -> None:
super().__init__(code, length, status, game_id, store_id, keychip_id)
self.access_code = access_code if access_code is not None else "00000000000000000000"
@classmethod
def from_req(cls, req: ADBHeader, access_code: str = None) -> "ADBFelicaLookupResponse":
c = cls(access_code, req.game_id, req.store_id, req.keychip_id)
c.head.protocol_ver = req.protocol_ver
return c
def make(self) -> bytes:
resp_struct = Struct(
"felica_idx" / Int32ul,
"access_code" / Int8ub[10],
Padding(2)
).build(dict(
felica_idx = 0,
access_code = bytes.fromhex(self.access_code)
))
self.head.length = HEADER_SIZE + len(resp_struct)
return self.head.make() + resp_struct
class ADBFelicaLookup2Request(ADBBaseRequest):
def __init__(self, data: bytes) -> None:
super().__init__(data)
self.random = struct.unpack_from("<16s", data, 0x20)[0]
idm, pmm = struct.unpack_from(">QQ", data, 0x30)
self.card_key_ver, self.write_ct, self.maca, company, fw_ver, self.dfc = struct.unpack_from("<16s16sQccH", data, 0x40)
self.idm = hex(idm)[2:].upper()
self.pmm = hex(pmm)[2:].upper()
self.company = CompanyCodes(int.from_bytes(company, 'little'))
self.fw_ver = ReaderFwVer.from_byte(fw_ver)
class ADBFelicaLookup2Response(ADBBaseResponse):
def __init__(self, user_id: Union[int, None] = None, access_code: Union[str, None] = None, game_id: str = "SXXX", store_id: int = 1, keychip_id: str = "A69E01A8888", code: int = 0x12, length: int = 0x130, status: int = 1) -> None:
super().__init__(code, length, status, game_id, store_id, keychip_id)
self.user_id = user_id if user_id is not None else -1
self.access_code = access_code if access_code is not None else "00000000000000000000"
self.company = CompanyCodes.SEGA
self.portal_status = PortalRegStatus.NO_REG
self.auth_key = [0] * 256
@classmethod
def from_req(cls, req: ADBHeader, user_id: Union[int, None] = None, access_code: Union[str, None] = None) -> "ADBFelicaLookup2Response":
c = cls(user_id, access_code, req.game_id, req.store_id, req.keychip_id)
c.head.protocol_ver = req.protocol_ver
return c
def make(self) -> bytes:
resp_struct = Struct(
"user_id" / Int32sl,
"relation1" / Int32sl,
"relation2" / Int32sl,
"access_code" / Int8ub[10],
"portal_status" / Int8ub,
"company_code" / Int8ub,
Padding(8),
"auth_key" / Int8ub[256],
).build(dict(
user_id = self.user_id,
relation1 = -1, # Unsupported
relation2 = -1, # Unsupported
access_code = bytes.fromhex(self.access_code),
portal_status = self.portal_status.value,
company_code = self.company.value,
auth_key = self.auth_key
))
self.head.length = HEADER_SIZE + len(resp_struct)
return self.head.make() + resp_struct
+56
View File
@@ -0,0 +1,56 @@
from construct import Struct, Padding, Int8sl
from typing import Final, List
from .base import *
NUM_LOGS: Final[int] = 20
NUM_LEN_LOG_EX: Final[int] = 48
class AmLogEx:
def __init__(self, data: bytes) -> None:
self.aime_id, status, self.user_id, self.credit_ct, self.bet_ct, self.won_ct, self.local_time, \
self.tseq, self.place_id = struct.unpack("<IIQiii4xQiI", data)
self.status = LogStatus(status)
class ADBStatusLogRequest(ADBBaseRequest):
def __init__(self, data: bytes) -> None:
super().__init__(data)
self.aime_id, status = struct.unpack_from("<II", data, 0x20)
self.status = LogStatus(status)
class ADBLogRequest(ADBBaseRequest):
def __init__(self, data: bytes) -> None:
super().__init__(data)
self.aime_id, status, self.user_id, self.credit_ct, self.bet_ct, self.won_ct = struct.unpack_from("<IIQiii", data, 0x20)
self.status = LogStatus(status)
class ADBLogExRequest(ADBBaseRequest):
def __init__(self, data: bytes) -> None:
super().__init__(data)
self.logs: List[AmLogEx] = []
for x in range(NUM_LOGS):
self.logs.append(AmLogEx(data[0x20 + (NUM_LEN_LOG_EX * x): 0x50 + (NUM_LEN_LOG_EX * x)]))
self.num_logs = struct.unpack_from("<I", data, 0x03E0)[0]
class ADBLogExResponse(ADBBaseResponse):
def __init__(self, game_id: str = "SXXX", store_id: int = 1, keychip_id: str = "A69E01A8888", protocol_ver: int = 12423, code: int = 20, length: int = 64, status: int = 1) -> None:
super().__init__(code, length, status, game_id, store_id, keychip_id, protocol_ver)
@classmethod
def from_req(cls, req: ADBHeader) -> "ADBLogExResponse":
c = cls(req.game_id, req.store_id, req.keychip_id, req.protocol_ver)
return c
def make(self) -> bytes:
resp_struct = Struct(
"log_result" / Int8sl[NUM_LOGS],
Padding(12)
)
body = resp_struct.build(dict(
log_result = [1] * NUM_LOGS
))
self.head.length = HEADER_SIZE + len(body)
return self.head.make() + body
+82
View File
@@ -0,0 +1,82 @@
from construct import Struct, Int32sl, Padding, Int8sl
from typing import Union
from .base import *
class ADBLookupException(Exception):
pass
class ADBLookupRequest(ADBBaseRequest):
def __init__(self, data: bytes) -> None:
super().__init__(data)
self.access_code = data[0x20:0x2A].hex()
company_code, fw_version, self.serial_number = struct.unpack_from("<bbI", data, 0x2A)
try:
self.company_code = CompanyCodes(company_code)
except ValueError as e:
raise ADBLookupException(f"Invalid company code - {e}")
self.fw_version = ReaderFwVer.from_byte(fw_version)
class ADBLookupResponse(ADBBaseResponse):
def __init__(self, user_id: Union[int, None], game_id: str = "SXXX", store_id: int = 1, keychip_id: str = "A69E01A8888", code: int = 0x06, length: int = 0x30, status: int = 1) -> None:
super().__init__(code, length, status, game_id, store_id, keychip_id)
self.user_id = user_id if user_id is not None else -1
self.portal_reg = PortalRegStatus.NO_REG
@classmethod
def from_req(cls, req: ADBHeader, user_id: Union[int, None]) -> "ADBLookupResponse":
c = cls(user_id, req.game_id, req.store_id, req.keychip_id)
c.head.protocol_ver = req.protocol_ver
return c
def make(self):
resp_struct = Struct(
"user_id" / Int32sl,
"portal_reg" / Int8sl,
Padding(11)
)
body = resp_struct.build(dict(
user_id = self.user_id,
portal_reg = self.portal_reg.value
))
self.head.length = HEADER_SIZE + len(body)
return self.head.make() + body
class ADBLookupExResponse(ADBBaseResponse):
def __init__(self, user_id: Union[int, None], game_id: str = "SXXX", store_id: int = 1, keychip_id: str = "A69E01A8888",
code: int = 0x10, length: int = 0x130, status: int = 1) -> None:
super().__init__(code, length, status, game_id, store_id, keychip_id)
self.user_id = user_id if user_id is not None else -1
self.portal_reg = PortalRegStatus.NO_REG
self.auth_key = [0] * 256
@classmethod
def from_req(cls, req: ADBHeader, user_id: Union[int, None]) -> "ADBLookupExResponse":
c = cls(user_id, req.game_id, req.store_id, req.keychip_id)
c.head.protocol_ver = req.protocol_ver
return c
def make(self):
resp_struct = Struct(
"user_id" / Int32sl,
"portal_reg" / Int8sl,
Padding(3),
"auth_key" / Int8sl[256],
"relation1" / Int32sl,
"relation2" / Int32sl,
)
body = resp_struct.build(dict(
user_id = self.user_id,
portal_reg = self.portal_reg.value,
auth_key = self.auth_key,
relation1 = -1,
relation2 = -1
))
self.head.length = HEADER_SIZE + len(body)
return self.head.make() + body
+294 -222
View File
@@ -1,297 +1,369 @@
from twisted.internet.protocol import Factory, Protocol
import logging, coloredlogs
from Crypto.Cipher import AES
import struct
from typing import Dict, Any
from typing import Dict, Tuple, Callable, Union, Optional
import asyncio
from logging.handlers import TimedRotatingFileHandler
from core.config import CoreConfig
from core.utils import create_sega_auth_key
from core.data import Data
from .adb_handlers import *
class AimedbProtocol(Protocol):
AIMEDB_RESPONSE_CODES = {
"felica_lookup": 0x03,
"lookup": 0x06,
"log": 0x0A,
"campaign": 0x0C,
"touch": 0x0E,
"lookup2": 0x10,
"felica_lookup2": 0x12,
"log2": 0x14,
"hello": 0x65,
}
request_list: Dict[int, Any] = {}
class AimedbServlette():
request_list: Dict[int, Tuple[Callable[[bytes, int], Union[ADBBaseResponse, bytes]], int, str]] = {}
def __init__(self, core_cfg: CoreConfig) -> None:
self.logger = logging.getLogger("aimedb")
self.config = core_cfg
self.data = Data(core_cfg)
if core_cfg.aimedb.key == "":
self.logger = logging.getLogger("aimedb")
if not hasattr(self.logger, "initted"):
log_fmt_str = "[%(asctime)s] Aimedb | %(levelname)s | %(message)s"
log_fmt = logging.Formatter(log_fmt_str)
fileHandler = TimedRotatingFileHandler(
"{0}/{1}.log".format(self.config.server.log_dir, "aimedb"),
when="d",
backupCount=10,
)
fileHandler.setFormatter(log_fmt)
consoleHandler = logging.StreamHandler()
consoleHandler.setFormatter(log_fmt)
self.logger.addHandler(fileHandler)
self.logger.addHandler(consoleHandler)
self.logger.setLevel(self.config.aimedb.loglevel)
coloredlogs.install(
level=core_cfg.aimedb.loglevel, logger=self.logger, fmt=log_fmt_str
)
self.logger.initted = True
if not core_cfg.aimedb.key:
self.logger.error("!!!KEY NOT SET!!!")
exit(1)
self.request_list[0x01] = self.handle_felica_lookup
self.request_list[0x04] = self.handle_lookup
self.request_list[0x05] = self.handle_register
self.request_list[0x09] = self.handle_log
self.request_list[0x0B] = self.handle_campaign
self.request_list[0x0D] = self.handle_touch
self.request_list[0x0F] = self.handle_lookup2
self.request_list[0x11] = self.handle_felica_lookup2
self.request_list[0x13] = self.handle_log2
self.request_list[0x64] = self.handle_hello
self.register_handler(0x01, 0x03, self.handle_felica_lookup, 'felica_lookup')
self.register_handler(0x02, 0x03, self.handle_felica_register, 'felica_register')
def append_padding(self, data: bytes):
"""Appends 0s to the end of the data until it's at the correct size"""
length = struct.unpack_from("<H", data, 6)
padding_size = length[0] - len(data)
data += bytes(padding_size)
return data
self.register_handler(0x04, 0x06, self.handle_lookup, 'lookup')
self.register_handler(0x05, 0x06, self.handle_register, 'register')
def connectionMade(self) -> None:
self.logger.debug(f"{self.transport.getPeer().host} Connected")
self.register_handler(0x07, 0x08, self.handle_status_log, 'status_log')
self.register_handler(0x09, 0x0A, self.handle_log, 'aime_log')
def connectionLost(self, reason) -> None:
self.logger.debug(
f"{self.transport.getPeer().host} Disconnected - {reason.value}"
)
self.register_handler(0x0B, 0x0C, self.handle_campaign, 'campaign')
self.register_handler(0x0D, 0x0E, self.handle_campaign_clear, 'campaign_clear')
def dataReceived(self, data: bytes) -> None:
self.register_handler(0x0F, 0x10, self.handle_lookup_ex, 'lookup_ex')
self.register_handler(0x11, 0x12, self.handle_felica_lookup_ex, 'felica_lookup_ex')
self.register_handler(0x13, 0x14, self.handle_log_ex, 'aime_log_ex')
self.register_handler(0x64, 0x65, self.handle_hello, 'hello')
def register_handler(self, cmd: int, resp:int, handler: Callable[[bytes, int], Union[ADBBaseResponse, bytes]], name: str) -> None:
self.request_list[cmd] = (handler, resp, name)
def start(self) -> None:
self.logger.info(f"Start on port {self.config.aimedb.port}")
addr = self.config.aimedb.listen_address if self.config.aimedb.listen_address else self.config.server.listen_address
asyncio.create_task(asyncio.start_server(self.dataReceived, addr, self.config.aimedb.port))
async def dataReceived(self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
self.logger.debug(f"Connection made from {writer.get_extra_info('peername')[0]}")
while True:
try:
data: bytes = await reader.read(4096)
if len(data) == 0:
self.logger.debug("Connection closed")
return
await self.process_data(data, reader, writer)
await writer.drain()
except ConnectionResetError as e:
self.logger.debug("Connection reset, disconnecting")
return
async def process_data(self, data: bytes, reader: asyncio.StreamReader, writer: asyncio.StreamWriter) -> Optional[bytes]:
addr = writer.get_extra_info('peername')[0]
cipher = AES.new(self.config.aimedb.key.encode(), AES.MODE_ECB)
try:
decrypted = cipher.decrypt(data)
except:
self.logger.error(f"Failed to decrypt {data.hex()}")
return None
self.logger.debug(f"{self.transport.getPeer().host} wrote {decrypted.hex()}")
if not decrypted[1] == 0xA1 and not decrypted[0] == 0x3E:
self.logger.error(f"Bad magic")
return None
req_code = decrypted[4]
if req_code == 0x66:
self.logger.info(f"goodbye from {self.transport.getPeer().host}")
self.transport.loseConnection()
except Exception as e:
self.logger.error(f"Failed to decrypt {data.hex()} because {e}")
return
self.logger.debug(f"{addr} wrote {decrypted.hex()}")
try:
resp = self.request_list[req_code](decrypted)
encrypted = cipher.encrypt(resp)
self.logger.debug(f"Response {resp.hex()}")
self.transport.write(encrypted)
head = ADBHeader.from_data(decrypted)
except KeyError:
self.logger.error(f"Unknown command code {hex(req_code)}")
return None
except ADBHeaderException as e:
self.logger.error(f"Error parsing ADB header: {e}")
try:
encrypted = cipher.encrypt(ADBBaseResponse().make())
writer.write(encrypted)
await writer.drain()
return
except ValueError as e:
self.logger.error(f"Failed to encrypt {resp.hex()} because {e}")
return None
except Exception as e:
self.logger.error(f"Failed to encrypt default response because {e}")
def handle_campaign(self, data: bytes) -> bytes:
self.logger.info(f"campaign from {self.transport.getPeer().host}")
ret = struct.pack(
"<5H",
0xA13E,
0x3087,
self.AIMEDB_RESPONSE_CODES["campaign"],
0x0200,
0x0001,
)
return self.append_padding(ret)
return
def handle_hello(self, data: bytes) -> bytes:
self.logger.info(f"hello from {self.transport.getPeer().host}")
ret = struct.pack(
"<5H", 0xA13E, 0x3087, self.AIMEDB_RESPONSE_CODES["hello"], 0x0020, 0x0001
)
return self.append_padding(ret)
if head.keychip_id == "ABCD1234567" or head.store_id == 0xfff0:
self.logger.warning(f"Request from uninitialized AMLib: {vars(head)}")
def handle_lookup(self, data: bytes) -> bytes:
luid = data[0x20:0x2A].hex()
user_id = self.data.card.get_user_id_from_card(access_code=luid)
if head.cmd == 0x66:
self.logger.info("Goodbye")
writer.close()
return
if user_id is None:
user_id = -1
handler, resp_code, name = self.request_list.get(head.cmd, (self.handle_default, None, 'default'))
self.logger.info(
f"lookup from {self.transport.getPeer().host}: luid {luid} -> user_id {user_id}"
)
if resp_code is None:
self.logger.warning(f"No handler for cmd {hex(head.cmd)}")
ret = struct.pack(
"<5H", 0xA13E, 0x3087, self.AIMEDB_RESPONSE_CODES["lookup"], 0x0130, 0x0001
)
ret += bytes(0x20 - len(ret))
elif resp_code > 0:
self.logger.info(f"{name} from {head.keychip_id} ({head.game_id}) @ {addr}")
resp = await handler(decrypted, resp_code)
if type(resp) == ADBBaseResponse or issubclass(type(resp), ADBBaseResponse):
resp_bytes = resp.make()
elif type(resp) == bytes:
resp_bytes = resp
elif resp is None: # Nothing to send, probably a goodbye
self.logger.warn(f"None return by handler for {name}")
return
if user_id is None:
ret += struct.pack("<iH", -1, 0)
else:
ret += struct.pack("<l", user_id)
return self.append_padding(ret)
self.logger.error(f"Unsupported type returned by ADB handler for {name}: {type(resp)}")
raise TypeError(f"Unsupported type returned by ADB handler for {name}: {type(resp)}")
def handle_lookup2(self, data: bytes) -> bytes:
self.logger.info(f"lookup2")
try:
encrypted = cipher.encrypt(resp_bytes)
self.logger.debug(f"Response {resp_bytes.hex()}")
writer.write(encrypted)
ret = bytearray(self.handle_lookup(data))
ret[4] = self.AIMEDB_RESPONSE_CODES["lookup2"]
except Exception as e:
self.logger.error(f"Failed to encrypt {resp_bytes.hex()} because {e}")
return bytes(ret)
async def handle_default(self, data: bytes, resp_code: int, length: int = 0x20) -> ADBBaseResponse:
req = ADBHeader.from_data(data)
return ADBBaseResponse(resp_code, length, 1, req.game_id, req.store_id, req.keychip_id, req.protocol_ver)
def handle_felica_lookup(self, data: bytes) -> bytes:
idm = data[0x20:0x28].hex()
pmm = data[0x28:0x30].hex()
access_code = self.data.card.to_access_code(idm)
self.logger.info(
f"felica_lookup from {self.transport.getPeer().host}: idm {idm} pmm {pmm} -> access_code {access_code}"
)
async def handle_hello(self, data: bytes, resp_code: int) -> ADBBaseResponse:
return await self.handle_default(data, resp_code)
ret = struct.pack(
"<5H",
0xA13E,
0x3087,
self.AIMEDB_RESPONSE_CODES["felica_lookup"],
0x0030,
0x0001,
)
ret += bytes(26)
ret += bytes.fromhex(access_code)
async def handle_campaign(self, data: bytes, resp_code: int) -> ADBBaseResponse:
h = ADBHeader.from_data(data)
if h.protocol_ver >= 0x3030:
req = h
resp = ADBCampaignResponse.from_req(req)
return self.append_padding(ret)
else:
req = ADBOldCampaignRequest(data)
def handle_felica_lookup2(self, data: bytes) -> bytes:
idm = data[0x30:0x38].hex()
pmm = data[0x38:0x40].hex()
access_code = self.data.card.to_access_code(idm)
user_id = self.data.card.get_user_id_from_card(access_code=access_code)
self.logger.info(f"Legacy campaign request for campaign {req.campaign_id} (protocol version {hex(h.protocol_ver)})")
resp = ADBOldCampaignResponse.from_req(req.head)
if user_id is None:
user_id = -1
# We don't currently support campaigns
return resp
async def handle_lookup(self, data: bytes, resp_code: int) -> ADBBaseResponse:
req = ADBLookupRequest(data)
user_id = await self.data.card.get_user_id_from_card(req.access_code)
is_banned = await self.data.card.get_card_banned(req.access_code)
is_locked = await self.data.card.get_card_locked(req.access_code)
ret = ADBLookupResponse.from_req(req.head, user_id)
if is_banned and is_locked:
ret.head.status = ADBStatus.BAN_SYS_USER
elif is_banned:
ret.head.status = ADBStatus.BAN_SYS
elif is_locked:
ret.head.status = ADBStatus.LOCK_USER
self.logger.info(
f"felica_lookup2 from {self.transport.getPeer().host}: idm {idm} ipm {pmm} -> access_code {access_code} user_id {user_id}"
f"access_code {req.access_code} -> user_id {ret.user_id}"
)
ret = struct.pack(
"<5H",
0xA13E,
0x3087,
self.AIMEDB_RESPONSE_CODES["felica_lookup2"],
0x0140,
0x0001,
if user_id and user_id > 0:
await self.data.card.update_card_last_login(req.access_code)
return ret
async def handle_lookup_ex(self, data: bytes, resp_code: int) -> ADBBaseResponse:
req = ADBLookupRequest(data)
user_id = await self.data.card.get_user_id_from_card(req.access_code)
is_banned = await self.data.card.get_card_banned(req.access_code)
is_locked = await self.data.card.get_card_locked(req.access_code)
ret = ADBLookupExResponse.from_req(req.head, user_id)
if is_banned and is_locked:
ret.head.status = ADBStatus.BAN_SYS_USER
elif is_banned:
ret.head.status = ADBStatus.BAN_SYS
elif is_locked:
ret.head.status = ADBStatus.LOCK_USER
self.logger.info(
f"access_code {req.access_code} -> user_id {ret.user_id}"
)
ret += bytes(22)
ret += struct.pack("<lq", user_id, -1) # first -1 is ext_id, 3rd is access code
ret += bytes.fromhex(access_code)
ret += struct.pack("<l", 1)
return self.append_padding(ret)
if user_id and user_id > 0 and self.config.aimedb.id_secret:
auth_key = create_sega_auth_key(user_id, req.head.game_id, req.head.store_id, req.head.keychip_id, self.config.aimedb.id_secret, self.config.aimedb.id_lifetime_seconds)
if auth_key is not None:
auth_key_extra_len = 256 - len(auth_key)
auth_key_full = auth_key.encode() + (b"\0" * auth_key_extra_len)
self.logger.debug(f"Generated auth token {auth_key}")
ret.auth_key = auth_key_full
def handle_touch(self, data: bytes) -> bytes:
self.logger.info(f"touch from {self.transport.getPeer().host}")
ret = struct.pack(
"<5H", 0xA13E, 0x3087, self.AIMEDB_RESPONSE_CODES["touch"], 0x0050, 0x0001
if user_id and user_id > 0:
await self.data.card.update_card_last_login(req.access_code)
return ret
async def handle_felica_lookup(self, data: bytes, resp_code: int) -> bytes:
"""
On official, I think a card has to be registered for this to actually work, but
I'm making the executive decision to not implement that and just kick back our
faux generated access code. The real felica IDm -> access code conversion is done
on the ADB server, which we do not and will not ever have access to. Because we can
assure that all IDms will be unique, this basic 0-padded hex -> int conversion will
be fine.
"""
req = ADBFelicaLookupRequest(data)
ac = self.data.card.to_access_code(req.idm)
self.logger.info(
f"idm {req.idm} ipm {req.pmm} -> access_code {ac}"
)
ret += bytes(5)
ret += struct.pack("<3H", 0x6F, 0, 1)
return ADBFelicaLookupResponse.from_req(req.head, ac)
return self.append_padding(ret)
async def handle_felica_register(self, data: bytes, resp_code: int) -> bytes:
"""
I've never seen this used.
"""
req = ADBFelicaLookupRequest(data)
ac = self.data.card.to_access_code(req.idm)
def handle_register(self, data: bytes) -> bytes:
luid = data[0x20:0x2A].hex()
if self.config.server.allow_user_registration:
user_id = self.data.user.create_user()
user_id = await self.data.user.create_user()
if user_id is None:
user_id = -1
self.logger.error("Failed to register user!")
user_id = -1
else:
card_id = self.data.card.create_card(user_id, luid)
card_id = await self.data.card.create_card(user_id, ac)
if card_id is None:
user_id = -1
self.logger.error("Failed to register card!")
user_id = -1
self.logger.info(
f"register from {self.transport.getPeer().host}: luid {luid} -> user_id {user_id}"
f"Register access code {ac} (IDm: {req.idm} PMm: {req.pmm}) -> user_id {user_id}"
)
else:
self.logger.info(
f"register from {self.transport.getPeer().host} blocked!: luid {luid}"
f"Registration blocked!: access code {ac} (IDm: {req.idm} PMm: {req.pmm})"
)
if user_id > 0:
await self.data.card.update_card_last_login(ac)
return ADBFelicaLookupResponse.from_req(req.head, ac)
async def handle_felica_lookup_ex(self, data: bytes, resp_code: int) -> bytes:
req = ADBFelicaLookup2Request(data)
access_code = self.data.card.to_access_code(req.idm)
user_id = await self.data.card.get_user_id_from_card(access_code=access_code)
if user_id is None:
user_id = -1
ret = struct.pack(
"<5H",
0xA13E,
0x3087,
self.AIMEDB_RESPONSE_CODES["lookup"],
0x0030,
0x0001 if user_id > -1 else 0,
)
ret += bytes(0x20 - len(ret))
ret += struct.pack("<l", user_id)
return self.append_padding(ret)
def handle_log(self, data: bytes) -> bytes:
# TODO: Save aimedb logs
self.logger.info(f"log from {self.transport.getPeer().host}")
ret = struct.pack(
"<5H", 0xA13E, 0x3087, self.AIMEDB_RESPONSE_CODES["log"], 0x0020, 0x0001
)
return self.append_padding(ret)
def handle_log2(self, data: bytes) -> bytes:
self.logger.info(f"log2 from {self.transport.getPeer().host}")
ret = struct.pack(
"<5H", 0xA13E, 0x3087, self.AIMEDB_RESPONSE_CODES["log2"], 0x0040, 0x0001
)
ret += bytes(22)
ret += struct.pack("H", 1)
return self.append_padding(ret)
class AimedbFactory(Factory):
protocol = AimedbProtocol
def __init__(self, cfg: CoreConfig) -> None:
self.config = cfg
log_fmt_str = "[%(asctime)s] Aimedb | %(levelname)s | %(message)s"
log_fmt = logging.Formatter(log_fmt_str)
self.logger = logging.getLogger("aimedb")
fileHandler = TimedRotatingFileHandler(
"{0}/{1}.log".format(self.config.server.log_dir, "aimedb"),
when="d",
backupCount=10,
)
fileHandler.setFormatter(log_fmt)
consoleHandler = logging.StreamHandler()
consoleHandler.setFormatter(log_fmt)
self.logger.addHandler(fileHandler)
self.logger.addHandler(consoleHandler)
self.logger.setLevel(self.config.aimedb.loglevel)
coloredlogs.install(
level=cfg.aimedb.loglevel, logger=self.logger, fmt=log_fmt_str
self.logger.info(
f"idm {req.idm} ipm {req.pmm} -> access_code {access_code} user_id {user_id}"
)
if self.config.aimedb.key == "":
self.logger.error("Please set 'key' field in your config file.")
exit(1)
resp = ADBFelicaLookup2Response.from_req(req.head, user_id, access_code)
self.logger.info(f"Ready on port {self.config.aimedb.port}")
if user_id and user_id > 0 and self.config.aimedb.id_secret:
auth_key = create_sega_auth_key(user_id, req.head.game_id, req.head.store_id, req.head.keychip_id, self.config.aimedb.id_secret, self.config.aimedb.id_lifetime_seconds)
if auth_key is not None:
auth_key_extra_len = 256 - len(auth_key)
auth_key_full = auth_key.encode() + (b"\0" * auth_key_extra_len)
self.logger.debug(f"Generated auth token {auth_key}")
resp.auth_key = auth_key_full
if user_id and user_id > 0:
await self.data.card.update_card_last_login(access_code)
return resp
async def handle_campaign_clear(self, data: bytes, resp_code: int) -> ADBBaseResponse:
req = ADBCampaignClearRequest(data)
resp = ADBCampaignClearResponse.from_req(req.head)
# We don't support campaign stuff
return resp
async def handle_register(self, data: bytes, resp_code: int) -> bytes:
req = ADBLookupRequest(data)
user_id = -1
if self.config.server.allow_user_registration:
user_id = await self.data.user.create_user()
if user_id is None:
self.logger.error("Failed to register user!")
user_id = -1
else:
card_id = await self.data.card.create_card(user_id, req.access_code)
if card_id is None:
self.logger.error("Failed to register card!")
user_id = -1
self.logger.info(
f"Register access code {req.access_code} -> user_id {user_id}"
)
else:
self.logger.info(
f"Registration blocked!: access code {req.access_code}"
)
resp = ADBLookupResponse.from_req(req.head, user_id)
if resp.user_id <= 0:
resp.head.status = ADBStatus.BAN_SYS # Closest we can get to a "You cannot register"
else:
await self.data.card.update_card_last_login(req.access_code)
return resp
# TODO: Save these in some capacity, as deemed relevant
async def handle_status_log(self, data: bytes, resp_code: int) -> bytes:
req = ADBStatusLogRequest(data)
self.logger.info(f"User {req.aime_id} logged {req.status.name} event")
return ADBBaseResponse(resp_code, 0x20, 1, req.head.game_id, req.head.store_id, req.head.keychip_id, req.head.protocol_ver)
async def handle_log(self, data: bytes, resp_code: int) -> bytes:
req = ADBLogRequest(data)
self.logger.info(f"User {req.aime_id} logged {req.status.name} event, credit_ct: {req.credit_ct} bet_ct: {req.bet_ct} won_ct: {req.won_ct}")
return ADBBaseResponse(resp_code, 0x20, 1, req.head.game_id, req.head.store_id, req.head.keychip_id, req.head.protocol_ver)
async def handle_log_ex(self, data: bytes, resp_code: int) -> bytes:
req = ADBLogExRequest(data)
strs = []
self.logger.info(f"Recieved {req.num_logs} or {len(req.logs)} logs")
for x in range(req.num_logs):
self.logger.debug(f"User {req.logs[x].aime_id} logged {req.logs[x].status.name} event, credit_ct: {req.logs[x].credit_ct} bet_ct: {req.logs[x].bet_ct} won_ct: {req.logs[x].won_ct}")
return ADBLogExResponse.from_req(req.head)
def buildProtocol(self, addr):
return AimedbProtocol(self.config)
+721 -246
View File
File diff suppressed because it is too large Load Diff
+92
View File
@@ -0,0 +1,92 @@
import yaml
import logging
import coloredlogs
from logging.handlers import TimedRotatingFileHandler
from starlette.routing import Route
from starlette.requests import Request
from starlette.applications import Starlette
from starlette.responses import PlainTextResponse
from os import environ, path, mkdir, W_OK, access
from typing import List
from core import CoreConfig, TitleServlet, MuchaServlet, AllnetServlet, BillingServlet, AimedbServlette
from core.frontend import FrontendServlet
async def dummy_rt(request: Request):
return PlainTextResponse("Service OK")
cfg_dir = environ.get("ARTEMIS_CFG_DIR", "config")
cfg: CoreConfig = CoreConfig()
if path.exists(f"{cfg_dir}/core.yaml"):
cfg.update(yaml.safe_load(open(f"{cfg_dir}/core.yaml")))
if not path.exists(cfg.server.log_dir):
mkdir(cfg.server.log_dir)
if not access(cfg.server.log_dir, W_OK):
print(
f"Log directory {cfg.server.log_dir} NOT writable, please check permissions"
)
exit(1)
logger = logging.getLogger("core")
log_fmt_str = "[%(asctime)s] Core | %(levelname)s | %(message)s"
log_fmt = logging.Formatter(log_fmt_str)
fileHandler = TimedRotatingFileHandler(
"{0}/{1}.log".format(cfg.server.log_dir, "core"), when="d", backupCount=10
)
fileHandler.setFormatter(log_fmt)
consoleHandler = logging.StreamHandler()
consoleHandler.setFormatter(log_fmt)
logger.addHandler(fileHandler)
logger.addHandler(consoleHandler)
log_lv = logging.DEBUG if cfg.server.is_develop else logging.INFO
logger.setLevel(log_lv)
coloredlogs.install(level=log_lv, logger=logger, fmt=log_fmt_str)
logger.info(f"Artemis starting in {'develop' if cfg.server.is_develop else 'production'} mode")
title = TitleServlet(cfg, cfg_dir) # This has to be loaded first to load plugins
mucha = MuchaServlet(cfg, cfg_dir)
route_lst: List[Route] = [
# Mucha
Route("/mucha_front/boardauth.do", mucha.handle_boardauth, methods=["POST"]),
Route("/mucha_front/updatacheck.do", mucha.handle_updatecheck, methods=["POST"]),
Route("/mucha_front/downloadstate.do", mucha.handle_dlstate, methods=["POST"]),
# General
Route("/", dummy_rt),
Route("/robots.txt", FrontendServlet.robots)
]
if not cfg.billing.standalone:
billing = BillingServlet(cfg, cfg_dir)
route_lst += [
Route("/request", billing.handle_billing_request, methods=["POST"]),
Route("/request/", billing.handle_billing_request, methods=["POST"]),
]
if not cfg.allnet.standalone:
allnet = AllnetServlet(cfg, cfg_dir)
route_lst += [
Route("/sys/servlet/PowerOn", allnet.handle_poweron, methods=["GET", "POST"]),
Route("/sys/servlet/DownloadOrder", allnet.handle_dlorder, methods=["GET", "POST"]),
Route("/sys/servlet/LoaderStateRecorder", allnet.handle_loaderstaterecorder, methods=["GET", "POST"]),
Route("/sys/servlet/Alive", allnet.handle_alive, methods=["GET", "POST"]),
Route("/naomitest.html", allnet.handle_naomitest),
]
if cfg.allnet.allow_online_updates:
route_lst += [
Route("/report-api/Report", allnet.handle_dlorder_report, methods=["POST"]),
Route("/dl/ini/{file:str}", allnet.handle_dlorder_ini),
]
for code, game in title.title_registry.items():
route_lst += game.get_routes()
app = Starlette(cfg.server.is_develop, route_lst)
+151 -36
View File
@@ -1,17 +1,49 @@
import logging, os
from typing import Any
class ServerConfig:
def __init__(self, parent_config: "CoreConfig") -> None:
self.__config = parent_config
@property
def listen_address(self) -> str:
"""
Address Artemis will bind to and listen on
"""
return CoreConfig.get_config_field(
self.__config, "core", "server", "listen_address", default="127.0.0.1"
)
@property
def hostname(self) -> str:
"""
Hostname sent to games
"""
return CoreConfig.get_config_field(
self.__config, "core", "server", "hostname", default="localhost"
)
@property
def port(self) -> int:
"""
Port the game will listen on
"""
return CoreConfig.get_config_field(
self.__config, "core", "server", "port", default=80
)
@property
def ssl_key(self) -> str:
return CoreConfig.get_config_field(
self.__config, "core", "server", "ssl_key", default="cert/title.key"
)
@property
def ssl_cert(self) -> str:
return CoreConfig.get_config_field(
self.__config, "core", "title", "ssl_cert", default="cert/title.pem"
)
@property
def allow_user_registration(self) -> bool:
return CoreConfig.get_config_field(
@@ -36,12 +68,49 @@ class ServerConfig:
self.__config, "core", "server", "is_develop", default=True
)
@property
def is_using_proxy(self) -> bool:
return CoreConfig.get_config_field(
self.__config, "core", "server", "is_using_proxy", default=False
)
@property
def proxy_port(self) -> int:
"""
What port the proxy is listening on. This will be sent instead of 'port' if
is_using_proxy is True and this value is non-zero
"""
return CoreConfig.get_config_field(
self.__config, "core", "server", "proxy_port", default=0
)
@property
def proxy_port_ssl(self) -> int:
"""
What port the proxy is listening for secure connections on. This will be sent
instead of 'port' if is_using_proxy is True and this value is non-zero
"""
return CoreConfig.get_config_field(
self.__config, "core", "server", "proxy_port_ssl", default=0
)
@property
def log_dir(self) -> str:
return CoreConfig.get_config_field(
self.__config, "core", "server", "log_dir", default="logs"
)
@property
def check_arcade_ip(self) -> bool:
return CoreConfig.get_config_field(
self.__config, "core", "server", "check_arcade_ip", default=False
)
@property
def strict_ip_checking(self) -> bool:
return CoreConfig.get_config_field(
self.__config, "core", "server", "strict_ip_checking", default=False
)
class TitleConfig:
def __init__(self, parent_config: "CoreConfig") -> None:
@@ -56,18 +125,17 @@ class TitleConfig:
)
@property
def hostname(self) -> str:
def reboot_start_time(self) -> str:
return CoreConfig.get_config_field(
self.__config, "core", "title", "hostname", default="localhost"
self.__config, "core", "title", "reboot_start_time", default=""
)
@property
def port(self) -> int:
def reboot_end_time(self) -> str:
return CoreConfig.get_config_field(
self.__config, "core", "title", "port", default=8080
self.__config, "core", "title", "reboot_end_time", default=""
)
class DatabaseConfig:
def __init__(self, parent_config: "CoreConfig") -> None:
self.__config = parent_config
@@ -105,7 +173,7 @@ class DatabaseConfig:
@property
def protocol(self) -> str:
return CoreConfig.get_config_field(
self.__config, "core", "database", "type", default="mysql"
self.__config, "core", "database", "protocol", default="mysql"
)
@property
@@ -123,13 +191,9 @@ class DatabaseConfig:
)
@property
def user_table_autoincrement_start(self) -> int:
def enable_memcached(self) -> bool:
return CoreConfig.get_config_field(
self.__config,
"core",
"database",
"user_table_autoincrement_start",
default=10000,
self.__config, "core", "database", "enable_memcached", default=True
)
@property
@@ -138,13 +202,12 @@ class DatabaseConfig:
self.__config, "core", "database", "memcached_host", default="localhost"
)
class FrontendConfig:
def __init__(self, parent_config: "CoreConfig") -> None:
self.__config = parent_config
@property
def enable(self) -> int:
def enable(self) -> bool:
return CoreConfig.get_config_field(
self.__config, "core", "frontend", "enable", default=False
)
@@ -152,7 +215,7 @@ class FrontendConfig:
@property
def port(self) -> int:
return CoreConfig.get_config_field(
self.__config, "core", "frontend", "port", default=8090
self.__config, "core", "frontend", "port", default=8080
)
@property
@@ -163,11 +226,28 @@ class FrontendConfig:
)
)
@property
def secret(self) -> str:
return CoreConfig.get_config_field(
self.__config, "core", "frontend", "secret", default=""
)
class AllnetConfig:
def __init__(self, parent_config: "CoreConfig") -> None:
self.__config = parent_config
@property
def standalone(self) -> bool:
return CoreConfig.get_config_field(
self.__config, "core", "allnet", "standalone", default=False
)
@property
def port(self) -> int:
return CoreConfig.get_config_field(
self.__config, "core", "allnet", "port", default=80
)
@property
def loglevel(self) -> int:
return CoreConfig.str_to_loglevel(
@@ -176,23 +256,36 @@ class AllnetConfig:
)
)
@property
def port(self) -> int:
return CoreConfig.get_config_field(
self.__config, "core", "allnet", "port", default=80
)
@property
def allow_online_updates(self) -> int:
return CoreConfig.get_config_field(
self.__config, "core", "allnet", "allow_online_updates", default=False
)
@property
def update_cfg_folder(self) -> str:
return CoreConfig.get_config_field(
self.__config, "core", "allnet", "update_cfg_folder", default=""
)
class BillingConfig:
def __init__(self, parent_config: "CoreConfig") -> None:
self.__config = parent_config
@property
def standalone(self) -> bool:
return CoreConfig.get_config_field(
self.__config, "core", "billing", "standalone", default=True
)
@property
def loglevel(self) -> int:
return CoreConfig.str_to_loglevel(
CoreConfig.get_config_field(
self.__config, "core", "billing", "loglevel", default="info"
)
)
@property
def port(self) -> int:
return CoreConfig.get_config_field(
@@ -217,11 +310,22 @@ class BillingConfig:
self.__config, "core", "billing", "signing_key", default="cert/billing.key"
)
class AimedbConfig:
def __init__(self, parent_config: "CoreConfig") -> None:
self.__config = parent_config
@property
def enable(self) -> bool:
return CoreConfig.get_config_field(
self.__config, "core", "aimedb", "enable", default=True
)
@property
def listen_address(self) -> bool:
return CoreConfig.get_config_field(
self.__config, "core", "aimedb", "listen_address", default=""
)
@property
def loglevel(self) -> int:
return CoreConfig.str_to_loglevel(
@@ -242,17 +346,22 @@ class AimedbConfig:
self.__config, "core", "aimedb", "key", default=""
)
@property
def id_secret(self) -> str:
return CoreConfig.get_config_field(
self.__config, "core", "aimedb", "id_secret", default=""
)
@property
def id_lifetime_seconds(self) -> int:
return CoreConfig.get_config_field(
self.__config, "core", "aimedb", "id_lifetime_seconds", default=86400
)
class MuchaConfig:
def __init__(self, parent_config: "CoreConfig") -> None:
self.__config = parent_config
@property
def enable(self) -> int:
return CoreConfig.get_config_field(
self.__config, "core", "mucha", "enable", default=False
)
@property
def loglevel(self) -> int:
return CoreConfig.str_to_loglevel(
@@ -261,13 +370,6 @@ class MuchaConfig:
)
)
@property
def hostname(self) -> str:
return CoreConfig.get_config_field(
self.__config, "core", "mucha", "hostname", default="localhost"
)
class CoreConfig(dict):
def __init__(self) -> None:
self.server = ServerConfig(self)
@@ -290,6 +392,19 @@ class CoreConfig(dict):
else:
return logging.INFO
@classmethod
def loglevel_to_str(cls, level: int) -> str:
if level == logging.ERROR:
return "error"
elif level == logging.WARN:
return "warn"
elif level == logging.INFO:
return "info"
elif level == logging.DEBUG:
return "debug"
else:
return "notset"
@classmethod
def get_config_field(
cls, __config: dict, module, *path: str, default: Any = ""
+1
View File
@@ -0,0 +1 @@
Generic single-database configuration.
+64
View File
@@ -0,0 +1,64 @@
# A generic, single database configuration.
[alembic]
script_location=.
# template used to generate migration files
# file_template = %%(rev)s_%%(slug)s
# max length of characters to apply to the
# "slug" field
#truncate_slug_length = 40
# set to 'true' to run the environment during
# the 'revision' command, regardless of autogenerate
# revision_environment = false
# set to 'true' to allow .pyc and .pyo files without
# a source .py file to be detected as revisions in the
# versions/ directory
# sourceless = false
# version location specification; this defaults
# to migrations//versions. When using multiple version
# directories, initial revisions must be specified with --version-path
# version_locations = %(here)s/bar %(here)s/bat migrations//versions
# the output encoding used when revision files
# are written from script.py.mako
# output_encoding = utf-8
# Logging configuration
[loggers]
keys = root,sqlalchemy,alembic
[handlers]
keys = console
[formatters]
keys = generic
[logger_root]
level = WARN
handlers = console
qualname =
[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine
[logger_alembic]
level = INFO
handlers =
qualname = alembic
[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic
[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S
+81
View File
@@ -0,0 +1,81 @@
from __future__ import with_statement
from alembic import context
from sqlalchemy import engine_from_config, pool
from logging.config import fileConfig
from core.data.schema.base import metadata
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config
# Interpret the config file for Python logging.
# This line sets up loggers basically.
fileConfig(config.config_file_name)
# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
target_metadata = metadata
# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.
def run_migrations_offline():
"""Run migrations in 'offline' mode.
This configures the context with just a URL
and not an Engine, though an Engine is acceptable
here as well. By skipping the Engine creation
we don't even need a DBAPI to be available.
Calls to context.execute() here emit the given string to the
script output.
"""
raise Exception('Not implemented or configured!')
url = config.get_main_option("sqlalchemy.url")
context.configure(
url=url, target_metadata=target_metadata, literal_binds=True)
with context.begin_transaction():
context.run_migrations()
def run_migrations_online():
"""Run migrations in 'online' mode.
In this scenario we need to create an Engine
and associate a connection with the context.
"""
ini_section = config.get_section(config.config_ini_section)
overrides = context.get_x_argument(as_dictionary=True)
for override in overrides:
ini_section[override] = overrides[override]
connectable = engine_from_config(
ini_section,
prefix='sqlalchemy.',
poolclass=pool.NullPool)
with connectable.connect() as connection:
context.configure(
connection=connection,
target_metadata=target_metadata,
compare_type=True,
compare_server_default=True,
)
with context.begin_transaction():
context.run_migrations()
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()
+24
View File
@@ -0,0 +1,24 @@
"""${message}
Revision ID: ${up_revision}
Revises: ${down_revision | comma,n}
Create Date: ${create_date}
"""
from alembic import op
import sqlalchemy as sa
${imports if imports else ""}
# revision identifiers, used by Alembic.
revision = ${repr(up_revision)}
down_revision = ${repr(down_revision)}
branch_labels = ${repr(branch_labels)}
depends_on = ${repr(depends_on)}
def upgrade():
${upgrades if upgrades else "pass"}
def downgrade():
${downgrades if downgrades else "pass"}
@@ -0,0 +1,24 @@
"""Initial Migration
Revision ID: 835b862f9bf0
Revises:
Create Date: 2024-01-09 13:06:10.787432
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '835b862f9bf0'
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
pass
def downgrade():
pass
@@ -0,0 +1,29 @@
"""Remove old db mgmt system
Revision ID: d8950c7ce2fc
Revises: 835b862f9bf0
Create Date: 2024-01-09 13:43:51.381175
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'd8950c7ce2fc'
down_revision = '835b862f9bf0'
branch_labels = None
depends_on = None
def upgrade():
op.drop_table("schema_versions")
def downgrade():
op.create_table(
"schema_versions",
sa.Column("game", sa.String(4), primary_key=True, nullable=False),
sa.Column("version", sa.Integer, nullable=False, server_default="1"),
mysql_charset="utf8mb4",
)
+1 -1
View File
@@ -17,7 +17,7 @@ except ModuleNotFoundError:
def cached(lifetime: int = 10, extra_key: Any = None) -> Callable:
def _cached(func: Callable) -> Callable:
if has_mc:
if has_mc and (cfg and cfg.database.enable_memcached):
hostname = "127.0.0.1"
if cfg:
hostname = cfg.database.memcached_host
+166 -196
View File
@@ -1,13 +1,14 @@
import logging, coloredlogs
from typing import Optional
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy import create_engine
from logging.handlers import TimedRotatingFileHandler
import importlib, os
import os
import secrets, string
import bcrypt
from hashlib import sha256
import alembic.config
import glob
from core.config import CoreConfig
from core.data.schema import *
@@ -15,31 +16,47 @@ from core.utils import Utils
class Data:
engine = None
session = None
user = None
arcade = None
card = None
base = None
def __init__(self, cfg: CoreConfig) -> None:
self.config = cfg
if self.config.database.sha2_password:
passwd = sha256(self.config.database.password.encode()).digest()
self.__url = f"{self.config.database.protocol}://{self.config.database.username}:{passwd.hex()}@{self.config.database.host}/{self.config.database.name}?charset=utf8mb4"
self.__url = f"{self.config.database.protocol}://{self.config.database.username}:{passwd.hex()}@{self.config.database.host}:{self.config.database.port}/{self.config.database.name}?charset=utf8mb4"
else:
self.__url = f"{self.config.database.protocol}://{self.config.database.username}:{self.config.database.password}@{self.config.database.host}/{self.config.database.name}?charset=utf8mb4"
self.__url = f"{self.config.database.protocol}://{self.config.database.username}:{self.config.database.password}@{self.config.database.host}:{self.config.database.port}/{self.config.database.name}?charset=utf8mb4"
self.__engine = create_engine(self.__url, pool_recycle=3600)
session = sessionmaker(bind=self.__engine, autoflush=True, autocommit=True)
self.session = scoped_session(session)
if Data.engine is None:
Data.engine = create_engine(self.__url, pool_recycle=3600)
self.__engine = Data.engine
self.user = UserData(self.config, self.session)
self.arcade = ArcadeData(self.config, self.session)
self.card = CardData(self.config, self.session)
self.base = BaseData(self.config, self.session)
self.schema_ver_latest = 4
if Data.session is None:
s = sessionmaker(bind=Data.engine, autoflush=True, autocommit=True)
Data.session = scoped_session(s)
if Data.user is None:
Data.user = UserData(self.config, self.session)
if Data.arcade is None:
Data.arcade = ArcadeData(self.config, self.session)
if Data.card is None:
Data.card = CardData(self.config, self.session)
if Data.base is None:
Data.base = BaseData(self.config, self.session)
log_fmt_str = "[%(asctime)s] %(levelname)s | Database | %(message)s"
log_fmt = logging.Formatter(log_fmt_str)
self.logger = logging.getLogger("database")
# Prevent the logger from adding handlers multiple times
if not getattr(self.logger, "handler_set", None):
log_fmt_str = "[%(asctime)s] %(levelname)s | Database | %(message)s"
log_fmt = logging.Formatter(log_fmt_str)
fileHandler = TimedRotatingFileHandler(
"{0}/{1}.log".format(self.config.server.log_dir, "db"),
encoding="utf-8",
@@ -60,220 +77,173 @@ class Data:
)
self.logger.handler_set = True # type: ignore
def __alembic_cmd(self, command: str, *args: str) -> None:
old_dir = os.path.abspath(os.path.curdir)
base_dir = os.path.join(os.path.abspath(os.path.curdir), 'core', 'data', 'alembic')
alembicArgs = [
"-c",
os.path.join(base_dir, "alembic.ini"),
"-x",
f"script_location={base_dir}",
"-x",
f"sqlalchemy.url={self.__url}",
command,
]
alembicArgs.extend(args)
os.chdir(base_dir)
alembic.config.main(argv=alembicArgs)
os.chdir(old_dir)
def create_database(self):
self.logger.info("Creating databases...")
try:
metadata.create_all(self.__engine.connect())
except SQLAlchemyError as e:
self.logger.error(f"Failed to create databases! {e}")
return
games = Utils.get_all_titles()
for game_dir, game_mod in games.items():
try:
if hasattr(game_mod, "database") and hasattr(game_mod, "current_schema_version"):
game_mod.database(self.config)
metadata.create_all(self.__engine.connect())
self.base.set_schema_ver(
game_mod.current_schema_version, game_mod.game_codes[0]
)
except Exception as e:
self.logger.warning(
f"Could not load database schema from {game_dir} - {e}"
)
self.logger.info(f"Setting base_schema_ver to {self.schema_ver_latest}")
self.base.set_schema_ver(self.schema_ver_latest)
self.logger.info(
f"Setting user auto_incrememnt to {self.config.database.user_table_autoincrement_start}"
)
self.user.reset_autoincrement(
self.config.database.user_table_autoincrement_start
metadata.create_all(
self.engine,
checkfirst=True,
)
def recreate_database(self):
self.logger.info("Dropping all databases...")
self.base.execute("SET FOREIGN_KEY_CHECKS=0")
try:
metadata.drop_all(self.__engine.connect())
except SQLAlchemyError as e:
self.logger.error(f"Failed to drop databases! {e}")
return
for _, mod in Utils.get_all_titles().items():
if hasattr(mod, "database"):
mod.database(self.config)
metadata.create_all(
self.engine,
checkfirst=True,
)
for root, dirs, files in os.walk("./titles"):
for dir in dirs:
if not dir.startswith("__"):
try:
mod = importlib.import_module(f"titles.{dir}")
# Stamp the end revision as if alembic had created it, so it can take off after this.
self.__alembic_cmd(
"stamp",
"head",
)
try:
if hasattr(mod, "database"):
mod.database(self.config)
metadata.drop_all(self.__engine.connect())
def schema_upgrade(self, ver: str = None):
self.__alembic_cmd(
"upgrade",
"head" if not ver else ver,
)
except Exception as e:
self.logger.warning(
f"Could not load database schema from {dir} - {e}"
)
def schema_downgrade(self, ver: str):
self.__alembic_cmd(
"downgrade",
ver,
)
except ImportError as e:
self.logger.warning(
f"Failed to load database schema dir {dir} - {e}"
)
break
self.base.execute("SET FOREIGN_KEY_CHECKS=1")
self.create_database()
def migrate_database(self, game: str, version: int, action: str) -> None:
old_ver = self.base.get_schema_ver(game)
sql = ""
if old_ver is None:
self.logger.error(
f"Schema for game {game} does not exist, did you run the creation script?"
)
return
if old_ver == version:
self.logger.info(
f"Schema for game {game} is already version {old_ver}, nothing to do"
)
return
if action == "upgrade":
for x in range(old_ver, version):
if not os.path.exists(
f"core/data/schema/versions/{game.upper()}_{x + 1}_{action}.sql"
):
self.logger.error(
f"Could not find {action} script {game.upper()}_{x + 1}_{action}.sql in core/data/schema/versions folder"
)
return
with open(
f"core/data/schema/versions/{game.upper()}_{x + 1}_{action}.sql",
"r",
encoding="utf-8",
) as f:
sql = f.read()
result = self.base.execute(sql)
if result is None:
self.logger.error("Error execuing sql script!")
return None
else:
for x in range(old_ver, version, -1):
if not os.path.exists(
f"core/data/schema/versions/{game.upper()}_{x - 1}_{action}.sql"
):
self.logger.error(
f"Could not find {action} script {game.upper()}_{x - 1}_{action}.sql in core/data/schema/versions folder"
)
return
with open(
f"core/data/schema/versions/{game.upper()}_{x - 1}_{action}.sql",
"r",
encoding="utf-8",
) as f:
sql = f.read()
result = self.base.execute(sql)
if result is None:
self.logger.error("Error execuing sql script!")
return None
result = self.base.set_schema_ver(version, game)
if result is None:
self.logger.error("Error setting version in schema_version table!")
return None
self.logger.info(f"Successfully migrated {game} to schema version {version}")
def create_owner(self, email: Optional[str] = None) -> None:
async def create_owner(self, email: Optional[str] = None, code: Optional[str] = "00000000000000000000") -> None:
pw = "".join(
secrets.choice(string.ascii_letters + string.digits) for i in range(20)
)
hash = bcrypt.hashpw(pw.encode(), bcrypt.gensalt())
user_id = self.user.create_user(email=email, permission=255, password=hash)
user_id = await self.user.create_user(username="sysowner", email=email, password=hash.decode(), permission=255)
if user_id is None:
self.logger.error(f"Failed to create owner with email {email}")
return
card_id = self.card.create_card(user_id, "00000000000000000000")
card_id = await self.card.create_card(user_id, code)
if card_id is None:
self.logger.error(f"Failed to create card for owner with id {user_id}")
return
self.logger.warn(
f"Successfully created owner with email {email}, access code 00000000000000000000, and password {pw} Make sure to change this password and assign a real card ASAP!"
self.logger.warning(
f"Successfully created owner with email {email}, access code {code}, and password {pw} Make sure to change this password and assign a real card ASAP!"
)
def migrate_card(self, old_ac: str, new_ac: str, should_force: bool) -> None:
if old_ac == new_ac:
self.logger.error("Both access codes are the same!")
async def migrate(self) -> None:
exist = await self.base.execute("SELECT * FROM alembic_version")
if exist is not None:
self.logger.warn("No need to migrate as you have already migrated to alembic. If you are trying to upgrade the schema, use `upgrade` instead!")
return
new_card = self.card.get_card_by_access_code(new_ac)
if new_card is None:
self.card.update_access_code(old_ac, new_ac)
self.logger.info("Upgrading to latest with legacy system")
if not await self.legacy_upgrade():
self.logger.warn("No need to migrate as you have already deleted the old schema_versions system. If you are trying to upgrade the schema, use `upgrade` instead!")
return
self.logger.info("Done")
if not should_force:
self.logger.warn(
f"Card already exists for access code {new_ac} (id {new_card['id']}). If you wish to continue, rerun with the '--force' flag."
f" All exiting data on the target card {new_ac} will be perminently erased and replaced with data from card {old_ac}."
)
return
self.logger.info(
f"All exiting data on the target card {new_ac} will be perminently erased and replaced with data from card {old_ac}."
self.logger.info("Stamp with initial revision")
self.__alembic_cmd(
"stamp",
"835b862f9bf0",
)
self.card.delete_card(new_card["id"])
self.card.update_access_code(old_ac, new_ac)
hanging_user = self.user.get_user(new_card["user"])
if hanging_user["password"] is None:
self.logger.info(f"Delete hanging user {hanging_user['id']}")
self.user.delete_user(hanging_user["id"])
self.logger.info("Upgrade")
self.__alembic_cmd(
"upgrade",
"head",
)
def delete_hanging_users(self) -> None:
"""
Finds and deletes users that have not registered for the webui that have no cards assocated with them.
"""
unreg_users = self.user.get_unregistered_users()
if unreg_users is None:
self.logger.error("Error occoured finding unregistered users")
async def legacy_upgrade(self) -> bool:
vers = await self.base.execute("SELECT * FROM schema_versions")
if vers is None:
self.logger.warn("Cannot legacy upgrade, schema_versions table unavailable!")
return False
for user in unreg_users:
cards = self.card.get_user_cards(user["id"])
if cards is None:
self.logger.error(f"Error getting cards for user {user['id']}")
continue
db_vers = {}
vers_list = vers.fetchall()
for x in vers_list:
db_vers[x['game']] = x['version']
if not cards:
self.logger.info(f"Delete hanging user {user['id']}")
self.user.delete_user(user["id"])
core_now_ver = int(db_vers['CORE']) + 1
while os.path.exists(f"core/data/schema/versions/CORE_{core_now_ver}_upgrade.sql"):
with open(f"core/data/schema/versions/CORE_{core_now_ver}_upgrade.sql", "r") as f:
result = await self.base.execute(f.read())
def autoupgrade(self) -> None:
all_games = self.base.get_all_schema_vers()
if all_games is None:
self.logger.warn("Failed to get schema versions")
for x in all_games:
game = x["game"].upper()
update_ver = 1
for y in range(2, 100):
if os.path.exists(f"core/data/schema/versions/{game}_{y}_upgrade.sql"):
update_ver = y
else:
if result is None:
self.logger.error(f"Invalid upgrade script CORE_{core_now_ver}_upgrade.sql")
break
self.migrate_database(game, update_ver, "upgrade")
result = await self.base.execute(f"UPDATE schema_versions SET version = {core_now_ver} WHERE game = 'CORE'")
if result is None:
self.logger.error(f"Failed to update schema version for CORE to {core_now_ver}")
break
self.logger.info(f"Upgrade CORE to version {core_now_ver}")
core_now_ver += 1
for _, mod in Utils.get_all_titles().items():
game_codes = getattr(mod, "game_codes", [])
for game in game_codes:
if game not in db_vers:
self.logger.warn(f"{game} does not have an antry in schema_versions, skipping")
continue
now_ver = int(db_vers[game]) + 1
while os.path.exists(f"core/data/schema/versions/{game}_{now_ver}_upgrade.sql"):
with open(f"core/data/schema/versions/{game}_{now_ver}_upgrade.sql", "r") as f:
result = await self.base.execute(f.read())
if result is None:
self.logger.error(f"Invalid upgrade script {game}_{now_ver}_upgrade.sql")
break
result = await self.base.execute(f"UPDATE schema_versions SET version = {now_ver} WHERE game = '{game}'")
if result is None:
self.logger.error(f"Failed to update schema version for {game} to {now_ver}")
break
self.logger.info(f"Upgrade {game} to version {now_ver}")
now_ver += 1
return True
async def create_revision(self, message: str) -> None:
if not message:
self.logger.info("Message is required for create-revision")
return
self.__alembic_cmd(
"revision",
"-m",
message,
)
async def create_revision_auto(self, message: str) -> None:
if not message:
self.logger.info("Message is required for create-revision")
return
self.__alembic_cmd(
"revision",
"--autogenerate",
"-m",
message,
)
+60 -47
View File
@@ -1,9 +1,10 @@
from typing import Optional, Dict
from sqlalchemy import Table, Column
from typing import Optional, Dict, List
from sqlalchemy import Table, Column, and_, or_
from sqlalchemy.sql.schema import ForeignKey, PrimaryKeyConstraint
from sqlalchemy.types import Integer, String, Boolean
from sqlalchemy.types import Integer, String, Boolean, JSON
from sqlalchemy.sql import func, select
from sqlalchemy.dialects.mysql import insert
from sqlalchemy.engine import Row
import re
from core.data.schema.base import BaseData, metadata
@@ -21,6 +22,7 @@ arcade = Table(
Column("city", String(255)),
Column("region_id", Integer),
Column("timezone", String(255)),
Column("ip", String(39)),
mysql_charset="utf8mb4",
)
@@ -39,7 +41,9 @@ machine = Table(
Column("country", String(3)), # overwrites if not null
Column("timezone", String(255)),
Column("ota_enable", Boolean),
Column("memo", String(255)),
Column("is_cab", Boolean),
Column("data", JSON),
mysql_charset="utf8mb4",
)
@@ -65,7 +69,7 @@ arcade_owner = Table(
class ArcadeData(BaseData):
def get_machine(self, serial: str = None, id: int = None) -> Optional[Dict]:
async def get_machine(self, serial: str = None, id: int = None) -> Optional[Row]:
if serial is not None:
serial = serial.replace("-", "")
if len(serial) == 11:
@@ -85,12 +89,12 @@ class ArcadeData(BaseData):
self.logger.error(f"{__name__ }: Need either serial or ID to look up!")
return None
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchone()
def put_machine(
async def put_machine(
self,
arcade_id: int,
serial: str = "",
@@ -106,13 +110,13 @@ class ArcadeData(BaseData):
arcade=arcade_id, keychip=serial, board=board, game=game, is_cab=is_cab
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.lastrowid
def set_machine_serial(self, machine_id: int, serial: str) -> None:
result = self.execute(
async def set_machine_serial(self, machine_id: int, serial: str) -> None:
result = await self.execute(
machine.update(machine.c.id == machine_id).values(keychip=serial)
)
if result is None:
@@ -121,8 +125,8 @@ class ArcadeData(BaseData):
)
return result.lastrowid
def set_machine_boardid(self, machine_id: int, boardid: str) -> None:
result = self.execute(
async def set_machine_boardid(self, machine_id: int, boardid: str) -> None:
result = await self.execute(
machine.update(machine.c.id == machine_id).values(board=boardid)
)
if result is None:
@@ -130,14 +134,21 @@ class ArcadeData(BaseData):
f"Failed to update board id for machine {machine_id} -> {boardid}"
)
def get_arcade(self, id: int) -> Optional[Dict]:
async def get_arcade(self, id: int) -> Optional[Row]:
sql = arcade.select(arcade.c.id == id)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchone()
def put_arcade(
async def get_arcade_machines(self, id: int) -> Optional[List[Row]]:
sql = machine.select(machine.c.arcade == id)
result = await self.execute(sql)
if result is None:
return None
return result.fetchall()
async def put_arcade(
self,
name: str,
nickname: str = None,
@@ -160,60 +171,62 @@ class ArcadeData(BaseData):
regional_id=regional_id,
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.lastrowid
def get_arcade_owners(self, arcade_id: int) -> Optional[Dict]:
async def get_arcades_managed_by_user(self, user_id: int) -> Optional[List[Row]]:
sql = select(arcade).join(arcade_owner, arcade_owner.c.arcade == arcade.c.id).where(arcade_owner.c.user == user_id)
result = await self.execute(sql)
if result is None:
return False
return result.fetchall()
async def get_manager_permissions(self, user_id: int, arcade_id: int) -> Optional[int]:
sql = select(arcade_owner.c.permissions).where(and_(arcade_owner.c.user == user_id, arcade_owner.c.arcade == arcade_id))
result = await self.execute(sql)
if result is None:
return False
return result.fetchone()
async def get_arcade_owners(self, arcade_id: int) -> Optional[Row]:
sql = select(arcade_owner).where(arcade_owner.c.arcade == arcade_id)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchall()
def add_arcade_owner(self, arcade_id: int, user_id: int) -> None:
async def add_arcade_owner(self, arcade_id: int, user_id: int) -> None:
sql = insert(arcade_owner).values(arcade=arcade_id, user=user_id)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.lastrowid
def format_serial(
async def format_serial(
self, platform_code: str, platform_rev: int, serial_num: int, append: int = 4152
) -> str:
return f"{platform_code}{platform_rev:02d}A{serial_num:04d}{append:04d}" # 0x41 = A, 0x52 = R
def validate_keychip_format(self, serial: str) -> bool:
serial = serial.replace("-", "")
if len(serial) != 11 or len(serial) != 15:
self.logger.error(
f"Serial validate failed: Incorrect length for {serial} (len {len(serial)})"
)
return False
platform_code = serial[:4]
platform_rev = serial[4:6]
const_a = serial[6]
num = serial[7:11]
append = serial[11:15]
if re.match("A[7|6]\d[E|X][0|1][0|1|2]A\d{4,8}", serial) is None:
self.logger.error(f"Serial validate failed: {serial} failed regex")
return False
if len(append) != 0 or len(append) != 4:
self.logger.error(
f"Serial validate failed: {serial} had malformed append {append}"
)
return False
if len(num) != 4:
self.logger.error(
f"Serial validate failed: {serial} had malformed number {num}"
)
if re.fullmatch(r"^A[0-9]{2}[E|X][-]?[0-9]{2}[A-HJ-NP-Z][0-9]{4}([0-9]{4})?$", serial) is None:
return False
return True
async def get_arcade_by_name(self, name: str) -> Optional[List[Row]]:
sql = arcade.select(or_(arcade.c.name.like(f"%{name}%"), arcade.c.nickname.like(f"%{name}%")))
result = await self.execute(sql)
if result is None:
return None
return result.fetchall()
async def get_arcades_by_ip(self, ip: str) -> Optional[List[Row]]:
sql = arcade.select().where(arcade.c.ip == ip)
result = await self.execute(sql)
if result is None:
return None
return result.fetchall()
+10 -49
View File
@@ -15,14 +15,6 @@ from core.config import CoreConfig
metadata = MetaData()
schema_ver = Table(
"schema_versions",
metadata,
Column("game", String(4), primary_key=True, nullable=False),
Column("version", Integer, nullable=False, server_default="1"),
mysql_charset="utf8mb4",
)
event_log = Table(
"event_log",
metadata,
@@ -43,11 +35,11 @@ class BaseData:
self.conn = conn
self.logger = logging.getLogger("database")
def execute(self, sql: str, opts: Dict[str, Any] = {}) -> Optional[CursorResult]:
async def execute(self, sql: str, opts: Dict[str, Any] = {}) -> Optional[CursorResult]:
res = None
try:
self.logger.info(f"SQL Execute: {''.join(str(sql).splitlines())} || {opts}")
self.logger.debug(f"SQL Execute: {''.join(str(sql).splitlines())}")
res = self.conn.execute(text(sql), opts)
except SQLAlchemyError as e:
@@ -58,7 +50,7 @@ class BaseData:
self.logger.error(f"UnicodeEncodeError error {e}")
return None
except:
except Exception:
try:
res = self.conn.execute(sql, opts)
@@ -70,7 +62,7 @@ class BaseData:
self.logger.error(f"UnicodeEncodeError error {e}")
return None
except:
except Exception:
self.logger.error(f"Unknown error")
raise
@@ -82,40 +74,7 @@ class BaseData:
"""
return randrange(10000, 9999999)
def get_all_schema_vers(self) -> Optional[List[Row]]:
sql = select(schema_ver)
result = self.execute(sql)
if result is None:
return None
return result.fetchall()
def get_schema_ver(self, game: str) -> Optional[int]:
sql = select(schema_ver).where(schema_ver.c.game == game)
result = self.execute(sql)
if result is None:
return None
row = result.fetchone()
if row is None:
return None
return row["version"]
def set_schema_ver(self, ver: int, game: str = "CORE") -> Optional[int]:
sql = insert(schema_ver).values(game=game, version=ver)
conflict = sql.on_duplicate_key_update(version=ver)
result = self.execute(conflict)
if result is None:
self.logger.error(
f"Failed to update schema version for game {game} (v{ver})"
)
return None
return result.lastrowid
def log_event(
async def log_event(
self, system: str, type: str, severity: int, message: str, details: Dict = {}
) -> Optional[int]:
sql = event_log.insert().values(
@@ -125,7 +84,7 @@ class BaseData:
message=message,
details=json.dumps(details),
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
self.logger.error(
@@ -135,9 +94,9 @@ class BaseData:
return result.lastrowid
def get_event_log(self, entries: int = 100) -> Optional[List[Dict]]:
async def get_event_log(self, entries: int = 100) -> Optional[List[Dict]]:
sql = event_log.select().limit(entries).all()
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
@@ -145,6 +104,8 @@ class BaseData:
def fix_bools(self, data: Dict) -> Dict:
for k, v in data.items():
if k == "userName" or k == "teamName":
continue
if type(v) == str and v.lower() == "true":
data[k] = True
elif type(v) == str and v.lower() == "false":
+45 -14
View File
@@ -27,70 +27,101 @@ aime_card = Table(
class CardData(BaseData):
def get_card_by_access_code(self, access_code: str) -> Optional[Row]:
async def get_card_by_access_code(self, access_code: str) -> Optional[Row]:
sql = aime_card.select(aime_card.c.access_code == access_code)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchone()
def get_card_by_id(self, card_id: int) -> Optional[Row]:
async def get_card_by_id(self, card_id: int) -> Optional[Row]:
sql = aime_card.select(aime_card.c.id == card_id)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchone()
def update_access_code(self, old_ac: str, new_ac: str) -> None:
async def update_access_code(self, old_ac: str, new_ac: str) -> None:
sql = aime_card.update(aime_card.c.access_code == old_ac).values(
access_code=new_ac
)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
self.logger.error(
f"Failed to change card access code from {old_ac} to {new_ac}"
)
def get_user_id_from_card(self, access_code: str) -> Optional[int]:
async def get_user_id_from_card(self, access_code: str) -> Optional[int]:
"""
Given a 20 digit access code as a string, get the user id associated with that card
"""
card = self.get_card_by_access_code(access_code)
card = await self.get_card_by_access_code(access_code)
if card is None:
return None
return int(card["user"])
def delete_card(self, card_id: int) -> None:
async def get_card_banned(self, access_code: str) -> Optional[bool]:
"""
Given a 20 digit access code as a string, check if the card is banned
"""
card = await self.get_card_by_access_code(access_code)
if card is None:
return None
if card["is_banned"]:
return True
return False
async def get_card_locked(self, access_code: str) -> Optional[bool]:
"""
Given a 20 digit access code as a string, check if the card is locked
"""
card = await self.get_card_by_access_code(access_code)
if card is None:
return None
if card["is_locked"]:
return True
return False
async def delete_card(self, card_id: int) -> None:
sql = aime_card.delete(aime_card.c.id == card_id)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
self.logger.error(f"Failed to delete card with id {card_id}")
def get_user_cards(self, aime_id: int) -> Optional[List[Row]]:
async def get_user_cards(self, aime_id: int) -> Optional[List[Row]]:
"""
Returns all cards owned by a user
"""
sql = aime_card.select(aime_card.c.user == aime_id)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchall()
def create_card(self, user_id: int, access_code: str) -> Optional[int]:
async def create_card(self, user_id: int, access_code: str) -> Optional[int]:
"""
Given a aime_user id and a 20 digit access code as a string, create a card and return the ID if successful
"""
sql = aime_card.insert().values(user=user_id, access_code=access_code)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.lastrowid
async def update_card_last_login(self, access_code: str) -> None:
sql = aime_card.update(aime_card.c.access_code == access_code).values(
last_login_date=func.now()
)
result = await self.execute(sql)
if result is None:
self.logger.warn(f"Failed to update last login time for {access_code}")
def to_access_code(self, luid: str) -> str:
"""
Given a felica cards internal 16 hex character luid, convert it to a 0-padded 20 digit access code as a string
+39 -23
View File
@@ -1,4 +1,3 @@
from enum import Enum
from typing import Optional, List
from sqlalchemy import Table, Column
from sqlalchemy.types import Integer, String, TIMESTAMP
@@ -24,15 +23,8 @@ aime_user = Table(
mysql_charset="utf8mb4",
)
class PermissionBits(Enum):
PermUser = 1
PermMod = 2
PermSysAdmin = 4
class UserData(BaseData):
def create_user(
async def create_user(
self,
id: int = None,
username: str = None,
@@ -60,47 +52,71 @@ class UserData(BaseData):
username=username, email=email, password=password, permissions=permission
)
result = self.execute(conflict)
result = await self.execute(conflict)
if result is None:
return None
return result.lastrowid
def get_user(self, user_id: int) -> Optional[Row]:
async def get_user(self, user_id: int) -> Optional[Row]:
sql = select(aime_user).where(aime_user.c.id == user_id)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return False
return result.fetchone()
def check_password(self, user_id: int, passwd: bytes = None) -> bool:
usr = self.get_user(user_id)
async def check_password(self, user_id: int, passwd: bytes = None) -> bool:
usr = await self.get_user(user_id)
if usr is None:
return False
if usr["password"] is None:
return False
if passwd is None or not passwd:
return False
return bcrypt.checkpw(passwd, usr["password"].encode())
def reset_autoincrement(self, ai_value: int) -> None:
# ALTER TABLE isn't in sqlalchemy so we do this the ugly way
sql = f"ALTER TABLE aime_user AUTO_INCREMENT={ai_value}"
self.execute(sql)
def delete_user(self, user_id: int) -> None:
async def delete_user(self, user_id: int) -> None:
sql = aime_user.delete(aime_user.c.id == user_id)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
self.logger.error(f"Failed to delete user with id {user_id}")
def get_unregistered_users(self) -> List[Row]:
async def get_unregistered_users(self) -> List[Row]:
"""
Returns a list of users who have not registered with the webui. They may or may not have cards.
"""
sql = select(aime_user).where(aime_user.c.password == None)
result = self.execute(sql)
result = await self.execute(sql)
if result is None:
return None
return result.fetchall()
async def find_user_by_email(self, email: str) -> Row:
sql = select(aime_user).where(aime_user.c.email == email)
result = await self.execute(sql)
if result is None:
return False
return result.fetchone()
async def find_user_by_username(self, username: str) -> List[Row]:
sql = aime_user.select(aime_user.c.username.like(f"%{username}%"))
result = await self.execute(sql)
if result is None:
return False
return result.fetchall()
async def change_password(self, user_id: int, new_passwd: str) -> bool:
sql = aime_user.update(aime_user.c.id == user_id).values(password = new_passwd)
result = await self.execute(sql)
return result is not None
async def change_username(self, user_id: int, new_name: str) -> bool:
sql = aime_user.update(aime_user.c.id == user_id).values(username = new_name)
result = await self.execute(sql)
return result is not None
@@ -0,0 +1,3 @@
ALTER TABLE machine DROP COLUMN memo;
ALTER TABLE machine DROP COLUMN is_blacklisted;
ALTER TABLE machine DROP COLUMN `data`;
@@ -0,0 +1 @@
ALTER TABLE arcade DROP COLUMN 'ip';
@@ -0,0 +1,3 @@
ALTER TABLE machine ADD memo varchar(255) NULL;
ALTER TABLE machine ADD is_blacklisted tinyint(1) NULL;
ALTER TABLE machine ADD `data` longtext NULL;
@@ -0,0 +1 @@
ALTER TABLE arcade ADD ip varchar(39) NULL;
@@ -0,0 +1,9 @@
ALTER TABLE diva_profile
DROP cnp_cid,
DROP cnp_val,
DROP cnp_rr,
DROP cnp_sp,
DROP btn_se_eqp,
DROP sld_se_eqp,
DROP chn_sld_se_eqp,
DROP sldr_tch_se_eqp;
@@ -0,0 +1,2 @@
ALTER TABLE diva_profile
DROP skn_eqp;
@@ -0,0 +1,9 @@
ALTER TABLE diva_profile
ADD cnp_cid INT NOT NULL DEFAULT -1,
ADD cnp_val INT NOT NULL DEFAULT -1,
ADD cnp_rr INT NOT NULL DEFAULT -1,
ADD cnp_sp VARCHAR(255) NOT NULL DEFAULT "",
ADD btn_se_eqp INT NOT NULL DEFAULT -1,
ADD sld_se_eqp INT NOT NULL DEFAULT -1,
ADD chn_sld_se_eqp INT NOT NULL DEFAULT -1,
ADD sldr_tch_se_eqp INT NOT NULL DEFAULT -1;
@@ -0,0 +1,2 @@
ALTER TABLE diva_profile
ADD skn_eqp INT NOT NULL DEFAULT 0;
@@ -0,0 +1,30 @@
SET FOREIGN_KEY_CHECKS = 0;
ALTER TABLE chuni_score_playlog
DROP COLUMN regionId,
DROP COLUMN machineType;
ALTER TABLE chuni_static_events
DROP COLUMN startDate;
ALTER TABLE chuni_profile_data
DROP COLUMN rankUpChallengeResults;
ALTER TABLE chuni_static_login_bonus
DROP FOREIGN KEY chuni_static_login_bonus_ibfk_1;
ALTER TABLE chuni_static_login_bonus_preset
DROP PRIMARY KEY;
ALTER TABLE chuni_static_login_bonus_preset
CHANGE COLUMN presetId id INT NOT NULL;
ALTER TABLE chuni_static_login_bonus_preset
ADD PRIMARY KEY(id);
ALTER TABLE chuni_static_login_bonus_preset
ADD CONSTRAINT chuni_static_login_bonus_preset_uk UNIQUE(id, version);
ALTER TABLE chuni_static_login_bonus
ADD CONSTRAINT chuni_static_login_bonus_ibfk_1 FOREIGN KEY(presetId)
REFERENCES chuni_static_login_bonus_preset(id) ON UPDATE CASCADE ON DELETE CASCADE;
SET FOREIGN_KEY_CHECKS = 1;
@@ -0,0 +1,12 @@
SET FOREIGN_KEY_CHECKS = 0;
ALTER TABLE chuni_score_playlog
CHANGE COLUMN isClear isClear TINYINT(1) NULL DEFAULT NULL;
ALTER TABLE chuni_score_best
CHANGE COLUMN isSuccess isSuccess TINYINT(1) NULL DEFAULT NULL ;
ALTER TABLE chuni_score_playlog
DROP COLUMN ticketId;
SET FOREIGN_KEY_CHECKS = 1;
@@ -0,0 +1,29 @@
SET FOREIGN_KEY_CHECKS = 0;
ALTER TABLE chuni_score_playlog
ADD COLUMN regionId INT,
ADD COLUMN machineType INT;
ALTER TABLE chuni_static_events
ADD COLUMN startDate TIMESTAMP NOT NULL DEFAULT current_timestamp();
ALTER TABLE chuni_profile_data
ADD COLUMN rankUpChallengeResults JSON;
ALTER TABLE chuni_static_login_bonus
DROP FOREIGN KEY chuni_static_login_bonus_ibfk_1;
ALTER TABLE chuni_static_login_bonus_preset
CHANGE COLUMN id presetId INT NOT NULL;
ALTER TABLE chuni_static_login_bonus_preset
DROP PRIMARY KEY;
ALTER TABLE chuni_static_login_bonus_preset
DROP INDEX chuni_static_login_bonus_preset_uk;
ALTER TABLE chuni_static_login_bonus_preset
ADD CONSTRAINT chuni_static_login_bonus_preset_pk PRIMARY KEY (presetId, version);
ALTER TABLE chuni_static_login_bonus
ADD CONSTRAINT chuni_static_login_bonus_ibfk_1 FOREIGN KEY (presetId, version)
REFERENCES chuni_static_login_bonus_preset(presetId, version) ON UPDATE CASCADE ON DELETE CASCADE;
SET FOREIGN_KEY_CHECKS = 1;
@@ -0,0 +1,12 @@
SET FOREIGN_KEY_CHECKS = 0;
ALTER TABLE chuni_score_playlog
CHANGE COLUMN isClear isClear TINYINT(6) NULL DEFAULT NULL;
ALTER TABLE chuni_score_best
CHANGE COLUMN isSuccess isSuccess INT(11) NULL DEFAULT NULL ;
ALTER TABLE chuni_score_playlog
ADD COLUMN ticketId INT(11) NULL AFTER machineType;
SET FOREIGN_KEY_CHECKS = 1;
@@ -0,0 +1,2 @@
ALTER TABLE ongeki_static_events
DROP COLUMN startDate;
@@ -0,0 +1,22 @@
SET FOREIGN_KEY_CHECKS=0;
ALTER TABLE ongeki_user_event_point DROP COLUMN version;
ALTER TABLE ongeki_user_event_point DROP COLUMN `rank`;
ALTER TABLE ongeki_user_event_point DROP COLUMN `type`;
ALTER TABLE ongeki_user_event_point DROP COLUMN date;
ALTER TABLE ongeki_user_tech_event DROP COLUMN version;
ALTER TABLE ongeki_user_mission_point DROP COLUMN version;
ALTER TABLE ongeki_static_events DROP COLUMN endDate;
DROP TABLE ongeki_tech_event_ranking;
DROP TABLE ongeki_static_music_ranking_list;
DROP TABLE ongeki_static_rewards;
DROP TABLE ongeki_static_present_list;
DROP TABLE ongeki_static_tech_music;
DROP TABLE ongeki_static_client_testmode;
DROP TABLE ongeki_static_game_point;
SET FOREIGN_KEY_CHECKS=1;
@@ -0,0 +1,2 @@
ALTER TABLE ongeki_static_events
ADD COLUMN startDate TIMESTAMP NOT NULL DEFAULT current_timestamp();
@@ -0,0 +1,98 @@
SET FOREIGN_KEY_CHECKS=0;
ALTER TABLE ongeki_user_event_point ADD COLUMN version INTEGER NOT NULL;
ALTER TABLE ongeki_user_event_point ADD COLUMN `rank` INTEGER;
ALTER TABLE ongeki_user_event_point ADD COLUMN `type` INTEGER NOT NULL;
ALTER TABLE ongeki_user_event_point ADD COLUMN date VARCHAR(25);
ALTER TABLE ongeki_user_tech_event ADD COLUMN version INTEGER NOT NULL;
ALTER TABLE ongeki_user_mission_point ADD COLUMN version INTEGER NOT NULL;
ALTER TABLE ongeki_static_events ADD COLUMN endDate TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
CREATE TABLE ongeki_tech_event_ranking (
id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
user INT NOT NULL,
version INT NOT NULL,
date VARCHAR(25),
eventId INT NOT NULL,
`rank` INT,
totalPlatinumScore INT NOT NULL,
totalTechScore INT NOT NULL,
UNIQUE KEY ongeki_tech_event_ranking_uk (user, eventId),
CONSTRAINT ongeki_tech_event_ranking_ibfk1 FOREIGN KEY (user) REFERENCES aime_user(id) ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE TABLE ongeki_static_music_ranking_list (
id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
version INT NOT NULL,
musicId INT NOT NULL,
point INT NOT NULL,
userName VARCHAR(255),
UNIQUE KEY ongeki_static_music_ranking_list_uk (version, musicId)
);
CREATE TABLE ongeki_static_rewards (
id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
version INT NOT NULL,
rewardId INT NOT NULL,
rewardName VARCHAR(255) NOT NULL,
itemKind INT NOT NULL,
itemId INT NOT NULL,
UNIQUE KEY ongeki_tech_event_ranking_uk (version, rewardId)
);
CREATE TABLE ongeki_static_present_list (
id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
version INT NOT NULL,
presentId INT NOT NULL,
presentName VARCHAR(255) NOT NULL,
rewardId INT NOT NULL,
stock INT NOT NULL,
message VARCHAR(255),
startDate VARCHAR(25) NOT NULL,
endDate VARCHAR(25) NOT NULL,
UNIQUE KEY ongeki_static_present_list_uk (version, presentId, rewardId)
);
CREATE TABLE ongeki_static_tech_music (
id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
version INT NOT NULL,
eventId INT NOT NULL,
musicId INT NOT NULL,
level INT NOT NULL,
UNIQUE KEY ongeki_static_tech_music_uk (version, musicId, eventId)
);
CREATE TABLE ongeki_static_client_testmode (
id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
regionId INT NOT NULL,
placeId INT NOT NULL,
clientId VARCHAR(11) NOT NULL,
updateDate TIMESTAMP NOT NULL,
isDelivery BOOLEAN NOT NULL,
groupId INT NOT NULL,
groupRole INT NOT NULL,
continueMode INT NOT NULL,
selectMusicTime INT NOT NULL,
advertiseVolume INT NOT NULL,
eventMode INT NOT NULL,
eventMusicNum INT NOT NULL,
patternGp INT NOT NULL,
limitGp INT NOT NULL,
maxLeverMovable INT NOT NULL,
minLeverMovable INT NOT NULL,
UNIQUE KEY ongeki_static_client_testmode_uk (clientId)
);
CREATE TABLE ongeki_static_game_point (
id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
`type` INT NOT NULL,
cost INT NOT NULL,
startDate VARCHAR(25) NOT NULL DEFAULT "2000-01-01 05:00:00.0",
endDate VARCHAR(25) NOT NULL DEFAULT "2099-01-01 05:00:00.0",
UNIQUE KEY ongeki_static_game_point_uk (`type`)
);
SET FOREIGN_KEY_CHECKS=1;
@@ -0,0 +1,3 @@
ALTER TABLE mai2_item_card
CHANGE COLUMN startDate startDate TIMESTAMP DEFAULT "2018-01-01 00:00:00.0",
CHANGE COLUMN endDate endDate TIMESTAMP DEFAULT "2038-01-01 00:00:00.0";
@@ -0,0 +1,78 @@
DELETE FROM mai2_static_event WHERE version < 13;
UPDATE mai2_static_event SET version = version - 13 WHERE version >= 13;
DELETE FROM mai2_static_music WHERE version < 13;
UPDATE mai2_static_music SET version = version - 13 WHERE version >= 13;
DELETE FROM mai2_static_ticket WHERE version < 13;
UPDATE mai2_static_ticket SET version = version - 13 WHERE version >= 13;
DELETE FROM mai2_static_cards WHERE version < 13;
UPDATE mai2_static_cards SET version = version - 13 WHERE version >= 13;
DELETE FROM mai2_profile_detail WHERE version < 13;
UPDATE mai2_profile_detail SET version = version - 13 WHERE version >= 13;
DELETE FROM mai2_profile_extend WHERE version < 13;
UPDATE mai2_profile_extend SET version = version - 13 WHERE version >= 13;
DELETE FROM mai2_profile_option WHERE version < 13;
UPDATE mai2_profile_option SET version = version - 13 WHERE version >= 13;
DELETE FROM mai2_profile_ghost WHERE version < 13;
UPDATE mai2_profile_ghost SET version = version - 13 WHERE version >= 13;
DELETE FROM mai2_profile_rating WHERE version < 13;
UPDATE mai2_profile_rating SET version = version - 13 WHERE version >= 13;
DROP TABLE maimai_score_best;
DROP TABLE maimai_playlog;
DROP TABLE maimai_profile_detail;
DROP TABLE maimai_profile_option;
DROP TABLE maimai_profile_web_option;
DROP TABLE maimai_profile_grade_status;
ALTER TABLE mai2_item_character DROP COLUMN point;
ALTER TABLE mai2_item_card MODIFY COLUMN cardId int(11) NOT NULL;
ALTER TABLE mai2_item_card MODIFY COLUMN cardTypeId int(11) NOT NULL;
ALTER TABLE mai2_item_card MODIFY COLUMN charaId int(11) NOT NULL;
ALTER TABLE mai2_item_card MODIFY COLUMN mapId int(11) NOT NULL;
ALTER TABLE mai2_item_character MODIFY COLUMN characterId int(11) NOT NULL;
ALTER TABLE mai2_item_character MODIFY COLUMN level int(11) NOT NULL;
ALTER TABLE mai2_item_character MODIFY COLUMN awakening int(11) NOT NULL;
ALTER TABLE mai2_item_character MODIFY COLUMN useCount int(11) NOT NULL;
ALTER TABLE mai2_item_charge MODIFY COLUMN chargeId int(11) NOT NULL;
ALTER TABLE mai2_item_charge MODIFY COLUMN stock int(11) NOT NULL;
ALTER TABLE mai2_item_favorite MODIFY COLUMN itemKind int(11) NOT NULL;
ALTER TABLE mai2_item_friend_season_ranking MODIFY COLUMN seasonId int(11) NOT NULL;
ALTER TABLE mai2_item_friend_season_ranking MODIFY COLUMN point int(11) NOT NULL;
ALTER TABLE mai2_item_friend_season_ranking MODIFY COLUMN `rank` int(11) NOT NULL;
ALTER TABLE mai2_item_friend_season_ranking MODIFY COLUMN rewardGet tinyint(1) NOT NULL;
ALTER TABLE mai2_item_friend_season_ranking MODIFY COLUMN userName varchar(8) NOT NULL;
ALTER TABLE mai2_item_item MODIFY COLUMN itemId int(11) NOT NULL;
ALTER TABLE mai2_item_item MODIFY COLUMN itemKind int(11) NOT NULL;
ALTER TABLE mai2_item_item MODIFY COLUMN stock int(11) NOT NULL;
ALTER TABLE mai2_item_item MODIFY COLUMN isValid tinyint(1) NOT NULL;
ALTER TABLE mai2_item_login_bonus MODIFY COLUMN bonusId int(11) NOT NULL;
ALTER TABLE mai2_item_login_bonus MODIFY COLUMN point int(11) NOT NULL;
ALTER TABLE mai2_item_login_bonus MODIFY COLUMN isCurrent tinyint(1) NOT NULL;
ALTER TABLE mai2_item_login_bonus MODIFY COLUMN isComplete tinyint(1) NOT NULL;
ALTER TABLE mai2_item_map MODIFY COLUMN mapId int(11) NOT NULL;
ALTER TABLE mai2_item_map MODIFY COLUMN distance int(11) NOT NULL;
ALTER TABLE mai2_item_map MODIFY COLUMN isLock tinyint(1) NOT NULL;
ALTER TABLE mai2_item_map MODIFY COLUMN isClear tinyint(1) NOT NULL;
ALTER TABLE mai2_item_map MODIFY COLUMN isComplete tinyint(1) NOT NULL;
ALTER TABLE mai2_item_print_detail MODIFY COLUMN printDate timestamp DEFAULT current_timestamp() NOT NULL;
ALTER TABLE mai2_item_print_detail MODIFY COLUMN serialId varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;
ALTER TABLE mai2_item_print_detail MODIFY COLUMN placeId int(11) NOT NULL;
ALTER TABLE mai2_item_print_detail MODIFY COLUMN clientId varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;
ALTER TABLE mai2_item_print_detail MODIFY COLUMN printerSerialId varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;
@@ -0,0 +1,3 @@
ALTER TABLE mai2_item_card
CHANGE COLUMN startDate startDate TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CHANGE COLUMN endDate endDate TIMESTAMP NOT NULL;
@@ -0,0 +1 @@
DROP TABLE aime.mai2_profile_consec_logins;
@@ -0,0 +1,62 @@
UPDATE mai2_static_event SET version = version + 13 WHERE version < 1000;
UPDATE mai2_static_music SET version = version + 13 WHERE version < 1000;
UPDATE mai2_static_ticket SET version = version + 13 WHERE version < 1000;
UPDATE mai2_static_cards SET version = version + 13 WHERE version < 1000;
UPDATE mai2_profile_detail SET version = version + 13 WHERE version < 1000;
UPDATE mai2_profile_extend SET version = version + 13 WHERE version < 1000;
UPDATE mai2_profile_option SET version = version + 13 WHERE version < 1000;
UPDATE mai2_profile_ghost SET version = version + 13 WHERE version < 1000;
UPDATE mai2_profile_rating SET version = version + 13 WHERE version < 1000;
ALTER TABLE mai2_item_character ADD point int(11) NULL;
ALTER TABLE mai2_item_card MODIFY COLUMN cardId int(11) NULL;
ALTER TABLE mai2_item_card MODIFY COLUMN cardTypeId int(11) NULL;
ALTER TABLE mai2_item_card MODIFY COLUMN charaId int(11) NULL;
ALTER TABLE mai2_item_card MODIFY COLUMN mapId int(11) NULL;
ALTER TABLE mai2_item_character MODIFY COLUMN characterId int(11) NULL;
ALTER TABLE mai2_item_character MODIFY COLUMN level int(11) NULL;
ALTER TABLE mai2_item_character MODIFY COLUMN awakening int(11) NULL;
ALTER TABLE mai2_item_character MODIFY COLUMN useCount int(11) NULL;
ALTER TABLE mai2_item_charge MODIFY COLUMN chargeId int(11) NULL;
ALTER TABLE mai2_item_charge MODIFY COLUMN stock int(11) NULL;
ALTER TABLE mai2_item_favorite MODIFY COLUMN itemKind int(11) NULL;
ALTER TABLE mai2_item_friend_season_ranking MODIFY COLUMN seasonId int(11) NULL;
ALTER TABLE mai2_item_friend_season_ranking MODIFY COLUMN point int(11) NULL;
ALTER TABLE mai2_item_friend_season_ranking MODIFY COLUMN `rank` int(11) NULL;
ALTER TABLE mai2_item_friend_season_ranking MODIFY COLUMN rewardGet tinyint(1) NULL;
ALTER TABLE mai2_item_friend_season_ranking MODIFY COLUMN userName varchar(8) NULL;
ALTER TABLE mai2_item_item MODIFY COLUMN itemId int(11) NULL;
ALTER TABLE mai2_item_item MODIFY COLUMN itemKind int(11) NULL;
ALTER TABLE mai2_item_item MODIFY COLUMN stock int(11) NULL;
ALTER TABLE mai2_item_item MODIFY COLUMN isValid tinyint(1) NULL;
ALTER TABLE mai2_item_login_bonus MODIFY COLUMN bonusId int(11) NULL;
ALTER TABLE mai2_item_login_bonus MODIFY COLUMN point int(11) NULL;
ALTER TABLE mai2_item_login_bonus MODIFY COLUMN isCurrent tinyint(1) NULL;
ALTER TABLE mai2_item_login_bonus MODIFY COLUMN isComplete tinyint(1) NULL;
ALTER TABLE mai2_item_map MODIFY COLUMN mapId int(11) NULL;
ALTER TABLE mai2_item_map MODIFY COLUMN distance int(11) NULL;
ALTER TABLE mai2_item_map MODIFY COLUMN isLock tinyint(1) NULL;
ALTER TABLE mai2_item_map MODIFY COLUMN isClear tinyint(1) NULL;
ALTER TABLE mai2_item_map MODIFY COLUMN isComplete tinyint(1) NULL;
ALTER TABLE mai2_item_print_detail MODIFY COLUMN printDate timestamp DEFAULT current_timestamp() NULL;
ALTER TABLE mai2_item_print_detail MODIFY COLUMN serialId varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL;
ALTER TABLE mai2_item_print_detail MODIFY COLUMN placeId int(11) NULL;
ALTER TABLE mai2_item_print_detail MODIFY COLUMN clientId varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL;
ALTER TABLE mai2_item_print_detail MODIFY COLUMN printerSerialId varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL;
@@ -0,0 +1,10 @@
ALTER TABLE mai2_profile_detail
DROP COLUMN mapStock;
ALTER TABLE mai2_profile_extend
DROP COLUMN selectResultScoreViewType;
ALTER TABLE mai2_profile_option
DROP COLUMN outFrameType,
DROP COLUMN touchVolume,
DROP COLUMN breakSlideVolume;

Some files were not shown because too many files have changed in this diff Show More