- LogService.reopenIssue() 将状态设回 open
- LogController 暴露 /issues/{id}/reopen 端点
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
221 行
10 KiB
Java
221 行
10 KiB
Java
package com.xuqm.bugcollect.controller;
|
|
|
|
import com.xuqm.common.model.ApiResponse;
|
|
import com.xuqm.common.model.PageResult;
|
|
import com.xuqm.bugcollect.dto.*;
|
|
import com.xuqm.bugcollect.service.LogService;
|
|
import com.xuqm.bugcollect.service.SourcemapService;
|
|
import com.xuqm.bugcollect.service.WebhookService;
|
|
import jakarta.validation.Valid;
|
|
import org.springframework.data.domain.Page;
|
|
import org.springframework.web.bind.annotation.*;
|
|
import org.springframework.web.multipart.MultipartFile;
|
|
|
|
import java.io.IOException;
|
|
import java.util.List;
|
|
|
|
@RestController
|
|
@RequestMapping("/bugcollect/v1")
|
|
public class LogController {
|
|
|
|
private final LogService logService;
|
|
private final SourcemapService sourcemapService;
|
|
private final WebhookService webhookService;
|
|
|
|
public LogController(LogService logService, SourcemapService sourcemapService, WebhookService webhookService) {
|
|
this.logService = logService;
|
|
this.sourcemapService = sourcemapService;
|
|
this.webhookService = webhookService;
|
|
}
|
|
|
|
// ── Ingestion ──────────────────────────────────────────────────────────────
|
|
|
|
@PostMapping("/issues/batch")
|
|
public ApiResponse<Void> ingestIssues(@Valid @RequestBody IssueBatchRequest request) {
|
|
logService.processIssueBatch(request);
|
|
return ApiResponse.ok();
|
|
}
|
|
|
|
@PostMapping("/events/batch")
|
|
public ApiResponse<Void> ingestEvents(@Valid @RequestBody EventBatchRequest request) {
|
|
logService.processEventBatch(request);
|
|
return ApiResponse.ok();
|
|
}
|
|
|
|
// ── Issues ─────────────────────────────────────────────────────────────────
|
|
|
|
@GetMapping("/issues")
|
|
public ApiResponse<PageResult<IssueResponse>> queryIssues(
|
|
@RequestParam String appKey,
|
|
@RequestParam(required = false) String level,
|
|
@RequestParam(required = false) String platform,
|
|
@RequestParam(required = false) String status,
|
|
@RequestParam(required = false) String q,
|
|
@RequestParam(required = false) String assignee,
|
|
@RequestParam(required = false) String environment,
|
|
@RequestParam(required = false) String from,
|
|
@RequestParam(required = false) String to,
|
|
@RequestParam(defaultValue = "1") int page,
|
|
@RequestParam(defaultValue = "20") int size) {
|
|
Page<IssueResponse> result = logService.queryIssues(
|
|
appKey, level, platform, status, q, assignee, environment, from, to, page - 1, size);
|
|
return ApiResponse.success(PageResult.of(result.getContent(), result.getTotalElements(), page, size));
|
|
}
|
|
|
|
@GetMapping("/issues/{id}")
|
|
public ApiResponse<IssueResponse> getIssueDetail(@PathVariable Long id) {
|
|
return ApiResponse.success(logService.getIssueDetail(id));
|
|
}
|
|
|
|
@GetMapping("/issues/{id}/events")
|
|
public ApiResponse<PageResult<IssueEventResponse>> getIssueEvents(
|
|
@PathVariable Long id,
|
|
@RequestParam(required = false) String from,
|
|
@RequestParam(required = false) String to,
|
|
@RequestParam(defaultValue = "1") int page,
|
|
@RequestParam(defaultValue = "20") int size) {
|
|
Page<IssueEventResponse> result = logService.getIssueEvents(id, from, to, page - 1, size);
|
|
return ApiResponse.success(PageResult.of(result.getContent(), result.getTotalElements(), page, size));
|
|
}
|
|
|
|
@GetMapping("/issues/{id}/trend")
|
|
public ApiResponse<IssueTrendResponse> getIssueTrend(
|
|
@PathVariable Long id,
|
|
@RequestParam(required = false) String from,
|
|
@RequestParam(required = false) String to) {
|
|
return ApiResponse.success(logService.getIssueTrend(id, from, to));
|
|
}
|
|
|
|
@DeleteMapping("/issues/{id}")
|
|
public ApiResponse<Void> deleteIssue(@PathVariable Long id) {
|
|
logService.deleteIssueAndEvents(id);
|
|
return ApiResponse.ok();
|
|
}
|
|
|
|
// ── Issue management ───────────────────────────────────────────────────────
|
|
|
|
@PutMapping("/issues/{id}/resolve")
|
|
public ApiResponse<Void> resolveIssue(@PathVariable Long id) {
|
|
logService.resolveIssue(id);
|
|
return ApiResponse.ok();
|
|
}
|
|
|
|
@PutMapping("/issues/{id}/ignore")
|
|
public ApiResponse<Void> ignoreIssue(@PathVariable Long id) {
|
|
logService.ignoreIssue(id);
|
|
return ApiResponse.ok();
|
|
}
|
|
|
|
@PutMapping("/issues/{id}/reopen")
|
|
public ApiResponse<Void> reopenIssue(@PathVariable Long id) {
|
|
logService.reopenIssue(id);
|
|
return ApiResponse.ok();
|
|
}
|
|
|
|
@PutMapping("/issues/{id}/assign")
|
|
public ApiResponse<Void> assignIssue(
|
|
@PathVariable Long id,
|
|
@RequestBody java.util.Map<String, String> body) {
|
|
logService.assignIssue(id, body.get("assignee"));
|
|
return ApiResponse.ok();
|
|
}
|
|
|
|
@PostMapping("/issues/bulk")
|
|
public ApiResponse<Void> bulkUpdateIssues(
|
|
@RequestParam String appKey,
|
|
@Valid @RequestBody IssueActionRequest request) {
|
|
logService.bulkUpdateIssues(appKey, request.ids(), request.action());
|
|
return ApiResponse.ok();
|
|
}
|
|
|
|
// ── Rankings ───────────────────────────────────────────────────────────────
|
|
|
|
@GetMapping("/issues/rankings/frequency")
|
|
public ApiResponse<List<IssueResponse>> getFrequencyRankings(
|
|
@RequestParam String appKey,
|
|
@RequestParam(required = false) String from,
|
|
@RequestParam(required = false) String to,
|
|
@RequestParam(defaultValue = "20") int limit) {
|
|
return ApiResponse.success(logService.getFrequencyRankings(appKey, from, to, limit));
|
|
}
|
|
|
|
@GetMapping("/issues/rankings/risk")
|
|
public ApiResponse<List<IssueResponse>> getRiskRankings(
|
|
@RequestParam String appKey,
|
|
@RequestParam(required = false) String from,
|
|
@RequestParam(required = false) String to,
|
|
@RequestParam(defaultValue = "20") int limit) {
|
|
return ApiResponse.success(logService.getRiskRankings(appKey, from, to, limit));
|
|
}
|
|
|
|
// ── Analytics events ───────────────────────────────────────────────────────
|
|
|
|
@GetMapping("/events")
|
|
public ApiResponse<PageResult<IssueEventResponse>> queryEvents(
|
|
@RequestParam String appKey,
|
|
@RequestParam(required = false) String name,
|
|
@RequestParam(required = false) String userId,
|
|
@RequestParam(required = false) String from,
|
|
@RequestParam(required = false) String to,
|
|
@RequestParam(defaultValue = "1") int page,
|
|
@RequestParam(defaultValue = "20") int size) {
|
|
Page<IssueEventResponse> result = logService.queryEvents(appKey, name, userId, from, to, page - 1, size);
|
|
return ApiResponse.success(PageResult.of(result.getContent(), result.getTotalElements(), page, size));
|
|
}
|
|
|
|
@GetMapping("/events/funnel")
|
|
public ApiResponse<FunnelResponse> queryFunnel(
|
|
@RequestParam String appKey,
|
|
@RequestParam String steps,
|
|
@RequestParam(required = false) String from,
|
|
@RequestParam(required = false) String to) {
|
|
return ApiResponse.success(logService.queryFunnel(appKey, List.of(steps.split(",")), from, to));
|
|
}
|
|
|
|
// ── Overview ───────────────────────────────────────────────────────────────
|
|
|
|
@GetMapping("/overview")
|
|
public ApiResponse<OverviewResponse> getOverview(
|
|
@RequestParam String appKey,
|
|
@RequestParam(required = false) String from,
|
|
@RequestParam(required = false) String to) {
|
|
return ApiResponse.success(logService.getOverview(appKey, from, to));
|
|
}
|
|
|
|
// ── Sourcemaps ─────────────────────────────────────────────────────────────
|
|
|
|
@PostMapping("/sourcemaps/upload")
|
|
public ApiResponse<SourcemapUploadResponse> uploadSourcemap(
|
|
@RequestParam String appKey,
|
|
@RequestParam String platform,
|
|
@RequestParam String appVersion,
|
|
@RequestParam(required = false) String bundleVersion,
|
|
@RequestParam(required = false, defaultValue = "index") String bundleName,
|
|
@RequestParam("file") MultipartFile file) throws IOException {
|
|
return ApiResponse.success(sourcemapService.upload(appKey, platform, appVersion, bundleVersion, bundleName, file));
|
|
}
|
|
|
|
// ── Webhooks ───────────────────────────────────────────────────────────────
|
|
|
|
@GetMapping("/webhooks")
|
|
public ApiResponse<List<WebhookResponse>> listWebhooks(@RequestParam String appKey) {
|
|
return ApiResponse.success(webhookService.listWebhooks(appKey));
|
|
}
|
|
|
|
@PostMapping("/webhooks")
|
|
public ApiResponse<WebhookResponse> createWebhook(@Valid @RequestBody WebhookRequest request) {
|
|
return ApiResponse.success(webhookService.createWebhook(request));
|
|
}
|
|
|
|
@PutMapping("/webhooks/{id}")
|
|
public ApiResponse<WebhookResponse> updateWebhook(@PathVariable Long id, @Valid @RequestBody WebhookRequest request) {
|
|
return ApiResponse.success(webhookService.updateWebhook(id, request));
|
|
}
|
|
|
|
@DeleteMapping("/webhooks/{id}")
|
|
public ApiResponse<Void> deleteWebhook(@PathVariable Long id) {
|
|
webhookService.deleteWebhook(id);
|
|
return ApiResponse.ok();
|
|
}
|
|
}
|