CollabMemberController.java

package com.yumu.noveltranslator.adapter.in.rest.collab;

import com.yumu.noveltranslator.port.dto.collab.InviteMemberRequest;
import com.yumu.noveltranslator.port.dto.collab.ProjectMemberResponse;
import com.yumu.noveltranslator.port.dto.common.Result;
import com.yumu.noveltranslator.port.dto.common.PageResponse;
import com.yumu.noveltranslator.enums.ProjectMemberRole;
import com.yumu.noveltranslator.adapter.in.security.annotation.RequireProjectAccess;
import com.yumu.noveltranslator.port.in.CollabPort;
import com.yumu.noveltranslator.util.SecurityUtil;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * 协作成员管理 Controller
 */
@RestController
@RequestMapping("/v1/collab")
@RequiredArgsConstructor
@Slf4j
public class CollabMemberController {

    private final CollabPort collabPort;

    @PostMapping("/projects/{projectId}/invite")
    @RequireProjectAccess(roles = {ProjectMemberRole.OWNER})
    public Result<ProjectMemberResponse> inviteMember(@PathVariable Long projectId,
                                                       @Valid @RequestBody InviteMemberRequest request) {
        Long inviterId = SecurityUtil.getRequiredUserId();
        ProjectMemberResponse member = collabPort.inviteMember(projectId, request, inviterId);
        return Result.ok(member);
    }

    @PostMapping("/join")
    public Result<ProjectMemberResponse> joinByCode(@RequestParam String inviteCode) {
        Long userId = SecurityUtil.getRequiredUserId();
        ProjectMemberResponse member = collabPort.joinByInviteCode(inviteCode, userId);
        return Result.ok(member);
    }

    @GetMapping("/projects/{projectId}/members")
    @RequireProjectAccess
    public Result<PageResponse<ProjectMemberResponse>> listMembers(
            @PathVariable Long projectId,
            @RequestParam(required = false, defaultValue = "1") Integer page,
            @RequestParam(required = false, defaultValue = "20") Integer pageSize) {
        PageResponse<ProjectMemberResponse> members = collabPort.getMembers(projectId, page, pageSize);
        return Result.ok(members);
    }

    @DeleteMapping("/projects/{projectId}/members/{memberId}")
    @RequireProjectAccess(roles = {ProjectMemberRole.OWNER})
    public Result<Void> removeMember(@PathVariable Long projectId, @PathVariable Long memberId) {
        Long operatorId = SecurityUtil.getRequiredUserId();
        collabPort.removeMember(projectId, memberId, operatorId);
        return Result.ok(null);
    }
}