alfio.controller.api.admin.ExtensionApiController.java Source code

Java tutorial

Introduction

Here is the source code for alfio.controller.api.admin.ExtensionApiController.java

Source

/**
 * 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.controller.api.support.PageAndContent;
import alfio.manager.user.UserManager;
import alfio.model.Event;
import alfio.model.ExtensionLog;
import alfio.model.ExtensionSupport;
import alfio.model.ExtensionSupport.*;
import alfio.extension.Extension;
import alfio.extension.ExtensionService;
import alfio.model.user.Organization;
import alfio.model.user.User;
import alfio.repository.EventRepository;
import alfio.repository.user.OrganizationRepository;
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.security.Principal;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@AllArgsConstructor
@RequestMapping("/admin/api/extensions")
@Log4j2
public class ExtensionApiController {

    private static final String SAMPLE_JS;

    static {
        try (InputStream is = new ClassPathResource("/alfio/extension/sample.js").getInputStream()) {
            SAMPLE_JS = StreamUtils.copyToString(is, StandardCharsets.UTF_8);
        } catch (IOException e) {
            throw new IllegalStateException("cannot read sample file", e);
        }
    }

    private final ExtensionService extensionService;
    private final UserManager userManager;
    private final OrganizationRepository organizationRepository;
    private final EventRepository eventRepository;

    @RequestMapping(value = "", method = RequestMethod.GET)
    public List<ExtensionSupport> listAll(Principal principal) {
        ensureAdmin(principal);
        return extensionService.listAll();
    }

    @RequestMapping(value = "/sample", method = RequestMethod.GET)
    public ExtensionSupport getSample() {
        return new ExtensionSupport("-", "", null, true, true, SAMPLE_JS);
    }

    @RequestMapping(value = "", method = RequestMethod.POST)
    public ResponseEntity<SerializablePair<Boolean, String>> create(@RequestBody Extension script,
            Principal principal) {
        return createOrUpdate(null, null, script, principal);
    }

    @RequestMapping(value = "{path}/{name}", method = RequestMethod.POST)
    public ResponseEntity<SerializablePair<Boolean, String>> update(@PathVariable("path") String path,
            @PathVariable("name") String name, @RequestBody Extension script, Principal principal) {
        return createOrUpdate(path, name, script, principal);
    }

    private ResponseEntity<SerializablePair<Boolean, String>> createOrUpdate(String previousPath,
            String previousName, Extension script, Principal principal) {
        try {
            ensureAdmin(principal);
            extensionService.createOrUpdate(previousPath, previousName, script);
            return ResponseEntity.ok(SerializablePair.of(true, null));
        } catch (Throwable t) {
            return ResponseEntity.badRequest().body(SerializablePair.of(false, t.getMessage()));
        }
    }

    @RequestMapping(value = "{path}/{name}", method = RequestMethod.GET)
    public ResponseEntity<ExtensionSupport> loadSingle(@PathVariable("path") String path,
            @PathVariable("name") String name, Principal principal) throws UnsupportedEncodingException {
        ensureAdmin(principal);
        return extensionService.getSingle(URLDecoder.decode(path, "UTF-8"), name).map(ResponseEntity::ok)
                .orElseGet(() -> ResponseEntity.notFound().build());
    }

    @RequestMapping(value = "{path}/{name}", method = RequestMethod.DELETE)
    public void delete(@PathVariable("path") String path, @PathVariable("name") String name, Principal principal) {
        ensureAdmin(principal);
        extensionService.delete(path, name);
    }

    @RequestMapping(value = "/{path}/{name}/toggle/{enable}", method = RequestMethod.POST)
    public void toggle(@PathVariable("path") String path, @PathVariable("name") String name,
            @PathVariable("enable") boolean enable, Principal principal) {
        ensureAdmin(principal);
        extensionService.toggle(path, name, enable);
    }

    //
    @RequestMapping(value = "/setting/system", method = RequestMethod.GET)
    public Map<Integer, List<ExtensionParameterMetadataAndValue>> getParametersFor(Principal principal) {
        ensureAdmin(principal);
        return extensionService.getConfigurationParametersFor("-", "-%", "SYSTEM").stream()
                .collect(Collectors.groupingBy(ExtensionParameterMetadataAndValue::getExtensionId));
    }

    @PostMapping("/setting/system/bulk-update")
    public void bulkUpdateSystem(@RequestBody List<ExtensionMetadataValue> toUpdate, Principal principal) {
        ensureAdmin(principal);
        ensureIdsArePresent(toUpdate, extensionService.getConfigurationParametersFor("-", "-%", "SYSTEM"));
        extensionService.bulkUpdateSystemSettings(toUpdate);
    }

    @DeleteMapping("/setting/system/{id}")
    public void deleteSystemSettingValue(@PathVariable("id") int id, Principal principal) {
        ensureAdmin(principal);
        extensionService.deleteSettingValue(id, "-");
    }

    @RequestMapping(value = "/setting/organization/{orgShortName}", method = RequestMethod.GET)
    public Map<Integer, List<ExtensionParameterMetadataAndValue>> getParametersFor(
            @PathVariable("orgShortName") String orgShortName, Principal principal) {
        Organization org = organizationRepository.findByName(orgShortName).orElseThrow(IllegalStateException::new);
        ensureOrganization(principal, org);
        return extensionService
                .getConfigurationParametersFor("-" + org.getId(), "-" + org.getId() + "-%", "ORGANIZATION").stream()
                .collect(Collectors.groupingBy(ExtensionParameterMetadataAndValue::getExtensionId));
    }

    @PostMapping("/setting/organization/{orgShortName}/bulk-update")
    public void bulkUpdateOrganization(@PathVariable("orgShortName") String orgShortName,
            @RequestBody List<ExtensionMetadataValue> toUpdate, Principal principal) {
        Organization org = organizationRepository.findByName(orgShortName).orElseThrow(IllegalStateException::new);
        ensureOrganization(principal, org);
        ensureIdsArePresent(toUpdate, extensionService.getConfigurationParametersFor("-" + org.getId(),
                "-" + org.getId() + "-%", "ORGANIZATION"));
        extensionService.bulkUpdateOrganizationSettings(org, toUpdate);
    }

    @DeleteMapping("/setting/organization/{orgShortName}/{id}")
    public void deleteOrganizationSettingValue(@PathVariable("orgShortName") String orgShortName,
            @PathVariable("id") int id, Principal principal) {
        Organization org = organizationRepository.findByName(orgShortName).orElseThrow(IllegalStateException::new);
        ensureOrganization(principal, org);
        extensionService.deleteSettingValue(id, "-" + org.getId());
    }

    @RequestMapping(value = "/setting/organization/{orgShortName}/event/{shortName}", method = RequestMethod.GET)
    public Map<Integer, List<ExtensionParameterMetadataAndValue>> getParametersFor(
            @PathVariable("orgShortName") String orgShortName, @PathVariable("shortName") String eventShortName,
            Principal principal) {

        Organization org = organizationRepository.findByName(orgShortName).orElseThrow(IllegalStateException::new);
        ensureOrganization(principal, org);
        Event event = eventRepository.findByShortName(eventShortName);
        ensureEventInOrganization(org, event);
        String pattern = String.format("-%d-%d", org.getId(), event.getId());
        return extensionService.getConfigurationParametersFor(pattern, pattern, "EVENT").stream()
                .collect(Collectors.groupingBy(ExtensionParameterMetadataAndValue::getExtensionId));
    }

    @PostMapping("/setting/organization/{orgShortName}/event/{shortName}/bulk-update")
    public void bulkUpdateEvent(@PathVariable("orgShortName") String orgShortName,
            @PathVariable("shortName") String eventShortName, @RequestBody List<ExtensionMetadataValue> toUpdate,
            Principal principal) {
        Organization org = organizationRepository.findByName(orgShortName).orElseThrow(IllegalStateException::new);
        ensureOrganization(principal, org);
        Event event = eventRepository.findByShortName(eventShortName);
        ensureEventInOrganization(org, event);
        String pattern = String.format("-%d-%d", org.getId(), event.getId());
        ensureIdsArePresent(toUpdate, extensionService.getConfigurationParametersFor(pattern, pattern, "EVENT"));
        extensionService.bulkUpdateEventSettings(org, event, toUpdate);
    }

    @DeleteMapping("/setting/organization/{orgShortName}/event/{shortName}/{id}")
    public void deleteEventSettingValue(@PathVariable("orgShortName") String orgShortName,
            @PathVariable("shortName") String eventShortName, @PathVariable("id") int id, Principal principal) {
        Organization org = organizationRepository.findByName(orgShortName).orElseThrow(IllegalStateException::new);
        ensureOrganization(principal, org);
        Event event = eventRepository.findByShortName(eventShortName);
        ensureEventInOrganization(org, event);
        extensionService.deleteSettingValue(id, String.format("-%d-%d", org.getId(), event.getId()));
    }

    //check that the ids are coherent
    private static void ensureIdsArePresent(List<ExtensionMetadataValue> toUpdate,
            List<ExtensionParameterMetadataAndValue> system) {
        Set<Integer> validIds = system.stream().map(ExtensionParameterMetadataAndValue::getId)
                .collect(Collectors.toSet());
        Set<Integer> toUpdateIds = toUpdate.stream().map(ExtensionMetadataValue::getId).collect(Collectors.toSet());
        if (!validIds.containsAll(toUpdateIds)) {
            throw new IllegalStateException();
        }
    }

    //

    @RequestMapping(value = "/log")
    public PageAndContent<List<ExtensionLog>> getLog(@RequestParam(required = false, name = "path") String path,
            @RequestParam(required = false, name = "name") String name,
            @RequestParam(required = false, name = "type") ExtensionLog.Type type,
            @RequestParam(required = false, name = "page", defaultValue = "0") Integer page, Principal principal) {
        ensureAdmin(principal);
        final int pageSize = 50;
        Pair<List<ExtensionLog>, Integer> res = extensionService.getLog(StringUtils.trimToNull(path),
                StringUtils.trimToNull(name), type, pageSize, (page == null ? 0 : page) * pageSize);
        return new PageAndContent<>(res.getLeft(), res.getRight());
    }

    private void ensureAdmin(Principal principal) {
        Validate.isTrue(userManager.isAdmin(userManager.findUserByUsername(principal.getName())));
    }

    private void ensureOrganization(Principal principal, Organization organization) {
        User user = userManager.findUserByUsername(principal.getName());
        Validate.isTrue(userManager.isOwnerOfOrganization(user, organization.getId()));
    }

    private static void ensureEventInOrganization(Organization organization, Event event) {
        Validate.isTrue(organization.getId() == event.getOrganizationId());
    }
}