Skip to content

feat(user) ✨ implement country preference API#24

Merged
Mattic77 merged 7 commits into
developmentfrom
Feature/User/GH-25-Implement-Country-Preference-API
Jun 5, 2026
Merged

feat(user) ✨ implement country preference API#24
Mattic77 merged 7 commits into
developmentfrom
Feature/User/GH-25-Implement-Country-Preference-API

Conversation

@Mattic77

@Mattic77 Mattic77 commented Jun 5, 2026

Copy link
Copy Markdown
Owner

GitHub Issue

Closes GH-25

Description 📝

This PR implements a dedicated API endpoint for users to manage their country preferences. This preference is used by the game engine to automatically filter questions without requiring the user to select their country manually for every session.

Type of Change

  • ✨ New feature (non-breaking change that adds functionality)
  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • 📝 Documentation
  • ♻️ Code refactor (improved game engine selection logic)

Changes

  • Created UpdateCountryPreferenceDto to handle "all" or specific UUID inputs.
  • Implemented updateCountryPreference in UserService to manage the preferredCountryId field.
  • Added PATCH /users/preferences/country to UserController with full Swagger documentation.
  • Integrated the preference check into GameService.startSession.
  • Enabled categoryId filtering in GameService.startSession.

Screenshots 📸 (N/A)

Mattic77 added 2 commits June 5, 2026 10:53
- add UpdateCountryPreferenceDto for preference toggle
- add updateCountryPreference method to UserService
- add PATCH /users/preferences/country endpoint to UserController
- allow selecting specific country or all to reset preference

Closes #25
- delete redundant update-country-preference.dto.ts
- move UpdateCountryPreferenceDto to update-user.dto.ts
- update UserController imports
@Mattic77 Mattic77 self-assigned this Jun 5, 2026
@Mattic77 Mattic77 added the new feauture this label is made fro new feature label Jun 5, 2026
@Mattic77 Mattic77 requested a review from Copilot June 5, 2026 09:00

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a user “preferred country” setting (persisted on User) and wires it into game session creation so that omitting countrySelection automatically filters questions by the user’s saved preference. It also adds optional categoryId filtering when starting a game session.

Changes:

  • Add PATCH /users/preferences/country plus service logic to store/reset preferredCountryId.
  • Extend Prisma schema with a User.preferredCountryId -> Country relation.
  • Update GameService.startSession to use the saved preference when countrySelection is omitted and to support categoryId filtering.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/user/user.service.ts Adds updateCountryPreference to persist/reset preferredCountryId.
src/user/user.controller.ts Exposes PATCH /users/preferences/country for authenticated users.
src/user/dto/update-user.dto.ts Adds preferredCountryId to profile updates and introduces UpdateCountryPreferenceDto.
src/game/game.service.ts Applies preferred country when countrySelection is omitted; adds category filtering to quiz selection.
src/game/dto/start-game.dto.ts Adds categoryId to StartGameDto and updates country selection docs.
prisma/schema.prisma Adds preferredCountryId column and relation between User and Country.
PR_DESCRIPTION.md Updates PR description to match the new feature scope and linked issue.
Comments suppressed due to low confidence (1)

src/game/game.service.ts:63

  • This uses $queryRawUnsafe with string interpolation for countryId, categoryId, and difficulty. Since categoryId and countrySelection come directly from the request, this introduces a SQL injection vector (and it will only get worse as more filters are added).
    const categoryId = dto.categoryId;

    // Fetch 15 random quiz IDs
    const quizzes = await this.prisma.$queryRawUnsafe<any[]>(`
      SELECT id FROM quiz
      WHERE 1=1
      ${countryId ? `AND country_id = '${countryId}'` : ''}
      ${categoryId ? `AND category_id = '${categoryId}'` : ''}
      ${difficulty ? `AND difficulty = '${difficulty}'` : ''}
      ORDER BY RANDOM()
      LIMIT 15
    `);

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/user/user.service.ts
Comment on lines +20 to +23
@ApiProperty({ example: 'uuid-of-country', required: false })
@IsOptional()
@IsString()
preferredCountryId?: string;
Comment thread src/user/dto/update-user.dto.ts Outdated
@@ -1,4 +1,4 @@
import { IsString, IsOptional, IsEmail, IsDate } from 'class-validator';
import { IsString, IsOptional, IsEmail, IsDate, IsNotEmpty } from 'class-validator';
Comment on lines +32 to +34
@IsString()
@IsNotEmpty()
countryId: string;
Comment on lines +16 to +18
@IsOptional()
@IsString()
categoryId?: string;
Comment thread prisma/schema.prisma
Comment on lines +50 to +51
preferredCountryId String? @map("preferred_country_id")
preferredCountry Country? @relation("UserPreferredCountry", fields: [preferredCountryId], references: [id])
Mattic77 and others added 3 commits June 5, 2026 11:12
- replace queryRawUnsafe with parameterized queryRaw
- use Prisma.sql and Prisma.join for safe dynamic filtering
- eliminate risk of string interpolation in SQL queries
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…ry preferences

- add IsUUID validation to preferredCountryId in UpdateUserDto
- add regex-based validation to countryId in UpdateCountryPreferenceDto
- allow only valid UUIDs or the string all to ensure fail-fast 400 errors

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.

Comment thread src/user/user.service.ts
Comment on lines +262 to +266
const normalizedCountryId = countryId.trim();
const data =
normalizedCountryId.toLowerCase() === 'all'
? { preferredCountryId: null }
: { preferredCountryId: normalizedCountryId };
Comment thread src/user/user.controller.ts
Comment on lines +28 to +31
@ApiProperty({ example: 'uuid-of-country', required: false })
@IsOptional()
@IsUUID()
preferredCountryId?: string;
Comment thread prisma/schema.prisma
Mattic77 and others added 2 commits June 5, 2026 11:24
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@Mattic77 Mattic77 requested a review from Copilot June 5, 2026 09:28
@Mattic77 Mattic77 merged commit 995fd43 into development Jun 5, 2026
2 checks passed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.

Comment thread src/user/user.service.ts
Comment on lines +262 to +266
const normalizedCountryId = countryId.trim();
const data =
normalizedCountryId.toLowerCase() === 'all'
? { preferredCountryId: null }
: { preferredCountryId: normalizedCountryId };
Comment on lines +27 to +32

@ApiProperty({ example: 'uuid-of-country', required: false })
@IsOptional()
@IsUUID()
preferredCountryId?: string;
}
Comment on lines +1 to +9
import {
IsString,
IsOptional,
IsEmail,
IsDate,
IsNotEmpty,
IsUUID,
Matches,
} from 'class-validator';
@@ -0,0 +1,5 @@
-- AlterTable
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

new feauture this label is made fro new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants