Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
Unike
/
UnikeForm-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
41932462
authored
Sep 09, 2025
by
Augusto
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
logs
parent
4abd89bc
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
532 additions
and
8 deletions
+532
-8
drizzle/0001_perpetual_human_fly.sql
+17
-0
drizzle/meta/0001_snapshot.json
+0
-0
drizzle/meta/_journal.json
+9
-1
src/drizzle/schema.ts
+82
-0
src/main.ts
+1
-1
src/modules/occurrence/dto/log-response.dto.ts
+70
-0
src/modules/occurrence/occurrence-log.service.ts
+243
-0
src/modules/occurrence/occurrence.controller.ts
+44
-3
src/modules/occurrence/occurrence.module.ts
+3
-2
src/modules/occurrence/occurrence.service.ts
+33
-1
src/types/index.ts
+30
-0
No files found.
drizzle/0001_perpetual_human_fly.sql
0 → 100644
View file @
41932462
CREATE
TABLE
`occurrence_logs`
(
`id`
varchar
(
25
)
NOT
NULL
,
`occurrenceId`
varchar
(
25
)
NOT
NULL
,
`log_action`
enum
(
'CREATED'
,
'UPDATED'
,
'ASSIGNED'
,
'DUAL_ASSIGNED'
,
'UNASSIGNED'
,
'STATUS_CHANGED'
,
'PRIORITY_CHANGED'
,
'COMMENT_ADDED'
,
'ATTACHMENT_ADDED'
,
'ATTACHMENT_REMOVED'
,
'CONCLUSION_ADDED'
,
'CONCLUSION_UPDATED'
,
'DELETED'
)
NOT
NULL
,
`description`
text
NOT
NULL
,
`oldValue`
text
,
`newValue`
text
,
`performedBy`
varchar
(
25
)
NOT
NULL
,
`createdAt`
timestamp
NOT
NULL
DEFAULT
now
(),
CONSTRAINT
`occurrence_logs_id`
PRIMARY
KEY
(
`id`
)
);
--> statement-breakpoint
CREATE
INDEX
`log_occurrence_idx`
ON
`occurrence_logs`
(
`occurrenceId`
);
--> statement-breakpoint
CREATE
INDEX
`log_performed_by_idx`
ON
`occurrence_logs`
(
`performedBy`
);
--> statement-breakpoint
CREATE
INDEX
`log_action_idx`
ON
`occurrence_logs`
(
`log_action`
);
--> statement-breakpoint
CREATE
INDEX
`log_created_at_idx`
ON
`occurrence_logs`
(
`createdAt`
);
\ No newline at end of file
drizzle/meta/0001_snapshot.json
0 → 100644
View file @
41932462
This diff is collapsed.
Click to expand it.
drizzle/meta/_journal.json
View file @
41932462
...
...
@@ -8,6 +8,13 @@
"when"
:
1757350101348
,
"tag"
:
"0000_add_manager_to_occurrences"
,
"breakpoints"
:
true
},
{
"idx"
:
1
,
"version"
:
"5"
,
"when"
:
1757352023356
,
"tag"
:
"0001_perpetual_human_fly"
,
"breakpoints"
:
true
}
]
}
}
\ No newline at end of file
src/drizzle/schema.ts
View file @
41932462
...
...
@@ -32,6 +32,21 @@ export const priorityEnum = mysqlEnum('priority', [
'HIGH'
,
'URGENT'
,
]);
export
const
logActionEnum
=
mysqlEnum
(
'log_action'
,
[
'CREATED'
,
'UPDATED'
,
'ASSIGNED'
,
'DUAL_ASSIGNED'
,
'UNASSIGNED'
,
'STATUS_CHANGED'
,
'PRIORITY_CHANGED'
,
'COMMENT_ADDED'
,
'ATTACHMENT_ADDED'
,
'ATTACHMENT_REMOVED'
,
'CONCLUSION_ADDED'
,
'CONCLUSION_UPDATED'
,
'DELETED'
,
]);
// Users table
export
const
users
=
mysqlTable
(
...
...
@@ -84,6 +99,7 @@ export const comments = mysqlTable(
id
:
varchar
(
'id'
,
{
length
:
25
}).
primaryKey
(),
content
:
text
(
'content'
).
notNull
(),
isInternal
:
boolean
(
'isInternal'
).
notNull
().
default
(
false
),
status
:
occurrenceStatusEnum
(
'status'
),
occurrenceId
:
varchar
(
'occurrenceId'
,
{
length
:
25
}).
notNull
(),
authorId
:
varchar
(
'authorId'
,
{
length
:
25
}).
notNull
(),
createdAt
:
timestamp
(
'createdAt'
).
notNull
().
defaultNow
(),
...
...
@@ -130,12 +146,34 @@ export const conclusions = mysqlTable(
}),
);
// Occurrence logs table
export
const
occurrenceLogs
=
mysqlTable
(
'occurrence_logs'
,
{
id
:
varchar
(
'id'
,
{
length
:
25
}).
primaryKey
(),
occurrenceId
:
varchar
(
'occurrenceId'
,
{
length
:
25
}).
notNull
(),
action
:
logActionEnum
.
notNull
(),
description
:
text
(
'description'
).
notNull
(),
oldValue
:
text
(
'oldValue'
),
newValue
:
text
(
'newValue'
),
performedBy
:
varchar
(
'performedBy'
,
{
length
:
25
}).
notNull
(),
createdAt
:
timestamp
(
'createdAt'
).
notNull
().
defaultNow
(),
},
(
table
)
=>
({
occurrenceIdx
:
index
(
'log_occurrence_idx'
).
on
(
table
.
occurrenceId
),
performedByIdx
:
index
(
'log_performed_by_idx'
).
on
(
table
.
performedBy
),
actionIdx
:
index
(
'log_action_idx'
).
on
(
table
.
action
),
createdAtIdx
:
index
(
'log_created_at_idx'
).
on
(
table
.
createdAt
),
}),
);
// Relations
export
const
usersRelations
=
relations
(
users
,
({
many
})
=>
({
reportedOccurrences
:
many
(
occurrences
,
{
relationName
:
'reportedBy'
}),
assignedOccurrences
:
many
(
occurrences
,
{
relationName
:
'assignedTo'
}),
managedOccurrences
:
many
(
occurrences
,
{
relationName
:
'managedBy'
}),
comments
:
many
(
comments
),
logs
:
many
(
occurrenceLogs
),
}));
export
const
occurrencesRelations
=
relations
(
occurrences
,
({
one
,
many
})
=>
({
...
...
@@ -157,6 +195,7 @@ export const occurrencesRelations = relations(occurrences, ({ one, many }) => ({
comments
:
many
(
comments
),
attachments
:
many
(
attachments
),
conclusion
:
one
(
conclusions
),
logs
:
many
(
occurrenceLogs
),
}));
export
const
commentsRelations
=
relations
(
comments
,
({
one
})
=>
({
...
...
@@ -184,6 +223,17 @@ export const conclusionsRelations = relations(conclusions, ({ one }) => ({
}),
}));
export
const
occurrenceLogsRelations
=
relations
(
occurrenceLogs
,
({
one
})
=>
({
occurrence
:
one
(
occurrences
,
{
fields
:
[
occurrenceLogs
.
occurrenceId
],
references
:
[
occurrences
.
id
],
}),
performedBy
:
one
(
users
,
{
fields
:
[
occurrenceLogs
.
performedBy
],
references
:
[
users
.
id
],
}),
}));
// Type exports for TypeScript
export
type
User
=
typeof
users
.
$inferSelect
;
export
type
NewUser
=
typeof
users
.
$inferInsert
;
...
...
@@ -195,6 +245,8 @@ export type Attachment = typeof attachments.$inferSelect;
export
type
NewAttachment
=
typeof
attachments
.
$inferInsert
;
export
type
Conclusion
=
typeof
conclusions
.
$inferSelect
;
export
type
NewConclusion
=
typeof
conclusions
.
$inferInsert
;
export
type
OccurrenceLog
=
typeof
occurrenceLogs
.
$inferSelect
;
export
type
NewOccurrenceLog
=
typeof
occurrenceLogs
.
$inferInsert
;
// Enum types
export
type
UserRole
=
'USER'
|
'MODERATOR'
|
'ADMIN'
;
...
...
@@ -206,6 +258,20 @@ export type OccurrenceStatus =
|
'PARCIAL_RESOLVED'
|
'CANCELLED'
;
export
type
Priority
=
'LOW'
|
'MEDIUM'
|
'HIGH'
|
'URGENT'
;
export
type
LogAction
=
|
'CREATED'
|
'UPDATED'
|
'ASSIGNED'
|
'DUAL_ASSIGNED'
|
'UNASSIGNED'
|
'STATUS_CHANGED'
|
'PRIORITY_CHANGED'
|
'COMMENT_ADDED'
|
'ATTACHMENT_ADDED'
|
'ATTACHMENT_REMOVED'
|
'CONCLUSION_ADDED'
|
'CONCLUSION_UPDATED'
|
'DELETED'
;
// Enum constants for runtime usage
export
const
UserRoleEnum
=
{
...
...
@@ -229,3 +295,19 @@ export const PriorityEnum = {
HIGH
:
'HIGH'
as
const
,
URGENT
:
'URGENT'
as
const
,
}
as
const
;
export
const
LogActionEnum
=
{
CREATED
:
'CREATED'
as
const
,
UPDATED
:
'UPDATED'
as
const
,
ASSIGNED
:
'ASSIGNED'
as
const
,
DUAL_ASSIGNED
:
'DUAL_ASSIGNED'
as
const
,
UNASSIGNED
:
'UNASSIGNED'
as
const
,
STATUS_CHANGED
:
'STATUS_CHANGED'
as
const
,
PRIORITY_CHANGED
:
'PRIORITY_CHANGED'
as
const
,
COMMENT_ADDED
:
'COMMENT_ADDED'
as
const
,
ATTACHMENT_ADDED
:
'ATTACHMENT_ADDED'
as
const
,
ATTACHMENT_REMOVED
:
'ATTACHMENT_REMOVED'
as
const
,
CONCLUSION_ADDED
:
'CONCLUSION_ADDED'
as
const
,
CONCLUSION_UPDATED
:
'CONCLUSION_UPDATED'
as
const
,
DELETED
:
'DELETED'
as
const
,
}
as
const
;
src/main.ts
View file @
41932462
...
...
@@ -46,6 +46,6 @@ async function bootstrap() {
const
document
=
SwaggerModule
.
createDocument
(
app
,
config
);
SwaggerModule
.
setup
(
'docs'
,
app
,
document
);
await
app
.
listen
(
process
.
env
.
PORT
??
300
1
);
await
app
.
listen
(
process
.
env
.
PORT
??
300
0
);
}
bootstrap
();
src/modules/occurrence/dto/log-response.dto.ts
0 → 100644
View file @
41932462
import
{
ApiProperty
,
ApiPropertyOptional
}
from
'@nestjs/swagger'
;
import
{
LogAction
,
LogActionEnum
}
from
'../../../types'
;
export
class
LogResponseDto
{
@
ApiProperty
({
description
:
'Unique identifier for the log entry'
,
example
:
'clxyz123abc456def'
,
})
id
:
string
;
@
ApiProperty
({
description
:
'ID of the occurrence this log entry belongs to'
,
example
:
'clxyz123abc456def'
,
})
occurrenceId
:
string
;
@
ApiProperty
({
description
:
'Type of action that was performed'
,
enum
:
LogActionEnum
,
example
:
LogActionEnum
.
STATUS_CHANGED
,
})
action
:
LogAction
;
@
ApiProperty
({
description
:
'Human-readable description of what happened'
,
example
:
'Status changed from OPEN to IN_PROGRESS'
,
})
description
:
string
;
@
ApiPropertyOptional
({
description
:
'Previous value before the change (if applicable)'
,
example
:
'OPEN'
,
})
oldValue
?:
string
|
null
;
@
ApiPropertyOptional
({
description
:
'New value after the change (if applicable)'
,
example
:
'IN_PROGRESS'
,
})
newValue
?:
string
|
null
;
@
ApiProperty
({
description
:
'ID of the user who performed the action'
,
example
:
'clxyz789def012ghi'
,
})
performedBy
:
string
;
@
ApiProperty
({
description
:
'Date and time when the action was performed'
,
example
:
'2024-01-01T12:00:00.000Z'
,
})
createdAt
:
Date
;
@
ApiPropertyOptional
({
description
:
'User who performed the action'
,
type
:
'object'
,
properties
:
{
id
:
{
type
:
'string'
,
example
:
'clxyz789def012ghi'
},
firstName
:
{
type
:
'string'
,
example
:
'John'
},
lastName
:
{
type
:
'string'
,
example
:
'Doe'
},
email
:
{
type
:
'string'
,
example
:
'john.doe@example.com'
},
},
})
performedByUser
?:
{
id
:
string
;
firstName
:
string
;
lastName
:
string
;
email
:
string
;
};
}
src/modules/occurrence/occurrence-log.service.ts
0 → 100644
View file @
41932462
import
{
Injectable
}
from
'@nestjs/common'
;
import
{
DrizzleService
}
from
'../../common/drizzle.service'
;
import
{
LogResponseDto
}
from
'./dto/log-response.dto'
;
import
{
LogAction
}
from
'../../types'
;
import
{
occurrenceLogs
,
users
}
from
'../../drizzle/schema'
;
import
{
eq
,
desc
}
from
'drizzle-orm'
;
@
Injectable
()
export
class
OccurrenceLogService
{
constructor
(
private
readonly
drizzle
:
DrizzleService
)
{}
async
createLog
(
occurrenceId
:
string
,
action
:
LogAction
,
description
:
string
,
performedBy
:
string
,
oldValue
?:
string
,
newValue
?:
string
,
):
Promise
<
void
>
{
const
logId
=
this
.
drizzle
.
generateId
();
await
this
.
drizzle
.
db
.
insert
(
occurrenceLogs
).
values
({
id
:
logId
,
occurrenceId
,
action
,
description
,
oldValue
:
oldValue
||
null
,
newValue
:
newValue
||
null
,
performedBy
,
});
}
async
getTimeline
(
occurrenceId
:
string
):
Promise
<
LogResponseDto
[]
>
{
const
logs
=
await
this
.
drizzle
.
db
.
select
({
id
:
occurrenceLogs
.
id
,
occurrenceId
:
occurrenceLogs
.
occurrenceId
,
action
:
occurrenceLogs
.
action
,
description
:
occurrenceLogs
.
description
,
oldValue
:
occurrenceLogs
.
oldValue
,
newValue
:
occurrenceLogs
.
newValue
,
performedBy
:
occurrenceLogs
.
performedBy
,
createdAt
:
occurrenceLogs
.
createdAt
,
performedByUser
:
{
id
:
users
.
id
,
firstName
:
users
.
firstName
,
lastName
:
users
.
lastName
,
email
:
users
.
email
,
},
})
.
from
(
occurrenceLogs
)
.
leftJoin
(
users
,
eq
(
occurrenceLogs
.
performedBy
,
users
.
id
))
.
where
(
eq
(
occurrenceLogs
.
occurrenceId
,
occurrenceId
))
.
orderBy
(
desc
(
occurrenceLogs
.
createdAt
));
return
logs
.
map
((
log
)
=>
({
id
:
log
.
id
,
occurrenceId
:
log
.
occurrenceId
,
action
:
log
.
action
,
description
:
log
.
description
,
oldValue
:
log
.
oldValue
,
newValue
:
log
.
newValue
,
performedBy
:
log
.
performedBy
,
createdAt
:
log
.
createdAt
,
performedByUser
:
log
.
performedByUser
||
undefined
,
}));
}
// Helper methods for common logging scenarios
async
logOccurrenceCreated
(
occurrenceId
:
string
,
performedBy
:
string
,
title
:
string
,
):
Promise
<
void
>
{
await
this
.
createLog
(
occurrenceId
,
'CREATED'
,
`Occurrence "
${
title
}
" was created`
,
performedBy
,
);
}
async
logOccurrenceUpdated
(
occurrenceId
:
string
,
performedBy
:
string
,
changes
:
string
[],
):
Promise
<
void
>
{
await
this
.
createLog
(
occurrenceId
,
'UPDATED'
,
`Occurrence updated:
${
changes
.
join
(
', '
)}
`
,
performedBy
,
);
}
async
logStatusChanged
(
occurrenceId
:
string
,
performedBy
:
string
,
oldStatus
:
string
,
newStatus
:
string
,
):
Promise
<
void
>
{
await
this
.
createLog
(
occurrenceId
,
'STATUS_CHANGED'
,
`Status changed from
${
oldStatus
}
to
${
newStatus
}
`
,
performedBy
,
oldStatus
,
newStatus
,
);
}
async
logPriorityChanged
(
occurrenceId
:
string
,
performedBy
:
string
,
oldPriority
:
string
,
newPriority
:
string
,
):
Promise
<
void
>
{
await
this
.
createLog
(
occurrenceId
,
'PRIORITY_CHANGED'
,
`Priority changed from
${
oldPriority
}
to
${
newPriority
}
`
,
performedBy
,
oldPriority
,
newPriority
,
);
}
async
logAssignment
(
occurrenceId
:
string
,
performedBy
:
string
,
assigneeName
:
string
,
):
Promise
<
void
>
{
await
this
.
createLog
(
occurrenceId
,
'ASSIGNED'
,
`Occurrence assigned to
${
assigneeName
}
`
,
performedBy
,
);
}
async
logDualAssignment
(
occurrenceId
:
string
,
performedBy
:
string
,
assigneeName
:
string
,
managerName
:
string
,
):
Promise
<
void
>
{
await
this
.
createLog
(
occurrenceId
,
'DUAL_ASSIGNED'
,
`Occurrence assigned to
${
assigneeName
}
with manager
${
managerName
}
`
,
performedBy
,
);
}
async
logUnassignment
(
occurrenceId
:
string
,
performedBy
:
string
,
):
Promise
<
void
>
{
await
this
.
createLog
(
occurrenceId
,
'UNASSIGNED'
,
'Occurrence was unassigned'
,
performedBy
,
);
}
async
logCommentAdded
(
occurrenceId
:
string
,
performedBy
:
string
,
isInternal
:
boolean
=
false
,
):
Promise
<
void
>
{
const
commentType
=
isInternal
?
'internal comment'
:
'comment'
;
await
this
.
createLog
(
occurrenceId
,
'COMMENT_ADDED'
,
`A
${
commentType
}
was added`
,
performedBy
,
);
}
async
logAttachmentAdded
(
occurrenceId
:
string
,
performedBy
:
string
,
filename
:
string
,
):
Promise
<
void
>
{
await
this
.
createLog
(
occurrenceId
,
'ATTACHMENT_ADDED'
,
`Attachment "
${
filename
}
" was added`
,
performedBy
,
);
}
async
logAttachmentRemoved
(
occurrenceId
:
string
,
performedBy
:
string
,
filename
:
string
,
):
Promise
<
void
>
{
await
this
.
createLog
(
occurrenceId
,
'ATTACHMENT_REMOVED'
,
`Attachment "
${
filename
}
" was removed`
,
performedBy
,
);
}
async
logConclusionAdded
(
occurrenceId
:
string
,
performedBy
:
string
,
):
Promise
<
void
>
{
await
this
.
createLog
(
occurrenceId
,
'CONCLUSION_ADDED'
,
'A conclusion was added'
,
performedBy
,
);
}
async
logConclusionUpdated
(
occurrenceId
:
string
,
performedBy
:
string
,
):
Promise
<
void
>
{
await
this
.
createLog
(
occurrenceId
,
'CONCLUSION_UPDATED'
,
'The conclusion was updated'
,
performedBy
,
);
}
async
logOccurrenceDeleted
(
occurrenceId
:
string
,
performedBy
:
string
,
title
:
string
,
):
Promise
<
void
>
{
await
this
.
createLog
(
occurrenceId
,
'DELETED'
,
`Occurrence "
${
title
}
" was deleted`
,
performedBy
,
);
}
}
src/modules/occurrence/occurrence.controller.ts
View file @
41932462
...
...
@@ -21,11 +21,13 @@ import {
ApiQuery
,
}
from
'@nestjs/swagger'
;
import
{
OccurrenceService
}
from
'./occurrence.service'
;
import
{
OccurrenceLogService
}
from
'./occurrence-log.service'
;
import
{
CreateOccurrenceDto
}
from
'./dto/create-occurrence.dto'
;
import
{
UpdateOccurrenceDto
}
from
'./dto/update-occurrence.dto'
;
import
{
OccurrenceResponseDto
}
from
'./dto/occurrence-response.dto'
;
import
{
AssignOccurrenceDto
}
from
'./dto/assign-occurrence.dto'
;
import
{
DualAssignOccurrenceDto
}
from
'./dto/dual-assign-occurrence.dto'
;
import
{
LogResponseDto
}
from
'./dto/log-response.dto'
;
import
{
OccurrenceStatus
,
Priority
,
...
...
@@ -36,12 +38,17 @@ import {
}
from
'../../types'
;
import
{
RolesGuard
}
from
'../auth/guards/roles.guard'
;
import
{
Roles
}
from
'../auth/decorators/roles.decorator'
;
import
{
CurrentUser
}
from
'../auth/decorators/current-user.decorator'
;
import
{
UserResponseDto
}
from
'../user/dto/user-response.dto'
;
@
ApiTags
(
'occurrences'
)
@
ApiBearerAuth
(
'JWT-auth'
)
@
Controller
(
'occurrences'
)
export
class
OccurrenceController
{
constructor
(
private
readonly
occurrenceService
:
OccurrenceService
)
{}
constructor
(
private
readonly
occurrenceService
:
OccurrenceService
,
private
readonly
occurrenceLogService
:
OccurrenceLogService
,
)
{}
@
Post
()
@
ApiOperation
({
summary
:
'Create a new occurrence'
})
...
...
@@ -308,6 +315,32 @@ export class OccurrenceController {
return
this
.
occurrenceService
.
findOne
(
id
);
}
@
Get
(
':id/timeline'
)
@
ApiOperation
({
summary
:
'Get occurrence timeline/logs'
,
description
:
'Returns a chronological list of all actions and changes made to the occurrence'
,
})
@
ApiParam
({
name
:
'id'
,
description
:
'Occurrence unique identifier'
,
example
:
'clxyz123abc456def'
,
})
@
ApiResponse
({
status
:
200
,
description
:
'Timeline of occurrence changes'
,
type
:
[
LogResponseDto
],
})
@
ApiResponse
({
status
:
404
,
description
:
'Occurrence not found'
,
})
async
getTimeline
(@
Param
(
'id'
)
id
:
string
):
Promise
<
LogResponseDto
[]
>
{
// First check if occurrence exists
await
this
.
occurrenceService
.
findOne
(
id
);
return
this
.
occurrenceLogService
.
getTimeline
(
id
);
}
@
Patch
(
':id'
)
@
ApiOperation
({
summary
:
'Update occurrence by ID'
})
@
ApiParam
({
...
...
@@ -368,8 +401,13 @@ export class OccurrenceController {
async
assignOccurrence
(
@
Param
(
'id'
)
id
:
string
,
@
Body
()
assignOccurrenceDto
:
AssignOccurrenceDto
,
@
CurrentUser
()
user
:
UserResponseDto
,
):
Promise
<
OccurrenceResponseDto
>
{
return
this
.
occurrenceService
.
assignOccurrence
(
id
,
assignOccurrenceDto
);
return
this
.
occurrenceService
.
assignOccurrence
(
id
,
assignOccurrenceDto
,
user
.
id
,
);
}
@
Patch
(
':id/dual-assign'
)
...
...
@@ -407,10 +445,12 @@ export class OccurrenceController {
async
dualAssignOccurrence
(
@
Param
(
'id'
)
id
:
string
,
@
Body
()
dualAssignOccurrenceDto
:
DualAssignOccurrenceDto
,
@
CurrentUser
()
user
:
UserResponseDto
,
):
Promise
<
OccurrenceResponseDto
>
{
return
this
.
occurrenceService
.
dualAssignOccurrence
(
id
,
dualAssignOccurrenceDto
,
user
.
id
,
);
}
...
...
@@ -438,8 +478,9 @@ export class OccurrenceController {
})
async
unassignOccurrence
(
@
Param
(
'id'
)
id
:
string
,
@
CurrentUser
()
user
:
UserResponseDto
,
):
Promise
<
OccurrenceResponseDto
>
{
return
this
.
occurrenceService
.
unassignOccurrence
(
id
);
return
this
.
occurrenceService
.
unassignOccurrence
(
id
,
user
.
id
);
}
@
Delete
(
':id'
)
...
...
src/modules/occurrence/occurrence.module.ts
View file @
41932462
import
{
Module
}
from
'@nestjs/common'
;
import
{
OccurrenceService
}
from
'./occurrence.service'
;
import
{
OccurrenceController
}
from
'./occurrence.controller'
;
import
{
OccurrenceLogService
}
from
'./occurrence-log.service'
;
import
{
DrizzleService
}
from
'../../common/drizzle.service'
;
@
Module
({
controllers
:
[
OccurrenceController
],
providers
:
[
OccurrenceService
,
DrizzleService
],
exports
:
[
OccurrenceService
],
// Export service
for use in other modules
providers
:
[
OccurrenceService
,
OccurrenceLogService
,
DrizzleService
],
exports
:
[
OccurrenceService
,
OccurrenceLogService
],
// Export services
for use in other modules
})
export
class
OccurrenceModule
{}
src/modules/occurrence/occurrence.service.ts
View file @
41932462
...
...
@@ -9,6 +9,7 @@ import { UpdateOccurrenceDto } from './dto/update-occurrence.dto';
import
{
OccurrenceResponseDto
}
from
'./dto/occurrence-response.dto'
;
import
{
AssignOccurrenceDto
}
from
'./dto/assign-occurrence.dto'
;
import
{
DualAssignOccurrenceDto
}
from
'./dto/dual-assign-occurrence.dto'
;
import
{
OccurrenceLogService
}
from
'./occurrence-log.service'
;
import
{
OccurrenceStatus
,
Priority
,
...
...
@@ -26,7 +27,10 @@ import { eq, and, or, like, desc, count, sql } from 'drizzle-orm';
@
Injectable
()
export
class
OccurrenceService
{
constructor
(
private
readonly
drizzle
:
DrizzleService
)
{}
constructor
(
private
readonly
drizzle
:
DrizzleService
,
private
readonly
logService
:
OccurrenceLogService
,
)
{}
private
async
getOccurrenceWithRelations
(
occurrenceId
:
string
,
...
...
@@ -162,6 +166,13 @@ export class OccurrenceService {
...
createOccurrenceDto
,
});
// Log the creation
await
this
.
logService
.
logOccurrenceCreated
(
occurrenceId
,
createOccurrenceDto
.
reporterId
,
createOccurrenceDto
.
title
,
);
// Get the full occurrence with relations
const
occurrence
=
await
this
.
getOccurrenceWithRelations
(
occurrenceId
);
...
...
@@ -445,6 +456,7 @@ export class OccurrenceService {
async
assignOccurrence
(
occurrenceId
:
string
,
assignOccurrenceDto
:
AssignOccurrenceDto
,
performedBy
:
string
,
):
Promise
<
OccurrenceResponseDto
>
{
// Check if occurrence exists
await
this
.
findOne
(
occurrenceId
);
...
...
@@ -481,11 +493,19 @@ export class OccurrenceService {
});
}
// Log the assignment
await
this
.
logService
.
logAssignment
(
occurrenceId
,
performedBy
,
`
${
assignee
.
firstName
}
${
assignee
.
lastName
}
`
,
);
return
this
.
getOccurrenceWithRelations
(
occurrenceId
);
}
async
unassignOccurrence
(
occurrenceId
:
string
,
performedBy
:
string
,
):
Promise
<
OccurrenceResponseDto
>
{
// Check if occurrence exists
await
this
.
findOne
(
occurrenceId
);
...
...
@@ -499,12 +519,16 @@ export class OccurrenceService {
})
.
where
(
eq
(
occurrences
.
id
,
occurrenceId
));
// Log the unassignment
await
this
.
logService
.
logUnassignment
(
occurrenceId
,
performedBy
);
return
this
.
getOccurrenceWithRelations
(
occurrenceId
);
}
async
dualAssignOccurrence
(
occurrenceId
:
string
,
dualAssignOccurrenceDto
:
DualAssignOccurrenceDto
,
performedBy
:
string
,
):
Promise
<
OccurrenceResponseDto
>
{
// Check if occurrence exists
await
this
.
findOne
(
occurrenceId
);
...
...
@@ -553,6 +577,14 @@ export class OccurrenceService {
});
}
// Log the dual assignment
await
this
.
logService
.
logDualAssignment
(
occurrenceId
,
performedBy
,
`
${
assignee
.
firstName
}
${
assignee
.
lastName
}
`
,
`
${
manager
.
firstName
}
${
manager
.
lastName
}
`
,
);
return
this
.
getOccurrenceWithRelations
(
occurrenceId
);
}
}
src/types/index.ts
View file @
41932462
...
...
@@ -8,6 +8,20 @@ export type OccurrenceStatus =
|
'PARCIAL_RESOLVED'
|
'CANCELLED'
;
export
type
Priority
=
'LOW'
|
'MEDIUM'
|
'HIGH'
|
'URGENT'
;
export
type
LogAction
=
|
'CREATED'
|
'UPDATED'
|
'ASSIGNED'
|
'DUAL_ASSIGNED'
|
'UNASSIGNED'
|
'STATUS_CHANGED'
|
'PRIORITY_CHANGED'
|
'COMMENT_ADDED'
|
'ATTACHMENT_ADDED'
|
'ATTACHMENT_REMOVED'
|
'CONCLUSION_ADDED'
|
'CONCLUSION_UPDATED'
|
'DELETED'
;
// Enum constants for runtime usage
export
const
UserRoleEnum
=
{
...
...
@@ -31,3 +45,19 @@ export const PriorityEnum = {
HIGH
:
'HIGH'
as
const
,
URGENT
:
'URGENT'
as
const
,
}
as
const
;
export
const
LogActionEnum
=
{
CREATED
:
'CREATED'
as
const
,
UPDATED
:
'UPDATED'
as
const
,
ASSIGNED
:
'ASSIGNED'
as
const
,
DUAL_ASSIGNED
:
'DUAL_ASSIGNED'
as
const
,
UNASSIGNED
:
'UNASSIGNED'
as
const
,
STATUS_CHANGED
:
'STATUS_CHANGED'
as
const
,
PRIORITY_CHANGED
:
'PRIORITY_CHANGED'
as
const
,
COMMENT_ADDED
:
'COMMENT_ADDED'
as
const
,
ATTACHMENT_ADDED
:
'ATTACHMENT_ADDED'
as
const
,
ATTACHMENT_REMOVED
:
'ATTACHMENT_REMOVED'
as
const
,
CONCLUSION_ADDED
:
'CONCLUSION_ADDED'
as
const
,
CONCLUSION_UPDATED
:
'CONCLUSION_UPDATED'
as
const
,
DELETED
:
'DELETED'
as
const
,
}
as
const
;
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