Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
K
kypo-adaptive-training
Manage
Activity
Members
Labels
Plan
Issues
3
Issue boards
Milestones
Iterations
Wiki
Requirements
Code
Merge requests
2
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Package Registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
MUNI-KYPO-CRP
backend-java
kypo-adaptive-training
Merge requests
!9
Resolve "Create missing service classes"
Code
Review changes
Check out branch
Download
Patches
Plain diff
Merged
Resolve "Create missing service classes"
16-create-missing-service-classes
into
8-integrate-the-necessary-parts-of-the-kypo2-training
Overview
0
Commits
12
Pipelines
0
Changes
23
Merged
Dominik Pilár
requested to merge
16-create-missing-service-classes
into
8-integrate-the-necessary-parts-of-the-kypo2-training
4 years ago
Overview
0
Commits
12
Pipelines
0
Changes
2
Expand
Closes
#16 (closed)
Edited
4 years ago
by
Dominik Pilár
👍
0
👎
0
Merge request reports
Compare
version 7
version 10
cd906ca7
4 years ago
version 9
08785412
4 years ago
version 8
c849e525
4 years ago
version 7
007c297a
4 years ago
version 6
ba54d812
4 years ago
version 5
3308a20d
4 years ago
version 4
86dbc8c3
4 years ago
version 3
eb01404b
4 years ago
version 2
9ec19a34
4 years ago
version 1
10885fff
4 years ago
8-integrate-the-necessary-parts-of-the-kypo2-training (base)
and
version 8
latest version
5771c903
12 commits,
4 years ago
version 10
cd906ca7
11 commits,
4 years ago
version 9
08785412
10 commits,
4 years ago
version 8
c849e525
9 commits,
4 years ago
version 7
007c297a
8 commits,
4 years ago
version 6
ba54d812
7 commits,
4 years ago
version 5
3308a20d
6 commits,
4 years ago
version 4
86dbc8c3
5 commits,
4 years ago
version 3
eb01404b
4 commits,
4 years ago
version 2
9ec19a34
3 commits,
4 years ago
version 1
10885fff
1 commit,
4 years ago
Show latest version
2 files
+
364
−
0
Inline
Compare changes
Side-by-side
Inline
Show whitespace changes
Show one file at a time
Files
2
Search (e.g. *.vue) (Ctrl+P)
src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingInstanceService.java
0 → 100644
+
305
−
0
Options
package
cz.muni.ics.kypo.training.adaptive.service.training
;
import
com.querydsl.core.types.Predicate
;
import
cz.muni.ics.kypo.training.adaptive.domain.AccessToken
;
import
cz.muni.ics.kypo.training.adaptive.domain.UserRef
;
import
cz.muni.ics.kypo.training.adaptive.domain.training.TrainingInstance
;
import
cz.muni.ics.kypo.training.adaptive.domain.training.TrainingRun
;
import
cz.muni.ics.kypo.training.adaptive.dto.responses.LockedPoolInfo
;
import
cz.muni.ics.kypo.training.adaptive.dto.responses.PoolInfoDTO
;
import
cz.muni.ics.kypo.training.adaptive.exceptions.*
;
import
cz.muni.ics.kypo.training.adaptive.repository.UserRefRepository
;
import
cz.muni.ics.kypo.training.adaptive.repository.training.AccessTokenRepository
;
import
cz.muni.ics.kypo.training.adaptive.repository.training.TrainingInstanceRepository
;
import
cz.muni.ics.kypo.training.adaptive.repository.training.TrainingRunRepository
;
import
cz.muni.ics.kypo.training.adaptive.service.api.SandboxServiceApi
;
import
org.apache.commons.lang3.RandomStringUtils
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Qualifier
;
import
org.springframework.data.domain.Page
;
import
org.springframework.data.domain.Pageable
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.stereotype.Service
;
import
org.springframework.web.reactive.function.client.WebClient
;
import
reactor.core.publisher.Mono
;
import
java.time.Clock
;
import
java.time.LocalDateTime
;
import
java.util.HashSet
;
import
java.util.Optional
;
import
java.util.Random
;
import
java.util.Set
;
/**
* The type Training instance service.
*/
@Service
public
class
TrainingInstanceService
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
TrainingInstanceService
.
class
);
private
TrainingInstanceRepository
trainingInstanceRepository
;
private
TrainingRunRepository
trainingRunRepository
;
private
AccessTokenRepository
accessTokenRepository
;
private
UserRefRepository
organizerRefRepository
;
private
SecurityService
securityService
;
private
final
Random
random
=
new
Random
();
/**
* Instantiates a new Training instance service.
*
* @param trainingInstanceRepository the training instance repository
* @param accessTokenRepository the access token repository
* @param trainingRunRepository the training run repository
* @param organizerRefRepository the organizer ref repository
* @param securityService the security service
*/
@Autowired
public
TrainingInstanceService
(
TrainingInstanceRepository
trainingInstanceRepository
,
AccessTokenRepository
accessTokenRepository
,
TrainingRunRepository
trainingRunRepository
,
UserRefRepository
organizerRefRepository
,
SecurityService
securityService
)
{
this
.
trainingInstanceRepository
=
trainingInstanceRepository
;
this
.
trainingRunRepository
=
trainingRunRepository
;
this
.
accessTokenRepository
=
accessTokenRepository
;
this
.
organizerRefRepository
=
organizerRefRepository
;
this
.
securityService
=
securityService
;
}
/**
* Finds basic info about Training Instance by id
*
* @param instanceId of a Training Instance that would be returned
* @return specific {@link TrainingInstance} by id
* @throws EntityNotFoundException training instance is not found.
*/
public
TrainingInstance
findById
(
Long
instanceId
)
{
return
trainingInstanceRepository
.
findById
(
instanceId
)
.
orElseThrow
(()
->
new
EntityNotFoundException
(
new
EntityErrorDetail
(
TrainingInstance
.
class
,
"id"
,
instanceId
.
getClass
(),
instanceId
)));
}
/**
* Find specific Training instance by id including its associated Training definition.
*
* @param instanceId the instance id
* @return the {@link TrainingInstance}
*/
public
TrainingInstance
findByIdIncludingDefinition
(
Long
instanceId
)
{
return
trainingInstanceRepository
.
findByIdIncludingDefinition
(
instanceId
)
.
orElseThrow
(()
->
new
EntityNotFoundException
(
new
EntityErrorDetail
(
TrainingInstance
.
class
,
"id"
,
instanceId
.
getClass
(),
instanceId
)));
}
/**
* Find all Training Instances.
*
* @param predicate represents a predicate (boolean-valued function) of one argument.
* @param pageable pageable parameter with information about pagination.
* @return all {@link TrainingInstance}s
*/
public
Page
<
TrainingInstance
>
findAll
(
Predicate
predicate
,
Pageable
pageable
)
{
return
trainingInstanceRepository
.
findAll
(
predicate
,
pageable
);
}
/**
* Find all training instances based on the logged in user.
*
* @param predicate the predicate
* @param pageable the pageable
* @param loggedInUserId the logged in user id
* @return the page
*/
public
Page
<
TrainingInstance
>
findAll
(
Predicate
predicate
,
Pageable
pageable
,
Long
loggedInUserId
)
{
return
trainingInstanceRepository
.
findAll
(
predicate
,
pageable
,
loggedInUserId
);
}
/**
* Creates new training instance
*
* @param trainingInstance to be created
* @return created {@link TrainingInstance}
*/
public
TrainingInstance
create
(
TrainingInstance
trainingInstance
)
{
trainingInstance
.
setAccessToken
(
generateAccessToken
(
trainingInstance
.
getAccessToken
()));
if
(
trainingInstance
.
getStartTime
().
isAfter
(
trainingInstance
.
getEndTime
()))
{
throw
new
EntityConflictException
(
new
EntityErrorDetail
(
TrainingInstance
.
class
,
"id"
,
trainingInstance
.
getId
().
getClass
(),
trainingInstance
.
getId
(),
"End time must be later than start time."
));
}
addLoggedInUserAsOrganizerToTrainingInstance
(
trainingInstance
);
return
trainingInstanceRepository
.
save
(
trainingInstance
);
}
/**
* updates training instance
*
* @param trainingInstanceToUpdate to be updated
* @return new access token if it was changed
* @throws EntityNotFoundException training instance is not found.
* @throws EntityConflictException cannot be updated for some reason.
*/
public
String
update
(
TrainingInstance
trainingInstanceToUpdate
)
{
validateStartAndEndTime
(
trainingInstanceToUpdate
);
TrainingInstance
trainingInstance
=
findById
(
trainingInstanceToUpdate
.
getId
());
//add original organizers and poolId to update
trainingInstanceToUpdate
.
setOrganizers
(
new
HashSet
<>(
trainingInstance
.
getOrganizers
()));
addLoggedInUserAsOrganizerToTrainingInstance
(
trainingInstanceToUpdate
);
trainingInstanceToUpdate
.
setPoolId
(
trainingInstance
.
getPoolId
());
//check if TI is running, true - only title can be changed, false - any field can be changed
if
(
LocalDateTime
.
now
(
Clock
.
systemUTC
()).
isAfter
(
trainingInstance
.
getStartTime
()))
{
this
.
checkChangedFieldsOfRunningTrainingInstance
(
trainingInstanceToUpdate
,
trainingInstance
);
}
else
{
//check if new access token should be generated, if not original is kept
if
(
shouldGenerateNewToken
(
trainingInstance
.
getAccessToken
(),
trainingInstanceToUpdate
.
getAccessToken
()))
{
trainingInstanceToUpdate
.
setAccessToken
(
generateAccessToken
(
trainingInstanceToUpdate
.
getAccessToken
()));
}
else
{
trainingInstanceToUpdate
.
setAccessToken
(
trainingInstance
.
getAccessToken
());
}
}
trainingInstanceRepository
.
save
(
trainingInstanceToUpdate
);
return
trainingInstanceToUpdate
.
getAccessToken
();
}
private
void
validateStartAndEndTime
(
TrainingInstance
trainingInstance
)
{
if
(
trainingInstance
.
getStartTime
().
isAfter
(
trainingInstance
.
getEndTime
()))
{
throw
new
EntityConflictException
(
new
EntityErrorDetail
(
TrainingInstance
.
class
,
"id"
,
trainingInstance
.
getId
().
getClass
(),
trainingInstance
.
getId
(),
"End time must be later than start time."
));
}
}
private
void
checkChangedFieldsOfRunningTrainingInstance
(
TrainingInstance
trainingInstanceToUpdate
,
TrainingInstance
currentTrainingInstance
)
{
if
(!
currentTrainingInstance
.
getStartTime
().
equals
(
trainingInstanceToUpdate
.
getStartTime
()))
{
throw
new
EntityConflictException
(
new
EntityErrorDetail
(
TrainingInstance
.
class
,
"id"
,
Long
.
class
,
trainingInstanceToUpdate
.
getId
(),
"The start time of the running training instance cannot be changed. Only title can be updated."
));
}
else
if
(!
currentTrainingInstance
.
getEndTime
().
equals
(
trainingInstanceToUpdate
.
getEndTime
()))
{
throw
new
EntityConflictException
(
new
EntityErrorDetail
(
TrainingInstance
.
class
,
"id"
,
Long
.
class
,
trainingInstanceToUpdate
.
getId
(),
"The end time of the running training instance cannot be changed. Only title can be updated."
));
}
else
if
(!
currentTrainingInstance
.
getAccessToken
().
equals
(
trainingInstanceToUpdate
.
getAccessToken
()))
{
throw
new
EntityConflictException
(
new
EntityErrorDetail
(
TrainingInstance
.
class
,
"id"
,
Long
.
class
,
trainingInstanceToUpdate
.
getId
(),
"The access token of the running training instance cannot be changed. Only title can be updated."
));
}
}
private
boolean
shouldGenerateNewToken
(
String
originalToken
,
String
newToken
)
{
//new token should not be generated if token in update equals original token or if token in update equals original token without PIN
String
tokenWithoutPin
=
originalToken
.
substring
(
0
,
originalToken
.
length
()
-
5
);
return
!(
newToken
.
equals
(
tokenWithoutPin
)
||
originalToken
.
equals
(
newToken
));
}
private
String
generateAccessToken
(
String
accessToken
)
{
String
newPass
=
""
;
boolean
generated
=
false
;
while
(!
generated
)
{
int
firstNumber
=
this
.
random
.
nextInt
(
5
)
+
5
;
String
pin
=
firstNumber
+
RandomStringUtils
.
random
(
3
,
false
,
true
);
newPass
=
accessToken
+
"-"
+
pin
;
Optional
<
AccessToken
>
pW
=
accessTokenRepository
.
findOneByAccessToken
(
newPass
);
if
(!
pW
.
isPresent
())
{
generated
=
true
;
}
}
AccessToken
newTokenInstance
=
new
AccessToken
();
newTokenInstance
.
setAccessToken
(
newPass
);
accessTokenRepository
.
saveAndFlush
(
newTokenInstance
);
return
newPass
;
}
private
void
addLoggedInUserAsOrganizerToTrainingInstance
(
TrainingInstance
trainingInstance
)
{
Optional
<
UserRef
>
authorOfTrainingInstance
=
organizerRefRepository
.
findUserByUserRefId
(
securityService
.
getUserRefIdFromUserAndGroup
());
if
(
authorOfTrainingInstance
.
isPresent
())
{
trainingInstance
.
addOrganizer
(
authorOfTrainingInstance
.
get
());
}
else
{
UserRef
userRef
=
securityService
.
createUserRefEntityByInfoFromUserAndGroup
();
trainingInstance
.
addOrganizer
(
organizerRefRepository
.
save
(
userRef
));
}
}
/**
* deletes training instance
*
* @param trainingInstance the training instance to be deleted.
* @throws EntityNotFoundException training instance is not found.
* @throws EntityConflictException cannot be deleted for some reason.
*/
public
void
delete
(
TrainingInstance
trainingInstance
)
{
trainingInstanceRepository
.
delete
(
trainingInstance
);
LOG
.
debug
(
"Training instance with id: {} deleted."
,
trainingInstance
.
getId
());
}
/**
* deletes training instance
*
* @param id the training instance to be deleted.
* @throws EntityNotFoundException training instance is not found.
* @throws EntityConflictException cannot be deleted for some reason.
*/
public
void
deleteById
(
Long
id
)
{
trainingInstanceRepository
.
deleteById
(
id
);
LOG
.
debug
(
"Training instance with id: {} deleted."
,
id
);
}
/**
* Update training instance pool training instance.
*
* @param trainingInstance the training instance
* @return the training instance
*/
public
TrainingInstance
updateTrainingInstancePool
(
TrainingInstance
trainingInstance
)
{
return
trainingInstanceRepository
.
saveAndFlush
(
trainingInstance
);
}
/**
* Finds all Training Runs of specific Training Instance.
*
* @param instanceId id of Training Instance whose Training Runs would be returned.
* @param isActive if isActive attribute is True, only active runs are returned
* @param pageable pageable parameter with information about pagination.
* @return {@link TrainingRun}s of specific {@link TrainingInstance}
*/
public
Page
<
TrainingRun
>
findTrainingRunsByTrainingInstance
(
Long
instanceId
,
Boolean
isActive
,
Pageable
pageable
)
{
// check if instance exists
this
.
findById
(
instanceId
);
if
(
isActive
==
null
)
{
return
trainingRunRepository
.
findAllByTrainingInstanceId
(
instanceId
,
pageable
);
}
else
if
(
isActive
)
{
return
trainingRunRepository
.
findAllActiveByTrainingInstanceId
(
instanceId
,
pageable
);
}
else
{
return
trainingRunRepository
.
findAllInactiveByTrainingInstanceId
(
instanceId
,
pageable
);
}
}
/**
* Find UserRefs by userRefId
*
* @param usersRefId of wanted UserRefs
* @return {@link UserRef}s with corresponding userRefIds
*/
public
Set
<
UserRef
>
findUserRefsByUserRefIds
(
Set
<
Long
>
usersRefId
)
{
return
organizerRefRepository
.
findUsers
(
usersRefId
);
}
/**
* Check if instance is finished.
*
* @param trainingInstanceId the training instance id
* @return true if instance is finished, false if not
*/
public
boolean
checkIfInstanceIsFinished
(
Long
trainingInstanceId
)
{
return
trainingInstanceRepository
.
isFinished
(
trainingInstanceId
,
LocalDateTime
.
now
(
Clock
.
systemUTC
()));
}
/**
* Find specific Training instance by its access token and with start time before current time and ending time after current time
*
* @param accessToken of Training instance
* @return Training instance
*/
public
TrainingInstance
findByStartTimeAfterAndEndTimeBeforeAndAccessToken
(
String
accessToken
)
{
return
trainingInstanceRepository
.
findByStartTimeAfterAndEndTimeBeforeAndAccessToken
(
LocalDateTime
.
now
(
Clock
.
systemUTC
()),
accessToken
)
.
orElseThrow
(()
->
new
EntityNotFoundException
(
new
EntityErrorDetail
(
TrainingInstance
.
class
,
"accessToken"
,
accessToken
.
getClass
(),
accessToken
,
"There is no active game session matching access token."
)));
}
}
Loading