ShareController.java

package com.oliwier.listmebackend.api;

import com.oliwier.listmebackend.api.dto.ListResponse;
import com.oliwier.listmebackend.api.dto.ShareTokenResponse;
import com.oliwier.listmebackend.domain.model.Device;
import com.oliwier.listmebackend.domain.model.ShoppingList;
import com.oliwier.listmebackend.domain.repository.ListDeviceRepository;
import com.oliwier.listmebackend.domain.repository.ShoppingListRepository;
import com.oliwier.listmebackend.domain.service.ShareService;
import com.oliwier.listmebackend.identity.CurrentDevice;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;

import java.util.UUID;

@RestController
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class ShareController {

    private final ShareService shareService;
    private final ShoppingListRepository listRepository;
    private final ListDeviceRepository listDeviceRepository;

    @PostMapping("/api/lists/{listId}/share")
    @Transactional
    public ShareTokenResponse share(@CurrentDevice Device device, @PathVariable UUID listId) {
        ShoppingList list = getListForDevice(listId, device);
        String token = shareService.generateShareToken(list);
        return new ShareTokenResponse(token, list.getId(), list.getName());
    }

    @DeleteMapping("/api/lists/{listId}/share")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    @Transactional
    public void revokeShare(@CurrentDevice Device device, @PathVariable UUID listId) {
        ShoppingList list = getListForDevice(listId, device);
        shareService.revokeShareToken(list);
    }

    @GetMapping("/api/share/{token}")
    public ListResponse preview(@PathVariable String token) {
        ShoppingList list = shareService.findByShareToken(token);
        return ListResponse.from(list);
    }

    @PostMapping("/api/share/{token}/join")
    @Transactional
    public ListResponse join(@CurrentDevice Device device, @PathVariable String token) {
        ShoppingList list = shareService.joinViaShareToken(token, device);
        return ListResponse.from(list);
    }

    private ShoppingList getListForDevice(UUID listId, Device device) {
        ShoppingList list = listRepository.findById(listId)
                .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "List not found"));
        if (!listDeviceRepository.existsByListIdAndDeviceId(listId, device.getId())) {
            throw new ResponseStatusException(HttpStatus.FORBIDDEN, "You don't have access to this list");
        }
        return list;
    }
}