diff --git a/CHANGELOG.md b/CHANGELOG.md
index cc1958b598844ba7c234259f3ae9469e358d86bd..bbc7f43922850fb939b6d25703e8531834f1e88c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
+## [2.2.4]
+
+### Added
+
+### Changed
+- Promote button description is now a bit more clear.
+
+### Fixed
+- Offer position to selected applicants did not work.
+
## [2.2.3]
### Added
diff --git a/build.gradle.kts b/build.gradle.kts
index 8ccbf59a025e74d3f383929a6af344aaf0200247..6f498c52578be06852479470346c8f144ba88836 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -4,7 +4,7 @@ import nl.javadude.gradle.plugins.license.DownloadLicensesExtension
import nl.javadude.gradle.plugins.license.LicenseExtension
group = "nl.tudelft.tam"
-version = "2.2.3"
+version = "2.2.4"
val javaVersion = JavaVersion.VERSION_21
diff --git a/src/main/java/nl/tudelft/tam/controller/ApplicationController.java b/src/main/java/nl/tudelft/tam/controller/ApplicationController.java
index 8b30913a76db8d4437e057c8dabe5c3046dc198d..87d200f408988493e8ff2c3510721bf7db26759e 100644
--- a/src/main/java/nl/tudelft/tam/controller/ApplicationController.java
+++ b/src/main/java/nl/tudelft/tam/controller/ApplicationController.java
@@ -37,6 +37,7 @@ import nl.tudelft.labracore.lib.security.user.Person;
import nl.tudelft.librador.util.PageUtil;
import nl.tudelft.tam.dto.create.ApplicationCreateDTO;
import nl.tudelft.tam.dto.util.ApplicationFilterDTO;
+import nl.tudelft.tam.dto.util.BulkOfferDTO;
import nl.tudelft.tam.dto.view.details.ApplicationDetailsJobOfferDTO;
import nl.tudelft.tam.enums.Status;
import nl.tudelft.tam.model.Application;
@@ -290,8 +291,8 @@ public class ApplicationController {
@PostMapping("offer/{offerId}")
@PreAuthorize("@authorisationService.canManageJob(#offerId)")
public String bulkOfferApplication(@AuthenticatedPerson Person person, @PathVariable Long offerId,
- @RequestParam String identifiersAll) {
- applicationService.bulkOffer(offerId, identifiersAll, person.getId());
+ BulkOfferDTO offerTo) {
+ applicationService.bulkOffer(offerId, offerTo.getIdentifiersAll(), person.getId());
return "redirect:/job-offer/" + offerId;
}
diff --git a/src/main/java/nl/tudelft/tam/dto/util/BulkOfferDTO.java b/src/main/java/nl/tudelft/tam/dto/util/BulkOfferDTO.java
new file mode 100644
index 0000000000000000000000000000000000000000..45c733b840fa6e7460651bfda1d8f9a948236af7
--- /dev/null
+++ b/src/main/java/nl/tudelft/tam/dto/util/BulkOfferDTO.java
@@ -0,0 +1,33 @@
+/*
+ * TAM
+ * Copyright (C) 2021 - Delft University of Technology
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+package nl.tudelft.tam.dto.util;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class BulkOfferDTO {
+
+ private String identifiersAll;
+
+}
diff --git a/src/main/java/nl/tudelft/tam/dto/view/details/ApplicationDetailsPersonDTO.java b/src/main/java/nl/tudelft/tam/dto/view/details/ApplicationDetailsPersonDTO.java
index b0d208efb7f2758ca074cb3477805a0188ab2239..54bddc02727759ba8a6e85d4650a1f496a88e627 100644
--- a/src/main/java/nl/tudelft/tam/dto/view/details/ApplicationDetailsPersonDTO.java
+++ b/src/main/java/nl/tudelft/tam/dto/view/details/ApplicationDetailsPersonDTO.java
@@ -33,4 +33,7 @@ public class ApplicationDetailsPersonDTO extends ApplicationSummaryDTO {
@Builder.Default
private Boolean taBefore = false;
+
+ @Builder.Default
+ private Boolean isHeadTA = false;
}
diff --git a/src/main/java/nl/tudelft/tam/service/ApplicationService.java b/src/main/java/nl/tudelft/tam/service/ApplicationService.java
index ef5d14c18fa7ba9ecf0fd4a28a7b9d7e473d67a0..d8ea3be426772237a171ef1fc2d75cc54a57f509 100644
--- a/src/main/java/nl/tudelft/tam/service/ApplicationService.java
+++ b/src/main/java/nl/tudelft/tam/service/ApplicationService.java
@@ -26,7 +26,6 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.commons.lang3.ArrayUtils;
-import org.checkerframework.checker.units.qual.A;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@@ -446,6 +445,37 @@ public class ApplicationService {
.anyMatch(offer -> appExistsFor(personId, offer.getId()));
}
+ /**
+ * Sets the TAed before field for a list of applications.
+ *
+ * @param applications The applications
+ * @param jobOfferId The job offer for which to check
+ */
+ public void setRoleInformation(List<ApplicationDetailsPersonDTO> applications, Long jobOfferId) {
+ JobOffer jobOffer = jobOfferService.findByIdOrThrow(jobOfferId);
+ EditionDetailsDTO edition = editionService.getEditionById(jobOffer.getEditionId());
+ CourseDetailsDTO course = courseService.getOrThrow(edition.getCourse().getId());
+ List<Long> personIds = applications.stream().map(ApplicationSummaryDTO::getPersonId).toList();
+ Set<Long> taIds = roleService
+ .getRolesById(course.getEditions().stream().map(EditionSummaryDTO::getId)
+ .collect(Collectors.toList()), personIds)
+ .stream()
+ .filter(r -> r.getType() == RoleDetailsDTO.TypeEnum.TA
+ || r.getType() == RoleDetailsDTO.TypeEnum.HEAD_TA)
+ .map(r -> r.getPerson().getId())
+ .collect(Collectors.toSet());
+ Set<Long> headTAIds = roleService
+ .getRolesById(List.of(edition.getId()), personIds)
+ .stream()
+ .filter(r -> r.getType() == RoleDetailsDTO.TypeEnum.HEAD_TA)
+ .map(r -> r.getPerson().getId())
+ .collect(Collectors.toSet());
+ applications.forEach(a -> {
+ a.setTaBefore(taIds.contains(a.getPersonId()));
+ a.setIsHeadTA(headTAIds.contains(a.getPersonId()));
+ });
+ }
+
/**
* Check if a person has ta'ed a course which is provided by a job offer.
*
@@ -543,14 +573,15 @@ public class ApplicationService {
.getPeopleById(
apps.stream().map(a -> a.getId().getPersonId()).collect(Collectors.toList()))
.stream().collect(Collectors.toMap(PersonSummaryDTO::getId, p -> p));
- return apps.stream().map(a -> {
+ List<ApplicationDetailsPersonDTO> dtos = apps.stream().map(a -> {
ApplicationDetailsPersonDTO dto = mapper.map(a, ApplicationDetailsPersonDTO.class);
dto.setPersonId(a.getId().getPersonId());
dto.setJobOfferId(a.getId().getJobOfferId());
dto.setPerson(ppl.get(dto.getPersonId()));
- dto.setTaBefore(hasTAedBefore(dto.getPersonId(), dto.getJobOfferId()));
return dto;
}).toList();
+ setRoleInformation(dtos, id);
+ return dtos;
}
/**
diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties
index 3c893e1411bacdaae5dd6be72d04efbeb0ce6650..40647b75cd73addfa351895aa7bffe63a8e8396a 100644
--- a/src/main/resources/messages.properties
+++ b/src/main/resources/messages.properties
@@ -239,10 +239,10 @@ jobOffer.accept = Accept
jobOffer.reject = Reject
jobOffer.promote = Promote
jobOffer.promote.confirm = Confirm Promotion
-jobOffer.promote.confirm.desc = Are you sure you would like to promote the following people:
+jobOffer.promote.confirm.desc = Are you sure you would like to promote the following people to Head TA:
jobOffer.demote = Demote
jobOffer.demote.confirm = Confirm Demote
-jobOffer.demote.confirm.desc = Are you sure you would like to demote the following people:
+jobOffer.demote.confirm.desc = Are you sure you would like to demote the following people to regular TA:
jobOffer.reject.confirm = Confirm Rejection
jobOffer.reject.confirm.desc = Are you sure you would like to reject the following people:
jobOffer.offer = Send Offer
diff --git a/src/main/resources/migrations.yaml b/src/main/resources/migrations.yaml
index 5c5564e0d0a71a1567aaba05fc3ae91763908a6c..3e5a2b1c6702bc88f75035cfddacad1c92e792bb 100644
--- a/src/main/resources/migrations.yaml
+++ b/src/main/resources/migrations.yaml
@@ -928,4 +928,4 @@ databaseChangeLog:
name: teachers_have_access
type: bit
defaultValueBoolean: true
- tableName: tamprogram
+ tableName: tamprogram
\ No newline at end of file
diff --git a/src/main/resources/templates/job_offer/confirm_offer_all_app.html b/src/main/resources/templates/job_offer/confirm_offer_all_app.html
index 24bab1ab8b1cdda346ba4aa6fc81ec34829fe72a..b57348fbbf893d86b096db013d7cf4d6be9e5bf4 100644
--- a/src/main/resources/templates/job_offer/confirm_offer_all_app.html
+++ b/src/main/resources/templates/job_offer/confirm_offer_all_app.html
@@ -29,7 +29,7 @@
data-closable
class="dialog">
<form
- th:action="@{|/application/offer/${offer.id}/|}"
+ th:action="@{|/application/offer/${offer.id}|}"
th:method="post"
class="flex vertical p-7">
<h1 class="underlined font-500" th:text="#{jobOffer.addOffer.confirm}"></h1>
diff --git a/src/main/resources/templates/job_offer/view_one.html b/src/main/resources/templates/job_offer/view_one.html
index 23600e4488a60904bd512a737a22e0844cacb0c4..a6fe771ff6fe5617845c46aae0f4e038709cefaa 100644
--- a/src/main/resources/templates/job_offer/view_one.html
+++ b/src/main/resources/templates/job_offer/view_one.html
@@ -670,7 +670,7 @@
class="table-row"
th:each="app : ${applications}"
th:data-status="${#strings.toLowerCase(app.status.name())}"
- th:with="headTA = ${@roleService.hasHeadTARole(app.personId, offer.editionId)}">
+ th:with="headTA = ${app.isHeadTA}">
<td>
<label class="check-box">
<input