Commit d1ad87f9 authored by Tomáš Biloš's avatar Tomáš Biloš
Browse files

Merge branch 'main' into xbilos/fixes

parents 114eb5c0 8d5922ea
Pipeline #142547 waiting for manual action with stage
......@@ -32,7 +32,7 @@ Make sure you are using Java 11 to build and run the project.
### Backend:
In `backend` directory
In `backend/` directory
Build: `mvn clean install`
Run `mvn spring-boot:run -pl secret-archive-app`
......@@ -40,7 +40,8 @@ There is h2 console is available at http://localhost:8080/pa165/h2-console, User
### Frontend:
In `frontend/` directory
enter `npm start`. You may have to install it by your favorite package manager. The service will be available at [http://localhost:4200/](http://localhost:4200/).
Build with `npm install`. Will be needed for the first time (or in some cases of changes to used packages).
Run with `npm start`. You may have to install it by your favorite package manager. The service will be available at [http://localhost:4200/](http://localhost:4200/).
### Available logins:
......
......@@ -4,21 +4,17 @@ import cz.fi.muni.pa165.seminar4.group7.entity.Country;
import cz.fi.muni.pa165.seminar4.group7.entity.Mission;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.dao.DataAccessException;
import javax.transaction.Transactional;
import java.sql.Date;
import java.util.Calendar;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
/**
* @author Jan Smejkal
......
package cz.fi.muni.pa165.seminar4.group7.controller;
import cz.fi.muni.pa165.seminar4.group7.agent_assignment.AgentAssignmentService;
import cz.fi.muni.pa165.seminar4.group7.agent.AgentService;
import cz.fi.muni.pa165.seminar4.group7.mapping.BeanMappingService;
import cz.fi.muni.pa165.seminar4.group7.mission.MissionService;
import cz.fi.muni.pa165.seminar4.group7.agent_assignment.AgentAssignmentService;
import cz.fi.muni.pa165.seminar4.group7.dto.agent_assignment.AgentAssignmentCreateDTO;
import cz.fi.muni.pa165.seminar4.group7.dto.agent_assignment.AgentAssignmentUpdateDTO;
import cz.fi.muni.pa165.seminar4.group7.dto.agent_assignment.AgentAssignmentDTO;
import cz.fi.muni.pa165.seminar4.group7.dto.agent_assignment.AgentAssignmentUpdateDTO;
import cz.fi.muni.pa165.seminar4.group7.entity.AgentAssignment;
import cz.fi.muni.pa165.seminar4.group7.mapping.BeanMappingService;
import cz.fi.muni.pa165.seminar4.group7.mission.MissionService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
/**
* @author Jan Smejkal
......@@ -47,8 +53,8 @@ public class AssignmentController {
}
// create assignment: POST to /assignments, DTO contains agent ID, mission ID, start, duration
@RequestMapping(value = "/", method = RequestMethod.POST)
public final void createAssignment(@RequestBody AgentAssignmentCreateDTO assignmentCreateDTO) {
@PostMapping("/")
public final AgentAssignmentDTO createAssignment(@RequestBody AgentAssignmentCreateDTO assignmentCreateDTO) {
logger.debug("rest POST createAssignment()");
var assignment = beanMappingService.map(assignmentCreateDTO, AgentAssignment.class);
var agent = agentService.findById(assignmentCreateDTO.getAgentId());
......@@ -62,17 +68,27 @@ public class AssignmentController {
}
assignment.setMission(mission.get());
assignmentService.create(assignment);
AgentAssignment assignmentCreated = assignmentService.create(assignment).get();
return beanMappingService.map(assignmentCreated, AgentAssignmentDTO.class);
}
// remove assignment: DELETE to /assignments/{id}
@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
@DeleteMapping("/{id}")
public void deleteAssignment(@PathVariable("id") String id) {
logger.debug("rest DELETE id=" + id);
assignmentService.deleteById(id);
}
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
@GetMapping()
public List<AgentAssignmentDTO> getAllAssignments() {
logger.debug("rest GET all assignments");
List<AgentAssignment> assignments = assignmentService.findAll();
// return assignments.map(value -> beanMappingService.map(value, AgentAssignmentDTO.class)).orElse(null);
return StreamSupport.stream(assignments.spliterator(), false)
.map(o -> beanMappingService.map(o, AgentAssignmentDTO.class)).collect(Collectors.toList());
}
@GetMapping("/{id}")
public AgentAssignmentDTO getDetail(@PathVariable("id") String id) {
logger.debug("rest GET detail for id=" + id);
var assignment = assignmentService.findById(id);
......@@ -80,18 +96,20 @@ public class AssignmentController {
}
// Update assignment: DTO contains only duration and start
@RequestMapping(value = "/{id}", method = RequestMethod.PUT)
public void updateAssignment(@PathVariable("id") String id,
@PutMapping("/{id}")
public AgentAssignmentDTO updateAssignment(@PathVariable("id") String id,
@RequestBody @Valid AgentAssignmentUpdateDTO agentAssignmentUpdateDTO) {
logger.debug("rest PUT/update id=" + id);
if (!id.equals(agentAssignmentUpdateDTO.getId())) {
throw new IllegalArgumentException("Provided data is inconsistent");
throw new IllegalArgumentException("Provided data is inconsistent, IDs don't match!");
}
AgentAssignment oldAssignment = assignmentService.findById(id).get();
oldAssignment.setDurationInDays(agentAssignmentUpdateDTO.getDurationInDays());
oldAssignment.setReport(agentAssignmentUpdateDTO.getReport());
assignmentService.update(beanMappingService.map(oldAssignment, AgentAssignment.class));
var assignmentUpdated = assignmentService.update(oldAssignment).get();
return beanMappingService.map(assignmentUpdated, AgentAssignmentDTO.class);
}
}
......@@ -52,6 +52,7 @@
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
</dependencies>
......
......@@ -3,6 +3,7 @@ package cz.fi.muni.pa165.seminar4.group7.agent_assignment;
import cz.fi.muni.pa165.seminar4.group7.entity.AgentAssignment;
import cz.fi.muni.pa165.seminar4.group7.entity.PerformanceEvaluation;
import java.util.List;
import java.util.Optional;
/**
......@@ -16,8 +17,10 @@ public interface AgentAssignmentService {
*
* @param assignment
* to create.
*
* @return Optional of AgentAssignment that was created.
*/
void create(AgentAssignment assignment);
Optional<AgentAssignment> create(AgentAssignment assignment);
/**
* Delete agent assignment by id.
......@@ -41,7 +44,7 @@ public interface AgentAssignmentService {
* @param assignment
* -- updated assignment.
*/
void update(AgentAssignment assignment);
Optional<AgentAssignment> update(AgentAssignment assignment);
/**
* Adds report to assignment.
......@@ -81,4 +84,10 @@ public interface AgentAssignmentService {
*/
Iterable<AgentAssignment> getAssignmentsByMissionId(String id);
/**
* Returns all agent assignments, no matter the mission or agent.
*
* @return assignments - iterable of all agent assignments.
*/
List<AgentAssignment> findAll();
}
......@@ -5,6 +5,7 @@ import cz.fi.muni.pa165.seminar4.group7.dao.AgentDao;
import cz.fi.muni.pa165.seminar4.group7.dao.MissionDao;
import cz.fi.muni.pa165.seminar4.group7.entity.AgentAssignment;
import cz.fi.muni.pa165.seminar4.group7.entity.PerformanceEvaluation;
import org.hibernate.service.spi.ServiceException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
......@@ -29,11 +30,16 @@ public class AgentAssignmentServiceImpl implements AgentAssignmentService {
}
@Override
public void create(AgentAssignment assignment) {
public Optional<AgentAssignment> create(AgentAssignment assignment) throws ServiceException {
if (assignmentDao.findById(assignment.getId()).isPresent()) {
throw new IllegalArgumentException("Record for the given assignment already exists.");
}
assignmentDao.save(assignment);
try {
return findById(assignment.getId());
} catch (IllegalArgumentException e) {
throw new ServiceException("Could not create the assignment.");
}
}
@Override
......@@ -54,11 +60,16 @@ public class AgentAssignmentServiceImpl implements AgentAssignmentService {
}
@Override
public void update(AgentAssignment assignment) {
public Optional<AgentAssignment> update(AgentAssignment assignment) {
if (assignmentDao.findById(assignment.getId()).isEmpty()) {
throw new IllegalArgumentException("Record for the given assignment does not exist.");
}
assignmentDao.save(assignment);
try {
return findById(assignment.getId());
} catch (IllegalArgumentException e) {
throw new ServiceException("Could not create the assignment.");
}
}
@Override
......@@ -98,4 +109,9 @@ public class AgentAssignmentServiceImpl implements AgentAssignmentService {
return mission.get().getAgentAssignments();
}
@Override
public List<AgentAssignment> findAll() {
return (List<AgentAssignment>) assignmentDao.findAll();
}
}
......@@ -73,6 +73,7 @@ public class AgentAssignmentServiceTest {
@Test
void createNewTest() {
when(assignmentDao.save(assignment)).thenReturn(assignment);
when(assignmentDao.findById(assignment.getId())).thenReturn(Optional.empty(), Optional.of(assignment));
assignmentService.create(assignment);
......
package cz.fi.muni.pa165.seminar4.group7;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.Mockito.when;
import java.util.List;
import java.util.Optional;
import cz.fi.muni.pa165.seminar4.group7.agent.AgentFacadeImpl;
import cz.fi.muni.pa165.seminar4.group7.agent.AgentService;
import cz.fi.muni.pa165.seminar4.group7.country.CountryService;
import cz.fi.muni.pa165.seminar4.group7.dto.agent.AgentDTO;
import cz.fi.muni.pa165.seminar4.group7.dto.skill.SkillDTO;
import cz.fi.muni.pa165.seminar4.group7.entity.Agent;
import cz.fi.muni.pa165.seminar4.group7.entity.Skill;
import cz.fi.muni.pa165.seminar4.group7.facade.AgentFacade;
import cz.fi.muni.pa165.seminar4.group7.mapping.BeanMappingService;
import cz.fi.muni.pa165.seminar4.group7.skill.SkillService;
import org.junit.jupiter.api.BeforeAll;
......@@ -18,11 +16,12 @@ import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.boot.test.context.SpringBootTest;
import cz.fi.muni.pa165.seminar4.group7.dto.agent.AgentDTO;
import cz.fi.muni.pa165.seminar4.group7.dto.skill.SkillDTO;
import cz.fi.muni.pa165.seminar4.group7.entity.Agent;
import cz.fi.muni.pa165.seminar4.group7.entity.Skill;
import cz.fi.muni.pa165.seminar4.group7.facade.AgentFacade;
import java.util.List;
import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.Mockito.when;
/**
* @author Tomáš Biloš
......
package cz.fi.muni.pa165.seminar4.group7;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatNoException;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.when;
import java.util.List;
import java.util.Optional;
import cz.fi.muni.pa165.seminar4.group7.agent.AgentService;
import cz.fi.muni.pa165.seminar4.group7.agent.AgentServiceImpl;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.boot.test.context.SpringBootTest;
import cz.fi.muni.pa165.seminar4.group7.dao.AgentDao;
import cz.fi.muni.pa165.seminar4.group7.entity.Agent;
import cz.fi.muni.pa165.seminar4.group7.entity.AgentAssignment;
......@@ -25,6 +10,20 @@ import cz.fi.muni.pa165.seminar4.group7.entity.Country;
import cz.fi.muni.pa165.seminar4.group7.entity.Mission;
import cz.fi.muni.pa165.seminar4.group7.entity.Skill;
import cz.fi.muni.pa165.seminar4.group7.enums.AgentRole;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatNoException;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.when;
/**
* @author Tomáš Biloš
......
package cz.fi.muni.pa165.seminar4.group7;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType;
import static org.assertj.core.api.AssertionsForClassTypes.assertThatNoException;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.List;
import java.util.Optional;
import cz.fi.muni.pa165.seminar4.group7.country.CountryService;
import cz.fi.muni.pa165.seminar4.group7.country.CountryServiceImpl;
import cz.fi.muni.pa165.seminar4.group7.dao.CountryDao;
import cz.fi.muni.pa165.seminar4.group7.entity.Country;
import cz.fi.muni.pa165.seminar4.group7.entity.Mission;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.boot.test.context.SpringBootTest;
import cz.fi.muni.pa165.seminar4.group7.dao.CountryDao;
import cz.fi.muni.pa165.seminar4.group7.entity.Country;
import cz.fi.muni.pa165.seminar4.group7.entity.Mission;
import java.util.List;
import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType;
import static org.assertj.core.api.AssertionsForClassTypes.assertThatNoException;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* @author Jan Smejkal
......
package cz.fi.muni.pa165.seminar4.group7;
import static org.assertj.core.api.Assertions.assertThat;
import cz.fi.muni.pa165.seminar4.group7.dto.agent.AgentDTO;
import cz.fi.muni.pa165.seminar4.group7.dto.resource.ResourceDTO;
import cz.fi.muni.pa165.seminar4.group7.dto.skill.SkillDTO;
import cz.fi.muni.pa165.seminar4.group7.entity.Agent;
import cz.fi.muni.pa165.seminar4.group7.entity.Resource;
import cz.fi.muni.pa165.seminar4.group7.entity.Skill;
import cz.fi.muni.pa165.seminar4.group7.enums.AgentRole;
import cz.fi.muni.pa165.seminar4.group7.mapping.BeanMappingServiceImpl;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import cz.fi.muni.pa165.seminar4.group7.dto.resource.ResourceDTO;
import cz.fi.muni.pa165.seminar4.group7.entity.Resource;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Tomáš Biloš
*/
......
......@@ -5,6 +5,7 @@ import { AgentListComponent } from './agent/agent-list.component';
import { EditAgentComponent } from './agent/edit-agent.component';
import { AssignmentCreateComponent } from './assignment/assignment-create.component';
import { AssignmentDetailComponent } from './assignment/assignment-detail.component';
import { AssignmentListComponent } from './assignment/assignment-list.component';
import { AgentDetailGuard } from './auth/agent-detail.guard';
import { AgentListGuard } from './auth/agent-list.guard';
import { AuthComponent } from './auth/auth.component';
......@@ -39,10 +40,9 @@ const routes: Routes = [
canActivate: [AgentDetailGuard],
},
{ path: 'assignment/create', component: AssignmentCreateComponent },
{ path: 'assignment/:id', component: AssignmentDetailComponent },
{
path: 'agents',
component: AgentListComponent,
{ path: 'assignment/:id', component: AssignmentDetailComponent },
{ path: 'assignments', component: AssignmentListComponent },
{ path: 'agents', component: AgentListComponent ,
canActivate: [AgentListGuard],
},
{ path: 'countries', component: CountryListComponent },
......
......@@ -13,7 +13,6 @@ import { MatListModule } from '@angular/material/list';
import { MatSelectModule } from '@angular/material/select';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatTableModule } from '@angular/material/table';
import { MatToolbarModule } from '@angular/material/toolbar';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
......@@ -31,7 +30,11 @@ import { HomeComponent } from './home/home.component';
import { LoginComponent } from './login/login.component';
import { MissionDetailComponent } from './mission/mission-detail.component';
import { MissionListComponent } from './mission/mission-list.component';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatNativeDateModule } from "@angular/material/core";
import { MatToolbarModule } from "@angular/material/toolbar";
import { NotFoundComponent } from './not-found.component';
import {AssignmentListComponent} from "./assignment/assignment-list.component";
@NgModule({
declarations: [
......@@ -48,6 +51,7 @@ import { NotFoundComponent } from './not-found.component';
NotFoundComponent,
AssignmentDetailComponent,
AssignmentCreateComponent,
AssignmentListComponent,
LoginComponent,
],
......@@ -74,6 +78,9 @@ import { NotFoundComponent } from './not-found.component';
MatDividerModule,
MatButtonModule,
ReactiveFormsModule,
MatDatepickerModule,
MatNativeDateModule,
MatToolbarModule,
],
providers: [],
bootstrap: [AppComponent],
......
......@@ -2,35 +2,41 @@
Error loading create page: {{ errorMessage }}
</div>
<div *ngIf="confirmMessage">Assignment has been created.</div>
<div *ngIf="assignment && agents && missions && state === requestState.SUCCESS">
<div>Agent Assignment record</div>
<mat-form-field appearance="fill">
<mat-label>Start date:</mat-label>
<input matInput [(ngModel)]="assignment.start" />
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Duration:</mat-label>
<input matInput [(ngModel)]="assignment.durationInDays" />
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Agent's report:</mat-label>
<input matInput [(ngModel)]="assignment.report" />
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Assignment:</mat-label>
<div *ngIf="agents && missions && state === requestState.SUCCESS">
<form [formGroup]="edit">
<mat-toolbar>Agent Assignment record</mat-toolbar>
<mat-form-field appearance="fill">
<mat-label>Start date:</mat-label>
<input matInput type="Date" formControlName="start"/>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Duration (days):</mat-label>
<input matInput formControlName="durationInDays" type="number" min="0"/>
</mat-form-field>
</form>
<div>
<mat-form-field appearance="fill">
<mat-label>Agent:</mat-label>
<mat-select id="select-agent" [(ngModel)]="assignment.agentId" class="bx--text-input" required name="actionSelection" >
<mat-option *ngFor="let agent of agents" [value]="agent.id">{{agent.name}}</mat-option>
</mat-select>
<mat-option *ngFor="let agent of agents" [value]="agent.id" >{{agent.name}}</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Mission:</mat-label>
<mat-select id="select-mission" [(ngModel)]="assignment.missionId" class="bx--text-input" required name="actionSelection" >
<mat-option *ngFor="let mission of missions" [value]="mission.id">{{mission.name}}</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
<div *ngIf="agents && missions && state === requestState.SUCCESS">
<mat-form-field appearance="fill">
<mat-label>Mission:</mat-label>
<mat-select id="select-mission" [(ngModel)]="assignment.missionId" class="bx--text-input" required name="actionSelection" >
<mat-option *ngFor="let mission of missions" [value]="mission.id">{{mission.name}}</mat-option>
</mat-select>
<mat-label>Agent's report:</mat-label>
<input matInput [(ngModel)]="assignment.report" />
</mat-form-field>
</div>
<div>
<button mat-button (click)="createAssignment()">Create</button>
<button mat-button (click)="createAssignment()" disabled="{{ !edit.valid }}">Create</button>
</div>
......@@ -4,8 +4,11 @@ import { firstValueFrom } from 'rxjs';
import { environment } from 'src/environments/environment';
import { RequestState } from '../request-state.enum';
import { AssignmentCreate } from './assignment.interface';
import { Assignment } from './assignment.interface';
import { Agent } from './assignment.interface';
import { Mission } from './assignment.interface';
import {FormControl, FormGroup, Validators} from "@angular/forms";
import { Router } from "@angular/router"
@Component({
selector: 'assignment-create',
......@@ -15,16 +18,26 @@ export class AssignmentCreateComponent implements OnInit {
requestState = RequestState;
state: RequestState = this.requestState.SUCCESS;
errorMessage = '';
assignment: AssignmentCreate | undefined;
assignment: AssignmentCreate = {
start: new Date(),
durationInDays: 0,
report: '',
missionId: '',
agentId: ''
}
agents: Agent[] | null = null;
missions: Mission[] | null = null;
confirmMessage = false;
//src/app/assignment/assignment-create.component.html:8:45 - error TS2532: Object is possibly 'undefined'.
constructor(private httpClient: HttpClient, /*private route: ActivatedRoute*/) {}
edit = new FormGroup({
start: new FormControl( '', [Validators.required]),
durationInDays: new FormControl('', [
Validators