Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
ScoutingSystemV2
/
ScoutingSystemElite-Api
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
5917bcb1
authored
Nov 26, 2025
by
Augusto
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
small fixes
parent
7730f929
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
151 additions
and
64 deletions
+151
-64
drizzle/0015_update_agents_country_to_fk.sql
+21
-0
drizzle/0016_remove_agent_id_from_players.sql
+9
-0
src/database/schema.ts
+4
-4
src/modules/agents/agents.controller.ts
+42
-27
src/modules/agents/agents.service.ts
+1
-1
src/modules/agents/dto/create-agent.dto.ts
+10
-4
src/modules/player-features/player-features.service.ts
+1
-0
src/modules/players/interfaces/player.interface.ts
+12
-7
src/modules/players/players.controller.ts
+31
-21
src/modules/players/players.service.ts
+0
-0
src/modules/profiles/dto/create-link.dto.ts
+9
-0
src/modules/profiles/dto/update-link.dto.ts
+9
-0
src/modules/profiles/profiles.service.ts
+2
-0
No files found.
drizzle/0015_update_agents_country_to_fk.sql
0 → 100644
View file @
5917bcb1
-- Update agents table to use countryWyId foreign key instead of country text field
-- This migration:
-- 1. Adds the new countryWyId column with a foreign key reference to areas.wy_id
-- 2. Drops the old country column
-- 3. Adds an index on countryWyId for query performance
-- Add new countryWyId column (initially nullable to allow migration)
ALTER
TABLE
agents
ADD
COLUMN
country_wy_id
INTEGER
;
-- Add index for query performance
CREATE
INDEX
idx_agents_country_wy_id
ON
agents
(
country_wy_id
);
-- Drop the old country column
ALTER
TABLE
agents
DROP
COLUMN
country
;
-- Add foreign key constraint (after dropping old column to avoid conflicts)
ALTER
TABLE
agents
ADD
CONSTRAINT
agents_country_wy_id_fk
FOREIGN
KEY
(
country_wy_id
)
REFERENCES
areas
(
wy_id
)
ON
DELETE
RESTRICT
;
-- Make countryWyId NOT NULL after migration
ALTER
TABLE
agents
ALTER
COLUMN
country_wy_id
SET
NOT
NULL
;
drizzle/0016_remove_agent_id_from_players.sql
0 → 100644
View file @
5917bcb1
-- Remove agentId column from players table
-- Agent relationships are now managed through the playerAgents junction table
-- This migration drops the direct foreign key reference to agents
-- Drop the foreign key constraint if it exists
ALTER
TABLE
players
DROP
CONSTRAINT
IF
EXISTS
players_agent_id_fk
;
-- Drop the agentId column
ALTER
TABLE
players
DROP
COLUMN
IF
EXISTS
agent_id
;
src/database/schema.ts
View file @
5917bcb1
...
...
@@ -213,9 +213,6 @@ export const players = pgTable(
// Transfer and financial information
onLoan
:
boolean
(
'on_loan'
).
default
(
false
),
agentId
:
integer
(
'agent_id'
).
references
(()
=>
agents
.
id
,
{
onDelete
:
'set null'
,
}),
ranking
:
varchar
(
'ranking'
,
{
length
:
255
}),
roi
:
varchar
(
'roi'
,
{
length
:
255
}),
// Return on Investment
marketValue
:
decimal
(
'market_value'
,
{
precision
:
15
,
scale
:
2
}),
// Monetary value
...
...
@@ -428,7 +425,9 @@ export const agents = pgTable('agents', {
phone
:
text
(
'phone'
).
notNull
(),
status
:
text
(
'status'
).
notNull
(),
address
:
text
(
'address'
).
notNull
(),
country
:
text
(
'country'
).
notNull
(),
countryWyId
:
integer
(
'country_wy_id'
)
.
notNull
()
.
references
(()
=>
areas
.
wyId
,
{
onDelete
:
'restrict'
}),
createdAt
:
timestamp
(
'created_at'
).
notNull
().
defaultNow
(),
updatedAt
:
timestamp
(
'updated_at'
).
notNull
().
defaultNow
(),
});
...
...
@@ -1042,6 +1041,7 @@ export const profileLinks = pgTable(
}),
title
:
varchar
(
'title'
,
{
length
:
255
}).
notNull
(),
// e.g., "YouTube", "Instagram", "Portfolio"
url
:
text
(
'url'
).
notNull
(),
icon
:
varchar
(
'icon'
,
{
length
:
255
}),
order
:
integer
(
'order'
).
default
(
0
),
isActive
:
boolean
(
'is_active'
).
default
(
true
),
createdAt
:
timestamp
(
'created_at'
,
{
withTimezone
:
true
}).
defaultNow
(),
...
...
src/modules/agents/agents.controller.ts
View file @
5917bcb1
...
...
@@ -39,11 +39,14 @@ export class AgentsController {
example1
:
{
summary
:
'Create new agent'
,
value
:
{
firstName
:
'John
'
,
lastName
:
'Smith
'
,
name
:
'John Smith
'
,
type
:
'individual
'
,
email
:
'john.smith@agents.com'
,
phone
:
'+1234567890'
,
company
:
'Elite Sports Management'
,
status
:
'active'
,
address
:
'123 Main St, New York'
,
countryWyId
:
1
,
description
:
'Elite sports agent'
,
},
},
},
...
...
@@ -53,14 +56,16 @@ export class AgentsController {
schema
:
{
example
:
{
id
:
1
,
firstName
:
'John
'
,
lastName
:
'Smith
'
,
name
:
'John Smith
'
,
type
:
'individual
'
,
email
:
'john.smith@agents.com'
,
phone
:
'+1234567890'
,
company
:
'Elite Sports Management'
,
status
:
'active'
,
address
:
'123 Main St, New York'
,
countryWyId
:
1
,
description
:
'Elite sports agent'
,
createdAt
:
'2025-01-15T10:30:00Z'
,
updatedAt
:
'2025-01-15T10:30:00Z'
,
deletedAt
:
null
,
},
},
})
...
...
@@ -92,14 +97,16 @@ export class AgentsController {
schema
:
{
example
:
{
id
:
1
,
firstName
:
'John
'
,
lastName
:
'Smith
'
,
name
:
'John Smith
'
,
type
:
'individual
'
,
email
:
'john.smith.new@agents.com'
,
phone
:
'+1987654321'
,
company
:
'Elite Sports Management'
,
status
:
'active'
,
address
:
'123 Main St, New York'
,
countryWyId
:
1
,
description
:
'Elite sports agent'
,
createdAt
:
'2025-01-15T10:30:00Z'
,
updatedAt
:
'2025-01-15T11:00:00Z'
,
deletedAt
:
null
,
},
},
})
...
...
@@ -122,14 +129,16 @@ export class AgentsController {
schema
:
{
example
:
{
id
:
1
,
firstName
:
'John
'
,
lastName
:
'Smith
'
,
name
:
'John Smith
'
,
type
:
'individual
'
,
email
:
'john.smith@agents.com'
,
phone
:
'+1234567890'
,
company
:
'Elite Sports Management'
,
status
:
'active'
,
address
:
'123 Main St, New York'
,
countryWyId
:
1
,
description
:
'Elite sports agent'
,
createdAt
:
'2025-01-15T10:30:00Z'
,
updatedAt
:
'2025-01-15T10:30:00Z'
,
deletedAt
:
null
,
},
},
})
...
...
@@ -149,14 +158,16 @@ export class AgentsController {
example
:
[
{
id
:
1
,
firstName
:
'John
'
,
lastName
:
'Smith
'
,
name
:
'John Smith
'
,
type
:
'individual
'
,
email
:
'john.smith@agents.com'
,
phone
:
'+1234567890'
,
company
:
'Elite Sports Management'
,
status
:
'active'
,
address
:
'123 Main St, New York'
,
countryWyId
:
1
,
description
:
'Elite sports agent'
,
createdAt
:
'2025-01-15T10:30:00Z'
,
updatedAt
:
'2025-01-15T10:30:00Z'
,
deletedAt
:
null
,
},
],
},
...
...
@@ -272,14 +283,16 @@ export class AgentsController {
example
:
[
{
id
:
1
,
firstName
:
'John
'
,
lastName
:
'Smith
'
,
name
:
'John Smith
'
,
type
:
'individual
'
,
email
:
'john.smith@agents.com'
,
phone
:
'+1234567890'
,
company
:
'Elite Sports Management'
,
status
:
'active'
,
address
:
'123 Main St, New York'
,
countryWyId
:
1
,
description
:
'Elite sports agent'
,
createdAt
:
'2025-01-15T10:30:00Z'
,
updatedAt
:
'2025-01-15T10:30:00Z'
,
deletedAt
:
null
,
},
],
},
...
...
@@ -302,14 +315,16 @@ export class AgentsController {
example
:
[
{
id
:
1
,
firstName
:
'John
'
,
lastName
:
'Smith
'
,
name
:
'John Smith
'
,
type
:
'individual
'
,
email
:
'john.smith@agents.com'
,
phone
:
'+1234567890'
,
company
:
'Elite Sports Management'
,
status
:
'active'
,
address
:
'123 Main St, New York'
,
countryWyId
:
1
,
description
:
'Elite sports agent'
,
createdAt
:
'2025-01-15T10:30:00Z'
,
updatedAt
:
'2025-01-15T10:30:00Z'
,
deletedAt
:
null
,
},
],
},
...
...
src/modules/agents/agents.service.ts
View file @
5917bcb1
...
...
@@ -27,7 +27,7 @@ export class AgentsService {
phone
:
data
.
phone
!
,
status
:
data
.
status
!
,
address
:
data
.
address
!
,
country
:
data
.
country
!
,
country
WyId
:
data
.
countryWyId
!
,
description
:
data
.
description
??
null
,
createdAt
:
now
as
any
,
updatedAt
:
now
as
any
,
...
...
src/modules/agents/dto/create-agent.dto.ts
View file @
5917bcb1
import
{
ApiProperty
,
ApiPropertyOptional
}
from
'@nestjs/swagger'
;
import
{
IsEmail
,
IsNotEmpty
,
IsOptional
,
IsString
}
from
'class-validator'
;
import
{
IsEmail
,
IsNotEmpty
,
IsOptional
,
IsString
,
IsNumber
,
}
from
'class-validator'
;
export
class
CreateAgentDto
{
@
ApiProperty
({
description
:
'Agent name'
})
...
...
@@ -31,10 +37,10 @@ export class CreateAgentDto {
@
IsNotEmpty
()
address
:
string
;
@
ApiProperty
({
description
:
'Country'
})
@
Is
String
()
@
ApiProperty
({
description
:
'Country
WY ID (Wyscout area ID)
'
})
@
Is
Number
()
@
IsNotEmpty
()
country
:
string
;
country
WyId
:
number
;
@
ApiPropertyOptional
({
description
:
'Description'
})
@
IsOptional
()
...
...
src/modules/player-features/player-features.service.ts
View file @
5917bcb1
...
...
@@ -561,6 +561,7 @@ export class PlayerFeaturesService {
],
set
:
{
notes
:
data
.
notes
??
null
,
deletedAt
:
null
,
updatedAt
:
new
Date
(),
},
})
...
...
src/modules/players/interfaces/player.interface.ts
View file @
5917bcb1
...
...
@@ -53,6 +53,16 @@ export interface Agent {
updatedAt
:
string
;
}
export
interface
Team
{
id
:
number
|
null
;
wyId
:
number
|
null
;
gsmId
:
number
|
null
;
name
:
string
|
null
;
officialName
:
string
|
null
;
createdAt
:
string
|
null
;
updatedAt
:
string
|
null
;
}
export
interface
StructuredPlayer
{
id
:
number
;
wyId
:
number
;
...
...
@@ -72,13 +82,8 @@ export interface StructuredPlayer {
position
:
PlayerPosition
|
null
;
otherPositions
:
PlayerPosition
[]
|
null
;
foot
:
string
|
null
;
currentTeamId
:
number
|
null
;
currentNationalTeamId
:
number
|
null
;
currentTeamName
:
string
|
null
;
currentTeamOfficialName
:
string
|
null
;
currentNationalTeamName
:
string
|
null
;
currentNationalTeamOfficialName
:
string
|
null
;
currentTeam
:
any
|
null
;
currentTeam
:
Team
|
null
;
currentNationalTeam
:
Team
|
null
;
gender
:
string
;
status
:
string
;
jerseyNumber
:
number
|
null
;
...
...
src/modules/players/players.controller.ts
View file @
5917bcb1
...
...
@@ -85,8 +85,8 @@ export class PlayersController {
return
this
.
playersService
.
upsertByWyId
(
body
as
any
);
}
@
Get
(
'
by-id/
:id'
)
@
ApiOperation
({
summary
:
'Get player by
database
ID'
})
@
Get
(
':id'
)
@
ApiOperation
({
summary
:
'Get player by ID'
})
@
ApiParam
({
name
:
'id'
,
type
:
Number
,
...
...
@@ -104,13 +104,23 @@ export class PlayersController {
return
player
;
}
@
Get
(
':wyId'
)
@
ApiOperation
({
summary
:
'Get player by wyId'
})
@
Get
(
'wy/:wyId'
)
@
ApiOperation
({
summary
:
'Get player by Wyscout ID (wyId)'
})
@
ApiParam
({
name
:
'wyId'
,
type
:
Number
,
description
:
'Wyscout ID (wyId) of the player'
,
})
@
ApiOkResponse
({
description
:
'Player if found'
,
type
:
Object
})
@
ApiNotFoundResponse
({
description
:
'Player not found'
})
async
getByWyId
(
@
Param
(
'wyId'
,
ParseIntPipe
)
wyId
:
number
,
):
Promise
<
StructuredPlayer
|
undefined
>
{
return
this
.
playersService
.
findByWyId
(
wyId
);
const
player
=
await
this
.
playersService
.
findByWyId
(
wyId
);
if
(
!
player
)
{
throw
new
NotFoundException
(
`Player with wyId
${
wyId
}
not found`
);
}
return
player
;
}
@
Get
()
...
...
@@ -286,16 +296,16 @@ export class PlayersController {
return
this
.
playersService
.
findAll
(
l
,
o
,
name
,
query
);
}
@
Patch
(
':
wyI
d'
)
@
Patch
(
':
i
d'
)
@
ApiOperation
({
summary
:
'Update player by
wyId
'
,
summary
:
'Update player by
ID
'
,
description
:
'Updates an existing player. Only provided fields will be updated.'
,
'Updates an existing player
by database ID
. Only provided fields will be updated.'
,
})
@
ApiParam
({
name
:
'
wyI
d'
,
name
:
'
i
d'
,
type
:
Number
,
description
:
'
Wyscout
ID of the player to update'
,
description
:
'
Database
ID of the player to update'
,
})
@
ApiBody
({
description
:
'Player update payload. All fields are optional.'
,
...
...
@@ -338,31 +348,31 @@ export class PlayersController {
},
})
@
ApiNotFoundResponse
({
description
:
'Player not found'
})
async
updateBy
Wy
Id
(
@
Param
(
'
wyId'
,
ParseIntPipe
)
wyI
d
:
number
,
async
updateById
(
@
Param
(
'
id'
,
ParseIntPipe
)
i
d
:
number
,
@
Body
()
body
:
UpdatePlayerDto
,
):
Promise
<
Player
>
{
const
result
=
await
this
.
playersService
.
updateBy
WyId
(
wyI
d
,
body
);
const
result
=
await
this
.
playersService
.
updateBy
Id
(
i
d
,
body
);
if
(
!
result
)
{
throw
new
NotFoundException
(
`Player with
wyId
${
wyI
d
}
not found`
);
throw
new
NotFoundException
(
`Player with
ID
${
i
d
}
not found`
);
}
return
result
;
}
@
Delete
(
':
wyI
d'
)
@
Delete
(
':
i
d'
)
@
HttpCode
(
HttpStatus
.
NO_CONTENT
)
@
ApiOperation
({
summary
:
'Delete player by
wyId
(soft delete)'
})
@
ApiOperation
({
summary
:
'Delete player by
ID
(soft delete)'
})
@
ApiParam
({
name
:
'
wyI
d'
,
name
:
'
i
d'
,
type
:
Number
,
description
:
'
Wyscout
ID of the player to delete'
,
description
:
'
Database
ID of the player to delete'
,
})
@
ApiNoContentResponse
({
description
:
'Player deleted successfully'
})
@
ApiNotFoundResponse
({
description
:
'Player not found'
})
async
deleteBy
WyId
(@
Param
(
'wyId'
,
ParseIntPipe
)
wyI
d
:
number
):
Promise
<
void
>
{
const
result
=
await
this
.
playersService
.
deleteBy
WyId
(
wyI
d
);
async
deleteBy
Id
(@
Param
(
'id'
,
ParseIntPipe
)
i
d
:
number
):
Promise
<
void
>
{
const
result
=
await
this
.
playersService
.
deleteBy
Id
(
i
d
);
if
(
!
result
)
{
throw
new
NotFoundException
(
`Player with
wyId
${
wyI
d
}
not found`
);
throw
new
NotFoundException
(
`Player with
ID
${
i
d
}
not found`
);
}
}
}
src/modules/players/players.service.ts
View file @
5917bcb1
This diff is collapsed.
Click to expand it.
src/modules/profiles/dto/create-link.dto.ts
View file @
5917bcb1
...
...
@@ -48,6 +48,15 @@ export class CreateLinkDto {
order
?:
number
;
@
ApiPropertyOptional
({
description
:
'Icon identifier or URL for the link'
,
example
:
'youtube'
,
type
:
String
,
})
@
IsOptional
()
@
IsString
()
icon
?:
string
;
@
ApiPropertyOptional
({
description
:
'Whether the link is active'
,
example
:
true
,
type
:
Boolean
,
...
...
src/modules/profiles/dto/update-link.dto.ts
View file @
5917bcb1
...
...
@@ -31,6 +31,15 @@ export class UpdateLinkDto {
order
?:
number
;
@
ApiPropertyOptional
({
description
:
'Icon identifier or URL for the link'
,
example
:
'youtube'
,
type
:
String
,
})
@
IsOptional
()
@
IsString
()
icon
?:
string
;
@
ApiPropertyOptional
({
description
:
'Whether the link is active'
,
example
:
true
,
type
:
Boolean
,
...
...
src/modules/profiles/profiles.service.ts
View file @
5917bcb1
...
...
@@ -175,6 +175,7 @@ export class ProfilesService {
coachId
:
data
.
coachId
??
null
,
title
:
data
.
title
,
url
:
data
.
url
,
icon
:
(
data
as
any
).
icon
??
null
,
order
:
data
.
order
??
0
,
isActive
:
data
.
isActive
??
true
,
}
as
NewProfileLink
)
...
...
@@ -202,6 +203,7 @@ export class ProfilesService {
const
updateData
:
any
=
{
updatedAt
:
new
Date
()
};
if
(
data
.
title
!==
undefined
)
updateData
.
title
=
data
.
title
;
if
(
data
.
url
!==
undefined
)
updateData
.
url
=
data
.
url
;
if
((
data
as
any
).
icon
!==
undefined
)
updateData
.
icon
=
(
data
as
any
).
icon
;
if
(
data
.
order
!==
undefined
)
updateData
.
order
=
data
.
order
;
if
(
data
.
isActive
!==
undefined
)
updateData
.
isActive
=
data
.
isActive
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment