Skip to content

Commit

Permalink
Merge whitelist to master (#496)
Browse files Browse the repository at this point in the history
* initial work for merging whitelist in master

*  disable postpone assignment option if one or more categories are linked to groups

* #487 - remove members + remove groups

* #487 - display "linked to group" message on event level only if the group is not linked directly to a category

* #487 - remove unnecessary ticket->email map
  • Loading branch information
cbellone authored Jul 31, 2018
1 parent 1dd755d commit 1742097
Show file tree
Hide file tree
Showing 35 changed files with 1,831 additions and 51 deletions.
14 changes: 4 additions & 10 deletions src/main/java/alfio/controller/ReservationController.java
Original file line number Diff line number Diff line change
Expand Up @@ -119,17 +119,10 @@ public String showBookingPage(@PathVariable("eventName") String eventName,
List<Ticket> ticketsInReservation = ticketReservationManager.findTicketsInReservation(reservationId);

model.addAttribute("postponeAssignment", false)
.addAttribute("showPostpone", !forceAssignment && ticketsInReservation.size() > 1);
.addAttribute("showPostpone", !forceAssignment && ticketsInReservation.size() > 1 && ticketReservationManager.containsCategoriesLinkedToGroups(reservationId, event.getId()));


try {
model.addAttribute("delayForOfflinePayment", Math.max(1, TicketReservationManager.getOfflinePaymentWaitingPeriod(event, configurationManager)));
} catch (TicketReservationManager.OfflinePaymentException e) {
if(event.getAllowedPaymentProxies().contains(PaymentProxy.OFFLINE)) {
log.error("Already started event {} has been found with OFFLINE payment enabled" , event.getDisplayName() , e);
}
model.addAttribute("delayForOfflinePayment", 0);
}
addDelayForOffline(model, event);

OrderSummary orderSummary = ticketReservationManager.orderSummaryForReservationId(reservationId, event, locale);

Expand Down Expand Up @@ -250,7 +243,8 @@ public String validateToOverview(@PathVariable("eventName") String eventName, @P
final TotalPrice reservationCost = ticketReservationManager.totalReservationCostWithVAT(reservationId);
Configuration.ConfigurationPathKey forceAssignmentKey = Configuration.from(event.getOrganizationId(), event.getId(), ConfigurationKeys.FORCE_TICKET_OWNER_ASSIGNMENT_AT_RESERVATION);
boolean forceAssignment = configurationManager.getBooleanConfigValue(forceAssignmentKey, false);
if(forceAssignment) {

if(forceAssignment || ticketReservationManager.containsCategoriesLinkedToGroups(reservationId, event.getId())) {
contactAndTicketsForm.setPostponeAssignment(false);
}

Expand Down
184 changes: 184 additions & 0 deletions src/main/java/alfio/controller/api/admin/GroupApiController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
/**
* This file is part of alf.io.
*
* alf.io is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* alf.io 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with alf.io. If not, see <http://www.gnu.org/licenses/>.
*/
package alfio.controller.api.admin;

import alfio.manager.EventManager;
import alfio.manager.GroupManager;
import alfio.manager.user.UserManager;
import alfio.model.group.Group;
import alfio.model.group.LinkedGroup;
import alfio.model.modification.GroupModification;
import alfio.model.modification.LinkedGroupModification;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.security.Principal;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

import static alfio.util.OptionalWrapper.optionally;

@RestController
@RequestMapping("/admin/api/group")
@RequiredArgsConstructor
public class GroupApiController {

private final GroupManager groupManager;
private final UserManager userManager;
private final EventManager eventManager;

@GetMapping("/for/{organizationId}")
public ResponseEntity<List<Group>> loadAllGroupsForOrganization(@PathVariable("organizationId") int organizationId, Principal principal) {
if(notOwner(principal.getName(), organizationId)) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
}
return ResponseEntity.ok(groupManager.getAllForOrganization(organizationId));
}

@GetMapping("/for/{organizationId}/detail/{listId}")
public ResponseEntity<GroupModification> loadDetail(@PathVariable("organizationId") int organizationId, @PathVariable("listId") int listId, Principal principal) {
if(notOwner(principal.getName(), organizationId)) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
}
return groupManager.loadComplete(listId).map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build());
}

@PostMapping("/for/{organizationId}/update/{groupId}")
public ResponseEntity<GroupModification> updateGroup(@PathVariable("organizationId") int organizationId,
@PathVariable("groupId") int listId,
@RequestBody GroupModification modification,
Principal principal) {
if(notOwner(principal.getName(), organizationId)) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
}
return groupManager.update(listId, modification).map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build());
}

@PostMapping("/for/{organizationId}/new")
public ResponseEntity<Integer> createNew(@PathVariable("organizationId") int organizationId, @RequestBody GroupModification request, Principal principal) {
if(notOwner(principal.getName(), organizationId)) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
}
if(request.getOrganizationId() != organizationId) {
return ResponseEntity.badRequest().build();
}
return ResponseEntity.ok(groupManager.createNew(request));
}

@GetMapping("/for/event/{eventName}/all")
public ResponseEntity<List<LinkedGroup>> findLinked(@PathVariable("eventName") String eventName,
Principal principal) {
return eventManager.getOptionalByName(eventName, principal.getName())
.map(event -> ResponseEntity.ok(groupManager.getLinksForEvent(event.getId())))
.orElseGet(() -> ResponseEntity.notFound().build());
}

@GetMapping("/for/event/{eventName}")
public ResponseEntity<LinkedGroup> findActiveGroup(@PathVariable("eventName") String eventName,
Principal principal) {
return eventManager.getOptionalByName(eventName, principal.getName())
.map(event -> {
Optional<LinkedGroup> configuration = groupManager.getLinksForEvent(event.getId()).stream()
.filter(c -> c.getTicketCategoryId() == null)
.findFirst();
return configuration.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.noContent().build());
})
.orElseGet(() -> ResponseEntity.notFound().build());
}

@GetMapping("/for/event/{eventName}/category/{categoryId}")
public ResponseEntity<LinkedGroup> findActiveGroup(@PathVariable("eventName") String eventName,
@PathVariable("categoryId") int categoryId,
Principal principal) {
return eventManager.getOptionalByName(eventName, principal.getName())
.map(event -> {
Optional<LinkedGroup> configuration = groupManager.findLinks(event.getId(), categoryId)
.stream()
.filter(c -> c.getTicketCategoryId() != null && c.getTicketCategoryId() == categoryId)
.findFirst();
return configuration.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.noContent().build());
})
.orElseGet(() -> ResponseEntity.notFound().build());
}

@PostMapping("/{groupId}/link")
public ResponseEntity<Integer> linkGroup(@PathVariable("groupId") int groupId, @RequestBody LinkedGroupModification body, Principal principal) {
if(body == null || groupId != body.getGroupId()) {
return ResponseEntity.badRequest().build();
}

return optionally(() -> eventManager.getSingleEventById(body.getEventId(), principal.getName()))
.map(event -> {
Optional<LinkedGroup> existing = groupManager.getLinksForEvent(event.getId())
.stream()
.filter(c -> Objects.equals(body.getTicketCategoryId(), c.getTicketCategoryId()))
.findFirst();
LinkedGroup link;
if(existing.isPresent()) {
link = groupManager.updateLink(existing.get().getId(), body);
} else {
link = groupManager.createLink(groupId, event.getId(), body);
}
return ResponseEntity.ok(link.getId());
})
.orElseGet(() -> ResponseEntity.notFound().build());
}

@DeleteMapping("/for/{organizationId}/link/{configurationId}")
public ResponseEntity<String> unlinkGroup(@PathVariable("organizationId") int organizationId, @PathVariable("configurationId") int configurationId, Principal principal) {
if(optionally(() -> userManager.findUserByUsername(principal.getName())).filter(u -> userManager.isOwnerOfOrganization(u, organizationId)).isPresent()) {
groupManager.disableLink(configurationId);
return ResponseEntity.ok("OK");
}
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
}

@DeleteMapping("/for/{organizationId}/id/{groupId}/member/{memberId}")
public ResponseEntity<Boolean> deactivateMember(@PathVariable("groupId") int groupId,
@PathVariable("memberId") int memberId,
@PathVariable("organizationId") int organizationId,
Principal principal) {
if(notOwner(principal.getName(), organizationId) || !groupManager.findById(groupId, organizationId).isPresent()) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
}

return ResponseEntity.ok(groupManager.deactivateMembers(Collections.singletonList(memberId), groupId));

}

@DeleteMapping("/for/{organizationId}/id/{groupId}")
public ResponseEntity<Boolean> deactivateGroup(@PathVariable("groupId") int groupId,
@PathVariable("organizationId") int organizationId,
Principal principal) {
if(notOwner(principal.getName(), organizationId) || !groupManager.findById(groupId, organizationId).isPresent()) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
}

return ResponseEntity.ok(groupManager.deactivateGroup(groupId));
}

private boolean notOwner(String username, int organizationId) {
return !optionally(() -> userManager.findUserByUsername(username))
.filter(user -> userManager.isOwnerOfOrganization(user, organizationId))
.isPresent();
}

}
11 changes: 11 additions & 0 deletions src/main/java/alfio/controller/api/support/TicketHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import alfio.manager.EuVatChecker;
import alfio.manager.EuVatChecker.SameCountryValidator;
import alfio.manager.FileUploadManager;
import alfio.manager.GroupManager;
import alfio.manager.TicketReservationManager;
import alfio.manager.support.PartialTicketTextGenerator;
import alfio.model.*;
Expand All @@ -35,6 +36,7 @@
import alfio.util.LocaleUtil;
import alfio.util.TemplateManager;
import alfio.util.Validator;
import alfio.util.Validator.AdvancedTicketAssignmentValidator;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
Expand Down Expand Up @@ -67,6 +69,7 @@ public class TicketHelper {
private final TicketFieldRepository ticketFieldRepository;
private final AdditionalServiceItemRepository additionalServiceItemRepository;
private final EuVatChecker vatChecker;
private final GroupManager groupManager;


public List<TicketFieldConfigurationDescriptionAndValue> findTicketFieldConfigurationAndValue(Ticket ticket) {
Expand Down Expand Up @@ -110,7 +113,12 @@ private Triple<ValidationResult, Event, Ticket> assignTicket(UpdateTicketOwnerFo

final TicketReservation ticketReservation = result.getMiddle();
List<TicketFieldConfiguration> fieldConf = ticketFieldRepository.findAdditionalFieldsForEvent(event.getId());
AdvancedTicketAssignmentValidator advancedValidator = new AdvancedTicketAssignmentValidator(new SameCountryValidator(vatChecker, event.getOrganizationId(), event.getId(), ticketReservation.getId()),
new GroupManager.WhitelistValidator(event.getId(), groupManager));

Validator.AdvancedValidationContext context = new Validator.AdvancedValidationContext(updateTicketOwner, fieldConf, t.getCategoryId(), t.getUuid(), formPrefix);
ValidationResult validationResult = Validator.validateTicketAssignment(updateTicketOwner, fieldConf, bindingResult, event, formPrefix, new SameCountryValidator(vatChecker, event.getOrganizationId(), event.getId(), ticketReservation.getId()))
.or(Validator.performAdvancedValidation(advancedValidator, context, bindingResult.orElse(null)))
.ifSuccess(() -> updateTicketOwner(updateTicketOwner, request, t, event, ticketReservation, userDetails));
return Triple.of(validationResult, event, ticketRepository.findByUUID(t.getUuid()));
}
Expand Down Expand Up @@ -213,6 +221,9 @@ private void updateTicketOwner(UpdateTicketOwnerForm updateTicketOwner, HttpServ
getConfirmationTextBuilder(request, event, ticketReservation, t, category),
getOwnerChangeTextBuilder(request, t, event),
userDetails);
if(t.hasBeenSold() && !groupManager.findLinks(event.getId(), t.getCategoryId()).isEmpty()) {
ticketRepository.forbidReassignment(Collections.singletonList(t.getId()));
}
}

private PartialTicketTextGenerator getOwnerChangeTextBuilder(HttpServletRequest request, Ticket t, Event event) {
Expand Down
12 changes: 8 additions & 4 deletions src/main/java/alfio/controller/form/ContactAndTicketsForm.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@
package alfio.controller.form;

import alfio.manager.EuVatChecker;
import alfio.model.*;
import alfio.model.Event;
import alfio.model.TicketFieldConfiguration;
import alfio.model.TicketReservation;
import alfio.model.TicketReservationAdditionalInfo;
import alfio.model.result.ValidationResult;
import alfio.util.ErrorsCode;
import alfio.util.Validator;
Expand All @@ -27,7 +30,10 @@
import org.springframework.validation.ValidationUtils;

import java.io.Serializable;
import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import static alfio.util.ErrorsCode.STEP_2_INVALID_VAT;
Expand Down Expand Up @@ -121,8 +127,6 @@ public void validate(BindingResult bindingResult, Event event, List<TicketFieldC
ValidationUtils.rejectIfEmptyOrWhitespace(bindingResult, "vatNr", "error.emptyField");
}

//TODO: here add vat nr validation!
//
}

if (email != null && !email.contains("@") && !bindingResult.hasFieldErrors("email")) {
Expand Down
Loading

0 comments on commit 1742097

Please sign in to comment.