* feat(config): make `performance_server` as default calculator
* deploy(docker): use osu-performance-server
* docs(readme): add ruleset download instructions
* chore(dev): update development environment
* feat(dev): update development environment setup and service startup order
* fix(deps): move `rosu-pp-py` to `project.optional-dependencies`
* feat(beatmap): handle deleted beatmaps
* feat(performance-server): add a long timeout for calculation
* feat(recalculate): enhance CLI arguments for performance, leaderboard, and rating recalculations with CSV output support
* fix(recalculate): resolve reviews
* Apply suggestions from code review
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fix(beatmapsync): resolve too long line
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Initial plan
* feat(calculator): add classic score simulator and scoring mode support
- Add ScoringMode enum with STANDARDISED and CLASSIC modes
- Add scoring_mode configuration to game settings
- Implement GetDisplayScore function in calculator.py
- Add get_display_score method to Score model
- Update score statistics to use display scores based on scoring mode
Co-authored-by: MingxuanGame <68982190+MingxuanGame@users.noreply.github.com>
* fix(calculator): apply scoring mode to TotalScoreBestScore delete method
- Update delete method to use display score for consistency
- Ensures all UserStatistics modifications use configured scoring mode
Co-authored-by: MingxuanGame <68982190+MingxuanGame@users.noreply.github.com>
* refactor(calculator): address code review feedback
- Move MAX_SCORE constant to app/const.py
- Implement is_basic() as method in HitResult enum
- Move imports to top of file in Score model
- Revert TotalScoreBestScore storage to use standardised score
- Apply display score calculation in tools/recalculate.py
- Keep display score usage in UserStatistics modifications
Co-authored-by: MingxuanGame <68982190+MingxuanGame@users.noreply.github.com>
* chore(linter): auto fix by pre-commit hooks
* Don't use forward-ref for `ScoringMode`
* chore(linter): auto fix by pre-commit hooks
* fix(calculator): update HitResult usage in get_display_score and adjust ruleset value in PerformanceServerPerformanceCalculator
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: MingxuanGame <MingxuanGame@outlook.com>
* feat(custom_ruleset): add custom rulesets support
* feat(custom-ruleset): add version check
* feat(custom-ruleset): add LegacyIO API to get ruleset hashes
* feat(pp): add check for rulesets whose pp cannot be calculated
* docs(readme): update README to include support for custom rulesets
* fix(custom-ruleset): make `rulesets` empty instead of throw a error when version check is disabled
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* chore(custom-ruleset): apply the latest changes of generator
c891bcd159
and
e25041ad3b
* feat(calculator): add fallback performance calculation for unsupported modes
* fix(calculator): remove debug print
* fix: resolve reviews
* feat(calculator): add difficulty calculation checks
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
APIs:
- GET `/api/private/user/preferences`: Get current user's preferences.
- PATCH `/api/private/user/preferences`: Modify current user's preferences. (body: Preferences)
- PUT `/api/private/user/preferences`: Overwrite current user's preferences. (body: Preferences)
- DELETE `/api/private/user/preferences`: Reset current user's preferences. (body: list[str])
- body specifies the content to be reset. If body is empty, reset all preferences.
User:
- `User.g0v0_playmode`: show the special ruleset like `OSURX`, and custom rulesets in the future.
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
## APIs Restricted for Restricted Users
A restricted user is blocked from performing the following actions, and will typically receive a `403 Forbidden` error:
* **Chat & Notifications:**
* Sending any chat messages (public or private).
* Joining or leaving chat channels.
* Creating new PM channels.
* **User Profile & Content:**
* Uploading a new avatar.
* Uploading a new profile cover image.
* Changing their username.
* Updating their userpage content.
* **Scores & Gameplay:**
* Submitting scores in multiplayer rooms.
* Deleting their own scores (to prevent hiding evidence of cheating).
* **Beatmaps:**
* Rating beatmaps.
* Taging beatmaps.
* **Relationship:**
* Adding friends or blocking users.
* Removing friends or unblocking users.
* **Teams:**
* Creating, updating, or deleting a team.
* Requesting to join a team.
* Handling join requests for a team they manage.
* Kicking a member from a team they manage.
* **Multiplayer:**
* Creating or deleting multiplayer rooms.
* Joining or leaving multiplayer rooms.
## What is Invisible to Normal Users
* **Leaderboards:**
* Beatmap leaderboards.
* Multiplayer (playlist) room leaderboards.
* **User Search/Lists:**
* Restricted users will not appear in the results of the `/api/v2/users` endpoint.
* They will not appear in the list of a team's members.
* **Relationship:**
* They will not appear in a user's friend list (`/friends`).
* **Profile & History:**
* Attempting to view a restricted user's profile, events, kudosu history, or score history will result in a `404 Not Found` error, effectively making their profile invisible (unless the user viewing the profile is the restricted user themselves).
* **Chat:**
* Normal users cannot start a new PM with a restricted user (they will get a `404 Not Found` error).
* **Ranking:**
* Restricted users are excluded from any rankings.
### How to Restrict a User
Insert into `user_account_history` with `type=restriction`.
```sql
-- length is in seconds
INSERT INTO user_account_history (`description`, `length`, `permanent`, `timestamp`, `type`, `user_id`) VALUE ('some description', 86400, 0, '2025-10-05 01:00:00', 'RESTRICTION', 1);
```
---
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
format: {time:YYYY-MM-DD HH:mm:ss} [{level}] | {name} | {message}
{name} is:
- Uvicorn: log from uvicorn server (#228B22)
- Service: log from class of `app.service` (blue)
- Fetcher: log from fetchers (magenta)
- Task: log from `app.tasks` (#FFD700)
- System: log from `system_logger` (red)
- Normal: log from `log(name)` (#FFC1C1)
- Default: the module name of caller
if you are writing services or tasks, you can just call `logger.`, we will pack it with name `Service` or `Task`
if you want to print fetcher logs, system-related logs, or normal logs, use `logger = (fetcher_logger / system_logger / log)(name)`
New API to maintain sessions and devices:
- GET /api/private/admin/sessions
- DELETE /api/private/admin/sessions/{session_id}
- GET /api/private/admin/trusted-devices
- DELETE /api/private/admin/trusted-devices/{device_id}
Auth:
web clients request `/oauth/token` and `/api/v2/session/verify` with `X-UUID` header to save the client as trusted device.
---------
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
New API:
- DELETE /api/private/score/{score_id}: delete a score
- POST /api/private/beatmapsets/{beatmapset_id}/sync: request for syncing a beatmapset
New configuration:
- OLD_SCORE_PROCESSING_MODE
* chore(deps): add pyotp
* feat(auth): implement TOTP verification
feat(auth): implement TOTP verification and email verification services
- Added TOTP keys management with a new database model `TotpKeys`.
- Introduced `EmailVerification` and `LoginSession` models for email verification.
- Created `verification_service` to handle email verification logic and TOTP processes.
- Updated user response models to include session verification methods.
- Implemented routes for TOTP creation, verification, and fallback to email verification.
- Enhanced login session management to support new location checks and verification methods.
- Added migration script to create `totp_keys` table in the database.
* feat(config): update config example
* docs(totp): complete creating TOTP flow
* refactor(totp): resolve review
* feat(api): forbid unverified request
* fix(totp): trace session by token id to avoid other sessions are forbidden
* chore(linter): make pyright happy
* fix(totp): only mark sessions with a specified token id
* feat(relationship): support legacy-compatible response format
* feat(score): add support for legacy score response format in API
* fix(score): avoid missing greenlet
* fix(score): fix missing field for model validation
* feat(user): apply legacy score format for user
* feat(api): use `int` to hint `APIVersion`
Add configuration: `BEATMAP_TAG_TOP_COUNT` to control the minimun vote count
Tips: this is 10 in osu-web, but private server doesn't have enough player so we use 2 as default value
Official tags see: https://osu.ppy.sh/wiki/Beatmap/Beatmap_tags