Открыть боковую панель
effective-dev-opensource
Effective-Office
Коммиты
a47e9f17
Коммит
a47e9f17
создал
Июн 18, 2025
по автору
Radch-enko
Просмотр файлов
Feature: Booking service: debugged the creation and deletion of calendar events
владелец
4fee33b1
Изменения
42
Скрыть пробелы
Построчно
Рядом
.gitignore
Просмотр файла @
a47e9f17
...
...
@@ -74,4 +74,6 @@ coverage/
*.sqlite3
/backend/app/src/main/resources/.env.properties
/backend/app/src/main/resources/google-credentials.json
\ Нет новой строки в конце файла
/backend/app/src/main/resources/google-credentials.json
/oldBackendExample
/scripts
\ Нет новой строки в конце файла
backend/app/build.gradle.kts
Просмотр файла @
a47e9f17
...
...
@@ -10,7 +10,8 @@ dependencies {
implementation
(
project
(
":backend:feature:booking:core"
))
implementation
(
project
(
":backend:feature:booking:calendar:google"
))
implementation
(
project
(
":backend:feature:booking:calendar:dummy"
))
implementation
(
project
(
":backend:feature:workspace:core"
))
// implementation(project(":backend:feature:workspace:core"))
implementation
(
project
(
":backend:feature:workspace"
))
implementation
(
"org.springframework:spring-tx"
)
implementation
(
libs
.
springdoc
.
openapi
.
starter
.
webmvc
.
ui
)
...
...
backend/app/src/main/resources/application.yml
Просмотр файла @
a47e9f17
...
...
@@ -26,7 +26,10 @@ springdoc:
swagger-ui
:
path
:
/swagger-ui.html
operations-sorter
:
method
packages-to-scan
:
band.effective.office.backend.app.controller, band.effective.office.backend.feature.authorization.controller, band.effective.office.backend.feature.booking.core.controller
packages-to-scan
:
band.effective.office.backend.app.controller,
band.effective.office.backend.feature.authorization.controller,
band.effective.office.backend.feature.booking.core.controller,
band.effective.office.backend.feature.workspace.core.controller
management
:
endpoints
:
...
...
backend/core/domain/src/main/kotlin/band/effective/office/backend/core/domain/model/User.kt
Просмотр файла @
a47e9f17
...
...
@@ -11,9 +11,9 @@ import java.util.UUID
*/
data class
User
(
val
id
:
UUID
=
UUID
.
randomUUID
(),
@
field
:
NotBlank
(
message
=
"Username is required"
)
@
field
:
Size
(
min
=
3
,
max
=
5
0
,
message
=
"Username must be between 3 and 50 characters"
)
@
field
:
Size
(
min
=
3
,
max
=
25
5
,
message
=
"Username must be between 3 and 50 characters"
)
val
username
:
String
,
@
field
:
NotBlank
(
message
=
"Email is required"
)
...
...
backend/core/domain/src/main/kotlin/band/effective/office/backend/core/domain/model/Workspace.kt
Просмотр файла @
a47e9f17
package
band.effective.office.backend.core.domain.model
import
java.util.
*
import
java.util.
UUID
/**
* Domain model representing a workspace in the office.
...
...
@@ -12,7 +12,7 @@ import java.util.*
* @property zone The zone where the workspace is located
*/
data class
Workspace
(
var
id
:
UUID
?
,
var
id
:
UUID
,
var
name
:
String
,
var
tag
:
String
,
var
utilities
:
List
<
Utility
>,
...
...
backend/core/domain/src/main/kotlin/band/effective/office/backend/core/domain/service/UserDomainService.kt
Просмотр файла @
a47e9f17
...
...
@@ -16,6 +16,14 @@ interface UserDomainService {
*/
fun
findByUsername
(
username
:
String
):
User
?
/**
* Find a user by email.
*
* @param email The email to search for.
* @return The user if found, null otherwise.
*/
fun
findByEmail
(
email
:
String
):
User
?
/**
* Find a user by ID.
*
...
...
backend/core/domain/src/main/kotlin/band/effective/office/backend/core/domain/service/WorkspaceDomainService.kt
Просмотр файла @
a47e9f17
...
...
@@ -26,16 +26,6 @@ interface WorkspaceDomainService {
*/
fun
findAllByTag
(
tag
:
String
):
List
<
Workspace
>
/**
* Returns all workspaces with the given tag which are free during the given period
*
* @param tag tag name of requested workspaces
* @param beginTimestamp period start time
* @param endTimestamp period end time
* @return List of [Workspace] with the given [tag]
*/
fun
findAllFreeByPeriod
(
tag
:
String
,
beginTimestamp
:
Instant
,
endTimestamp
:
Instant
):
List
<
Workspace
>
/**
* Returns all workspace zones
*
...
...
backend/core/repository/src/main/resources/db/migration/V1__create_users_table.sql
удалено
100644 → 0
Просмотр файла @
4fee33b1
CREATE
TABLE
users
(
id
UUID
PRIMARY
KEY
,
username
VARCHAR
(
50
)
NOT
NULL
UNIQUE
,
email
VARCHAR
(
255
)
NOT
NULL
UNIQUE
,
first_name
VARCHAR
(
255
)
NOT
NULL
,
last_name
VARCHAR
(
255
)
NOT
NULL
,
created_at
TIMESTAMP
NOT
NULL
,
updated_at
TIMESTAMP
NOT
NULL
,
active
BOOLEAN
NOT
NULL
DEFAULT
TRUE
);
-- Add index for common queries
CREATE
INDEX
idx_users_username
ON
users
(
username
);
CREATE
INDEX
idx_users_email
ON
users
(
email
);
CREATE
INDEX
idx_users_active
ON
users
(
active
);
-- Add comment to table
COMMENT
ON
TABLE
users
IS
'Table storing user information'
;
\ Нет новой строки в конце файла
backend/core/repository/src/main/resources/db/migration/V1_create_tables.sql
0 → 100644
Просмотр файла @
a47e9f17
CREATE
TABLE
users
(
id
UUID
PRIMARY
KEY
,
username
VARCHAR
(
255
)
NOT
NULL
,
email
VARCHAR
(
255
)
NOT
NULL
UNIQUE
,
first_name
VARCHAR
(
255
)
NOT
NULL
,
last_name
VARCHAR
(
255
)
NOT
NULL
,
created_at
TIMESTAMP
NOT
NULL
,
updated_at
TIMESTAMP
NOT
NULL
,
active
BOOLEAN
NOT
NULL
DEFAULT
TRUE
);
-- Add index for common queries
CREATE
INDEX
idx_users_username
ON
users
(
username
);
CREATE
INDEX
idx_users_email
ON
users
(
email
);
CREATE
INDEX
idx_users_active
ON
users
(
active
);
-- Add comment to table
COMMENT
ON
TABLE
users
IS
'Table storing user information'
;
CREATE
TABLE
workspaces
(
id
UUID
PRIMARY
KEY
,
name
VARCHAR
(
255
)
NOT
NULL
UNIQUE
,
tag
VARCHAR
(
255
)
NOT
NULL
UNIQUE
,
zone_id
UUID
REFERENCES
workspace_zones
(
id
)
);
CREATE
TABLE
utilities
(
id
UUID
PRIMARY
KEY
,
name
VARCHAR
(
255
)
NOT
NULL
UNIQUE
,
icon_url
VARCHAR
(
255
)
NOT
NULL
UNIQUE
);
CREATE
TABLE
workspace_zones
(
id
UUID
PRIMARY
KEY
,
name
VARCHAR
(
255
)
NOT
NULL
UNIQUE
);
CREATE
TABLE
workspace_utilities
(
workspace_id
UUID
REFERENCES
workspaces
(
id
),
utility_id
UUID
REFERENCES
utilities
(
id
),
PRIMARY
KEY
(
workspace_id
,
utility_id
)
);
\ Нет новой строки в конце файла
backend/feature/authorization/src/main/kotlin/band/effective/office/backend/feature/authorization/config/SecurityConfig.kt
Просмотр файла @
a47e9f17
...
...
@@ -34,6 +34,7 @@ class SecurityConfig(
.
requestMatchers
(
"/swagger-ui.html/**"
,
"/swagger-ui/**"
,
"/api-docs/**"
,
"/v3/api-docs/**"
).
permitAll
()
.
requestMatchers
(
"/actuator/**"
).
permitAll
()
.
requestMatchers
(
"/bookings/**"
).
permitAll
()
// TODO for testing
.
requestMatchers
(
"/workspaces/**"
).
permitAll
()
// TODO for testing
.
anyRequest
().
authenticated
()
}
.
addFilterBefore
(
...
...
backend/feature/booking/calendar/google/build.gradle.kts
Просмотр файла @
a47e9f17
...
...
@@ -5,7 +5,8 @@ plugins {
dependencies
{
implementation
(
project
(
":backend:core:domain"
))
implementation
(
project
(
":backend:feature:booking:core"
))
implementation
(
project
(
":backend:feature:workspace:core"
))
// implementation(project(":backend:feature:workspace:core"))
implementation
(
project
(
":backend:feature:workspace"
))
implementation
(
libs
.
jakarta
)
implementation
(
libs
.
jakarta
.
servlet
.
api
)
...
...
backend/feature/booking/calendar/google/src/main/kotlin/band/effective/office/backend/feature/booking/calendar/google/GoogleCalendarProvider.kt
Просмотр файла @
a47e9f17
package
band.effective.office.backend.feature.booking.calendar.google
import
band.effective.office.backend.core.domain.model.User
import
band.effective.office.backend.core.domain.service.UserDomainService
import
band.effective.office.backend.core.domain.service.WorkspaceDomainService
import
band.effective.office.backend.feature.booking.core.domain.CalendarProvider
import
band.effective.office.backend.feature.booking.core.domain.model.Booking
import
band.effective.office.backend.feature.booking.core.domain.model.Workspace
import
com.google.api.client.googleapis.json.GoogleJsonResponseException
import
com.google.api.client.util.DateTime
import
com.google.api.services.calendar.Calendar
...
...
@@ -24,7 +25,9 @@ import org.springframework.stereotype.Component
@ConditionalOnProperty
(
name
=
[
"calendar.provider"
],
havingValue
=
"google"
)
class
GoogleCalendarProvider
(
private
val
calendar
:
Calendar
,
private
val
calendarIdProvider
:
CalendarIdProvider
private
val
calendarIdProvider
:
CalendarIdProvider
,
private
val
userDomainService
:
UserDomainService
,
private
val
workspaceDomainService
:
WorkspaceDomainService
)
:
CalendarProvider
{
private
val
logger
=
LoggerFactory
.
getLogger
(
GoogleCalendarProvider
::
class
.
java
)
...
...
@@ -41,7 +44,7 @@ class GoogleCalendarProvider(
logger
.
debug
(
"event: {}"
,
event
)
val
savedEvent
=
runCatching
{
calendar
.
events
().
insert
(
default
Calendar
,
event
).
execute
()
calendar
.
events
().
insert
(
workspace
Calendar
Id
,
event
).
execute
()
}.
onFailure
{
logger
.
error
(
"Failed to create event"
,
it
)
return
@onFailure
...
...
@@ -53,7 +56,7 @@ class GoogleCalendarProvider(
// Check if the event was successfully created in the workspace calendar
if
(!
checkEventAvailability
(
savedEvent
,
workspaceCalendarId
))
{
// If not available, delete the event and throw an exception
deleteEventBy
Id
(
savedEvent
.
id
)
deleteEventBy
Booking
(
booking
)
throw
WorkspaceUnavailableException
(
"Workspace ${booking.workspace.name} is unavailable at the requested time"
)
}
...
...
@@ -86,21 +89,21 @@ class GoogleCalendarProvider(
override
fun
deleteEvent
(
booking
:
Booking
)
{
logger
.
debug
(
"Deleting event for booking: {}"
,
booking
)
val
externalEventId
=
booking
.
externalEventId
?:
throw
IllegalArgumentException
(
"Booking must have an external event ID to be deleted"
)
booking
.
externalEventId
?:
throw
IllegalArgumentException
(
"Booking must have an external event ID to be deleted"
)
deleteEventBy
Id
(
externalEventId
)
deleteEventBy
Booking
(
booking
)
}
private
fun
deleteEventBy
Id
(
eventId
:
Str
ing
)
{
private
fun
deleteEventBy
Booking
(
booking
:
Book
ing
)
{
try
{
calendar
.
events
().
delete
(
defaultCalendar
,
eventId
).
execute
()
val
calendarId
=
getCalendarIdByWorkspace
(
booking
.
workspace
.
id
)
calendar
.
events
().
delete
(
calendarId
,
booking
.
externalEventId
).
execute
()
}
catch
(
e
:
GoogleJsonResponseException
)
{
if
(
e
.
statusCode
!=
404
&&
e
.
statusCode
!=
410
)
{
throw
e
}
// If the event doesn't exist (404) or has been deleted (410), ignore the exception
logger
.
warn
(
"Event with ID {} not found or already deleted"
,
e
ventId
)
logger
.
warn
(
"Event with ID {} not found or already deleted"
,
booking
.
externalE
ventId
)
}
}
...
...
@@ -115,7 +118,7 @@ class GoogleCalendarProvider(
val
workspaceCalendarId
=
getCalendarIdByWorkspace
(
workspaceId
)
val
events
=
listEvents
(
workspaceCalendarId
,
from
,
to
)
return
events
.
map
{
convertToBooking
(
it
)
}
return
events
.
map
{
convertToBooking
(
it
,
workspaceCalendarId
)
}
}
override
fun
findEventsByUser
(
userId
:
UUID
,
from
:
Instant
,
to
:
Instant
?):
List
<
Booking
>
{
...
...
@@ -126,43 +129,56 @@ class GoogleCalendarProvider(
to
?:
"infinity"
)
// In a real implementation, we would need to query the user's email from a user repository
// For simplicity, we'll assume we have a method to get the user's email
// Get the user's email from the user domain service
val
userEmail
=
getUserEmailById
(
userId
)
// Get all calendar IDs
val
calendarIds
=
calendarIdProvider
.
getAllCalendarIds
()
// Query all calendars for events with the user as an attendee or organizer
val
allEvent
s
=
mutableListOf
<
Event
>()
val
booking
s
=
mutableListOf
<
Booking
>()
for
(
calendarId
in
calendarIds
)
{
val
events
=
listEvents
(
calendarId
,
from
,
to
,
userEmail
)
al
lEvents
.
addAll
(
events
.
filter
{
event
->
v
al
filteredEvents
=
events
.
filter
{
event
->
event
.
organizer
?.
email
==
userEmail
||
event
.
attendees
?.
any
{
it
.
email
==
userEmail
}
==
true
})
}
bookings
.
addAll
(
filteredEvents
.
map
{
convertToBooking
(
it
,
calendarId
)
})
}
return
allEvents
.
map
{
convertToBooking
(
it
)
}
return
bookings
}
override
fun
findEventById
(
id
:
UUID
):
Booking
?
{
logger
.
debug
(
"Finding event with ID {}"
,
id
)
//
In a real implementation, we would need to map
the booking ID
to
the
external event ID
//
For simplicity, we'll assume the booking ID is the external
event
ID
val
externalEvent
Id
=
id
.
toString
()
//
Search for events with
the booking ID
in
the
description
//
We need to search in all calendars because we don't know which calendar the
event
is in
val
calendar
Id
s
=
calendarIdProvider
.
getAllCalendarIds
()
return
try
{
val
event
=
calendar
.
events
().
get
(
defaultCalendar
,
externalEventId
).
execute
()
convertToBooking
(
event
)
}
catch
(
e
:
GoogleJsonResponseException
)
{
if
(
e
.
statusCode
==
404
)
{
null
}
else
{
throw
e
// Search for events with the booking ID in the description
// We'll search for events in the last year to limit the search
val
oneYearAgo
=
Instant
.
now
().
minusSeconds
(
365
*
24
*
60
*
60
)
// TODO
for
(
calendarId
in
calendarIds
)
{
try
{
// Search for events with the booking ID in the description
val
events
=
listEvents
(
calendarId
,
oneYearAgo
,
null
)
// Find the event with the exact booking ID
val
event
=
events
.
firstOrNull
{
event
->
event
.
description
?.
contains
(
id
.
toString
())
==
true
}
if
(
event
!=
null
)
{
return
convertToBooking
(
event
,
calendarId
)
}
}
catch
(
e
:
Exception
)
{
logger
.
warn
(
"Failed to search for events in calendar {}: {}"
,
calendarId
,
e
.
message
)
}
}
return
null
}
// Helper methods
...
...
@@ -189,13 +205,26 @@ class GoogleCalendarProvider(
eventsRequest
.
q
=
q
}
return
eventsRequest
.
execute
().
items
?:
emptyList
()
return
try
{
eventsRequest
.
execute
().
items
?:
emptyList
()
}
catch
(
e
:
GoogleJsonResponseException
)
{
logger
.
error
(
"Failed to list events from Google Calendar: {}"
,
e
.
details
)
if
(
e
.
statusCode
==
404
)
{
logger
.
warn
(
"Calendar with ID {} not found"
,
calendarId
)
}
else
if
(
e
.
statusCode
==
403
)
{
logger
.
warn
(
"Permission denied for calendar with ID {}"
,
calendarId
)
}
emptyList
()
}
catch
(
e
:
Exception
)
{
logger
.
error
(
"Unexpected error when listing events from Google Calendar"
,
e
)
emptyList
()
}
}
private
fun
convertToGoogleEvent
(
booking
:
Booking
):
Event
{
val
event
=
Event
()
.
setSummary
(
"Booking: ${booking.workspace.
n
ame}"
)
.
setDescription
(
"Booking created by ${booking.owner.firstName} ${booking.owner.lastName}"
)
.
setSummary
(
"Booking: ${booking.workspace.
tag} - ${booking.owner.firstName} ${booking.owner.lastN
ame}"
)
.
setDescription
(
"Booking created by ${booking.owner.firstName} ${booking.owner.lastName}
\nBooking ID: ${booking.id}
"
)
.
setStart
(
EventDateTime
().
setDateTime
(
DateTime
(
booking
.
beginBooking
.
toEpochMilli
())))
.
setEnd
(
EventDateTime
().
setDateTime
(
DateTime
(
booking
.
endBooking
.
toEpochMilli
())))
...
...
@@ -211,21 +240,38 @@ class GoogleCalendarProvider(
return
event
}
private
fun
convertToBooking
(
event
:
Event
):
Booking
{
// In a real implementation, we would need to map the Google Calendar event to a Booking
// This would involve looking up users and workspaces by their IDs or emails
// For simplicity, we'll create dummy objects
private
fun
convertToBooking
(
event
:
Event
,
calendarId
:
String
?
=
null
):
Booking
{
// Get the organizer's email and find the corresponding user
logger
.
debug
(
"event.organizer?.email: ${event.organizer?.email}"
)
val
organizerEmail
=
event
.
organizer
.
email
?:
"unknown@example.com"
val
owner
=
findOrCreateUserByEmail
(
organizerEmail
)
val
owner
=
createDummyUser
(
event
.
organizer
?.
email
?:
"unknown@example.com"
)
val
participants
=
event
.
attendees
?.
map
{
attendee
->
createDummyUser
(
attendee
.
email
)
// Get the attendees' emails and find the corresponding users
val
participants
=
event
.
attendees
?.
mapNotNull
{
attendee
->
findOrCreateUserByEmail
(
attendee
.
email
)
}
?:
emptyList
()
val
workspace
=
createDummyWorkspace
(
event
.
summary
?:
"Unknown Workspace"
)
// Use the calendar ID (which is the workspace name) to find the workspace
// If calendarId is not provided, fall back to extracting from event summary
val
workspaceName
=
calendarId
?:
event
.
summary
?.
substringAfter
(
"Booking: "
)
?:
"Unknown Workspace"
// Try to find a workspace with this name
// In a real implementation, we might have a more robust way to map events to workspaces
val
workspace
=
workspaceDomainService
.
findAllByTag
(
"meeting"
)
.
firstOrNull
{
it
.
name
==
workspaceName
}
?:
throw
IllegalStateException
(
"Workspace with name $workspaceName not found"
)
// Extract booking ID from event description or use a random UUID if not found
val
bookingIdStr
=
event
.
description
?.
let
{
val
regex
=
"Booking ID: ([0-9a-f-]+)"
.
toRegex
()
val
matchResult
=
regex
.
find
(
it
)
matchResult
?.
groupValues
?.
get
(
1
)
}
val
bookingId
=
bookingIdStr
?.
let
{
UUID
.
fromString
(
it
)
}
?:
UUID
.
randomUUID
()
return
Booking
(
id
=
UUID
.
randomUUID
(),
// In a real implementation, we would map this to a persistent ID
id
=
bookingId
,
owner
=
owner
,
participants
=
participants
,
workspace
=
workspace
,
...
...
@@ -235,34 +281,73 @@ class GoogleCalendarProvider(
)
}
private
fun
createDummyUser
(
email
:
String
):
User
{
return
User
(
/**
* Finds a user by email or creates a new one if not found.
*
* @param email The email of the user to find or create
* @return The found or created user
*/
private
fun
findOrCreateUserByEmail
(
email
:
String
):
User
{
// Try to find a user with this email
val
user
=
userDomainService
.
findByEmail
(
email
)
if
(
user
!=
null
)
{
return
user
}
// If not found, create a new user
val
newUser
=
User
(
id
=
UUID
.
randomUUID
(),
username
=
email
.
substringBefore
(
"@"
),
email
=
email
,
firstName
=
"
Dummy
"
,
firstName
=
"
Unknown
"
,
lastName
=
"User"
)
}
private
fun
createDummyWorkspace
(
name
:
String
):
Workspace
{
return
Workspace
(
id
=
UUID
.
randomUUID
(),
name
=
name
,
tag
=
"meeting"
)
// Save the new user
return
userDomainService
.
createUser
(
newUser
)
}
private
fun
getUserEmailById
(
userId
:
UUID
):
String
{
//
In a real implementation, we would l
ook up the user's email in
a repository
// For simplicity, we'll return a dummy email
return
"stanislav.radchenko@effective.ba
nd"
//
L
ook up the user's email in
the user domain service
val
user
=
userDomainService
.
findById
(
userId
)
return
user
?.
email
?:
throw
IllegalArgumentException
(
"User with ID $userId not fou
nd"
)
}
/**
* Checks if a workspace is available at the requested time.
*
* @param event The event to check availability for
* @param workspaceCalendarId The calendar ID of the workspace
* @return True if the workspace is available, false otherwise
*/
private
fun
checkEventAvailability
(
event
:
Event
,
workspaceCalendarId
:
String
):
Boolean
{
// In a real implementation, we would check if the workspace is available at the requested time
// For simplicity, we'll assume it's always available
return
true
// Get the start and end time of the event
val
startTime
=
Instant
.
ofEpochMilli
(
event
.
start
.
dateTime
.
value
)
val
endTime
=
Instant
.
ofEpochMilli
(
event
.
end
.
dateTime
.
value
)
// Get all events in the workspace calendar during this time period
val
events
=
listEvents
(
workspaceCalendarId
,
startTime
,
endTime
)
// Check if there are any overlapping events
// Exclude the event itself if it's already in the calendar
val
overlappingEvents
=
events
.
filter
{
existingEvent
->
// Skip the event itself
if
(
existingEvent
.
id
==
event
.
id
)
{
return
@filter
false
}
// Check if the events overlap
val
existingStartTime
=
Instant
.
ofEpochMilli
(
existingEvent
.
start
.
dateTime
.
value
)
val
existingEndTime
=
Instant
.
ofEpochMilli
(
existingEvent
.
end
.
dateTime
.
value
)
// Events overlap if one starts before the other ends and ends after the other starts
(
startTime
.
isBefore
(
existingEndTime
)
&&
endTime
.
isAfter
(
existingStartTime
))
}
// The workspace is available if there are no overlapping events
return
overlappingEvents
.
isEmpty
()
}
// Exception class for workspace unavailability
...
...
backend/feature/booking/calendar/google/src/main/kotlin/band/effective/office/backend/feature/booking/calendar/google/WorkspaceCalendarIdProvider.kt
Просмотр файла @
a47e9f17
...
...
@@ -17,7 +17,7 @@ import org.springframework.stereotype.Component
@Component
@Primary
class
WorkspaceCalendarIdProvider
(
private
val
workspaceService
:
WorkspaceDomainService
private
val
workspace
Domain
Service
:
WorkspaceDomainService
,
)
:
CalendarIdProvider
{
private
val
logger
=
LoggerFactory
.
getLogger
(
this
::
class
.
java
)
...
...
@@ -44,10 +44,8 @@ class WorkspaceCalendarIdProvider(
// Try to get the workspace from the WorkspaceService
try
{
val
workspace
=
workspaceService
.
findById
(
workspaceId
)
val
workspace
=
workspace
Domain
Service
.
findById
(
workspaceId
)
if
(
workspace
!=
null
)
{
// In a real implementation, we would get the calendar ID from the workspace
// For now, we'll use the workspace name as the calendar ID
val
calendarId
=
workspace
.
name
// Cache the calendar ID for future use
...
...
@@ -71,7 +69,7 @@ class WorkspaceCalendarIdProvider(
override
fun
getAllCalendarIds
():
List
<
String
>
{
// Get all workspaces with the "meeting" tag
val
meetingWorkspaces
:
List
<
Workspace
>
=
try
{
workspaceService
.
findAllByTag
(
"meeting"
)
workspace
Domain
Service
.
findAllByTag
(
"meeting"
)
}
catch
(
e
:
Exception
)
{
logger
.
warn
(
"Failed to get meeting workspaces: {}"
,
e
.
message
)
emptyList
()
...
...
@@ -80,7 +78,7 @@ class WorkspaceCalendarIdProvider(
// Add calendar IDs for all meeting workspaces
meetingWorkspaces
.
forEach
{
workspace
->
val
workspaceId
=
workspace
.
id
if
(
workspaceId
!=
null
&&
!
calendarIds
.
containsKey
(
workspaceId
))
{
if
(!
calendarIds
.
containsKey
(
workspaceId
))
{
calendarIds
[
workspaceId
]
=
workspace
.
name
}
}
...
...
backend/feature/booking/core/src/main/kotlin/band/effective/office/backend/feature/booking/core/controller/BookingController.kt
Просмотр файла @
a47e9f17
package
band.effective.office.backend.feature.booking.core.controller
import
band.effective.office.backend.core.domain.service.UserDomainService
import
band.effective.office.backend.
feature.booking.
core.domain.
model
.Workspace
import
band.effective.office.backend.core.domain.
service
.Workspace
DomainService
import
band.effective.office.backend.feature.booking.core.dto.BookingDto
import
band.effective.office.backend.feature.booking.core.dto.CreateBookingDto
import
band.effective.office.backend.feature.booking.core.dto.UpdateBookingDto
...
...
@@ -33,9 +33,8 @@ import org.springframework.web.bind.annotation.RestController
@Tag
(
name
=
"Bookings"
,
description
=
"API for managing bookings"
)
class
BookingController
(
private
val
bookingService
:
BookingService
,
private
val
userService
:
UserDomainService
// In a real implementation, we would need a service for retrieving Workspace objects
// private val workspaceService: WorkspaceService
private
val
userService
:
UserDomainService
,
private
val
workspaceService
:
WorkspaceDomainService
,
)
{
/**
...
...
@@ -105,7 +104,7 @@ class BookingController(
}
else
->
{
// In a real implementation, we would need a method to get all bookings
//
TODO
In a real implementation, we would need a method to get all bookings
// For now, we'll return an empty list
emptyList
()
}
...
...
@@ -142,16 +141,8 @@ class BookingController(
userService
.
findById
(
userId
)
}
// In a real implementation, we would get the workspace from a service
// val workspace = workspaceService.getWorkspaceById(createBookingDto.workspaceId)
// ?: return ResponseEntity.notFound().build()
// For now, create a stub workspace
val
workspace
=
Workspace
(
id
=
createBookingDto
.
workspaceId
,
name
=
createBookingDto
.
workspaceId
.
toString
(),
tag
=
"meeting"
)
val
workspace
=
workspaceService
.
findById
(
createBookingDto
.
workspaceId
)
?:
return
ResponseEntity
.
notFound
().
build
()
// Convert DTO to a domain model and create the booking
val
booking
=
createBookingDto
.
toDomain
(
owner
,
participants
,
workspace
)
...
...
backend/feature/booking/core/src/main/kotlin/band/effective/office/backend/feature/booking/core/domain/model/Booking.kt
Просмотр файла @
a47e9f17
package
band.effective.office.backend.feature.booking.core.domain.model
import
band.effective.office.backend.core.domain.model.User
import
band.effective.office.backend.core.domain.model.Workspace
import
java.time.Instant
import
java.util.UUID
...
...
backend/feature/booking/core/src/main/kotlin/band/effective/office/backend/feature/booking/core/domain/model/Utility.kt
удалено
100644 → 0
Просмотр файла @
4fee33b1
package
band.effective.office.backend.feature.booking.core.domain.model
import
java.util.UUID
/**
* Represents a utility available in a workspace.
*/
data class
Utility
(
val
id
:
UUID
=
UUID
.
randomUUID
(),
val
name
:
String
,
val
iconUrl
:
String
,
val
count
:
Int
)
\ Нет новой строки в конце файла
backend/feature/booking/core/src/main/kotlin/band/effective/office/backend/feature/booking/core/domain/model/Workspace.kt
удалено
100644 → 0
Просмотр файла @
4fee33b1
package
band.effective.office.backend.feature.booking.core.domain.model
import
java.util.UUID
/**
* Represents a workspace in the office that can be booked.
*/
data class
Workspace
(
val
id
:
UUID
=
UUID
.
randomUUID
(),
val
name
:
String
,
val
tag
:
String
,
val
utilities
:
List
<
Utility
>
=
emptyList
(),
val
zone
:
WorkspaceZone
?
=
null
)
\ Нет новой строки в конце файла
backend/feature/booking/core/src/main/kotlin/band/effective/office/backend/feature/booking/core/domain/model/WorkspaceZone.kt
удалено
100644 → 0
Просмотр файла @
4fee33b1
package
band.effective.office.backend.feature.booking.core.domain.model
import
java.util.UUID
/**
* Represents a zone in the office where workspaces are located.
*/
data class
WorkspaceZone
(
val
id
:
UUID
=
UUID
.
randomUUID
(),
val
name
:
String
)
\ Нет новой строки в конце файла
backend/feature/booking/core/src/main/kotlin/band/effective/office/backend/feature/booking/core/dto/BookingDto.kt
Просмотр файла @
a47e9f17
package
band.effective.office.backend.feature.booking.core.dto
import
band.effective.office.backend.core.domain.model.User
import
band.effective.office.backend.core.domain.model.Utility
import
band.effective.office.backend.core.domain.model.Workspace
import
band.effective.office.backend.core.domain.model.WorkspaceZone
import
band.effective.office.backend.feature.booking.core.domain.model.Booking
import
band.effective.office.backend.feature.booking.core.domain.model.RecurrenceModel
import
band.effective.office.backend.feature.booking.core.domain.model.Workspace
import
com.fasterxml.jackson.annotation.JsonFormat
import
io.swagger.v3.oas.annotations.media.Schema
import
java.time.Instant
...
...
@@ -152,7 +154,7 @@ data class UtilityDto(
/**
* Converts a domain model to a DTO.
*/
fun
fromDomain
(
utility
:
band
.
effective
.
office
.
backend
.
feature
.
booking
.
core
.
domain
.
model
.
Utility
):
UtilityDto
{
fun
fromDomain
(
utility
:
Utility
):
UtilityDto
{
return
UtilityDto
(
id
=
utility
.
id
,
name
=
utility
.
name
,
...
...
@@ -178,7 +180,7 @@ data class WorkspaceZoneDto(
/**
* Converts a domain model to a DTO.
*/
fun
fromDomain
(
zone
:
band
.
effective
.
office
.
backend
.
feature
.
booking
.
core
.
domain
.
model
.
WorkspaceZone
):
WorkspaceZoneDto
{
fun
fromDomain
(
zone
:
WorkspaceZone
):
WorkspaceZoneDto
{
return
WorkspaceZoneDto
(
id
=
zone
.
id
,
name
=
zone
.
name
...
...
backend/feature/booking/core/src/main/kotlin/band/effective/office/backend/feature/booking/core/dto/CreateUpdateBookingDto.kt
Просмотр файла @
a47e9f17
package
band.effective.office.backend.feature.booking.core.dto
import
band.effective.office.backend.core.domain.model.User
import
band.effective.office.backend.core.domain.model.Workspace
import
band.effective.office.backend.feature.booking.core.domain.model.Booking
import
band.effective.office.backend.feature.booking.core.domain.model.Workspace
import
com.fasterxml.jackson.annotation.JsonFormat
import
io.swagger.v3.oas.annotations.media.Schema
import
jakarta.validation.Valid
...
...
Пред
1
2
3
След
Редактирование
Предварительный просмотр
Поддерживает Markdown
0%
Попробовать снова
или
прикрепить новый файл
.
Отмена
You are about to add
0
people
to the discussion. Proceed with caution.
Сначала завершите редактирование этого сообщения!
Отмена
Пожалуйста,
зарегистрируйтесь
или
войдите
чтобы прокомментировать