or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

analytics.mdcloud-development.mdconfiguration.mdcore-services.mddevelopment-tools.mdecommerce.mdindex.mdlive-streaming.mdlogistics.mdmedia-content.mdmessaging.mdqr-codes.mduser-management.md

media-content.mddocs/

0

# Media & Content

1

2

Media file management, content security, and content moderation services for images, videos, audio files, and other media types in WeChat MiniApp applications.

3

4

## Capabilities

5

6

### Media Service Interface

7

8

Core media operations for uploading, managing, and processing media files.

9

10

```java { .api }

11

public interface WxMaMediaService {

12

// Media Upload

13

WxMediaUploadResult uploadMedia(String type, File media) throws WxErrorException;

14

WxMediaUploadResult uploadMedia(String type, InputStream inputStream, String fileName) throws WxErrorException;

15

16

// Media Download

17

File downloadMedia(String mediaId, File file) throws WxErrorException;

18

InputStream downloadMedia(String mediaId) throws WxErrorException;

19

20

// Temporary Media (3 days retention)

21

WxMediaUploadResult uploadTempMedia(String type, File media) throws WxErrorException;

22

WxMediaUploadResult uploadTempMedia(String type, InputStream inputStream, String fileName) throws WxErrorException;

23

24

// Image Upload (permanent)

25

WxMediaUploadResult uploadImg(File media) throws WxErrorException;

26

WxMediaUploadResult uploadImg(InputStream inputStream, String fileName) throws WxErrorException;

27

}

28

```

29

30

### Security Service Interface

31

32

Content security and moderation operations for text, images, and other media content.

33

34

```java { .api }

35

public interface WxMaSecurityService {

36

// Text Security Check

37

boolean checkText(String content) throws WxErrorException;

38

boolean checkText(String content, Integer scene, Integer version) throws WxErrorException;

39

40

// Image Security Check

41

boolean checkImage(File imageFile) throws WxErrorException;

42

boolean checkImage(String mediaId) throws WxErrorException;

43

boolean checkImage(InputStream inputStream, String fileName) throws WxErrorException;

44

45

// Audio Security Check

46

boolean checkAudio(File audioFile) throws WxErrorException;

47

boolean checkAudio(String mediaId) throws WxErrorException;

48

49

// User Risk Assessment

50

WxMaUserRiskRank getUserRiskRank(String openid, Integer scene) throws WxErrorException;

51

}

52

```

53

54

### Media Upload Models

55

56

Data models for media upload operations and responses.

57

58

```java { .api }

59

public class WxMediaUploadResult implements Serializable {

60

private String type; // Media type (image, voice, video, thumb)

61

private String mediaId; // Media ID for subsequent operations

62

private Long createdAt; // Upload timestamp

63

private String url; // Media URL (for permanent images)

64

65

// Getters and setters

66

public String getType();

67

public void setType(String type);

68

public String getMediaId();

69

public void setMediaId(String mediaId);

70

public Long getCreatedAt();

71

public void setCreatedAt(Long createdAt);

72

public String getUrl();

73

public void setUrl(String url);

74

75

// Utility methods

76

public Date getCreatedAtAsDate();

77

public static WxMediaUploadResult fromJson(String json);

78

public String toJson();

79

}

80

```

81

82

### Security Check Models

83

84

Data models for content security and user risk assessment.

85

86

```java { .api }

87

public class WxMaSecurityCheckResult implements Serializable {

88

private Integer errCode; // Error code (0: pass, 87014: risky content)

89

private String errMsg; // Error message

90

private String traceId; // Trace ID for tracking

91

private SecurityResult result; // Detailed security check result

92

93

public static class SecurityResult {

94

private String suggest; // Suggestion (pass, review, risky)

95

private String label; // Risk label (if any)

96

97

public String getSuggest();

98

public void setSuggest(String suggest);

99

public String getLabel();

100

public void setLabel(String label);

101

}

102

103

// Getters and setters

104

public Integer getErrCode();

105

public void setErrCode(Integer errCode);

106

public String getErrMsg();

107

public void setErrMsg(String errMsg);

108

public String getTraceId();

109

public void setTraceId(String traceId);

110

public SecurityResult getResult();

111

public void setResult(SecurityResult result);

112

113

// Convenience methods

114

public boolean isPassed();

115

public boolean isRisky();

116

public boolean needsReview();

117

}

118

119

public class WxMaUserRiskRank implements Serializable {

120

private Integer riskRank; // Risk rank (0: normal, 1-4: increasing risk levels)

121

private String openid; // User OpenID

122

private Long timestamp; // Assessment timestamp

123

124

// Getters and setters

125

public Integer getRiskRank();

126

public void setRiskRank(Integer riskRank);

127

public String getOpenid();

128

public void setOpenid(String openid);

129

public Long getTimestamp();

130

public void setTimestamp(Long timestamp);

131

132

// Convenience methods

133

public boolean isHighRisk();

134

public boolean isNormalRisk();

135

public String getRiskLevel();

136

}

137

```

138

139

### Media Type Constants

140

141

Constants for different media types and security check parameters.

142

143

```java { .api }

144

public class WxMaMediaConstants {

145

// Media Types

146

public static final String IMAGE = "image";

147

public static final String VOICE = "voice";

148

public static final String VIDEO = "video";

149

public static final String THUMB = "thumb";

150

151

// Security Check Scenes

152

public static final Integer SCENE_SOCIAL = 1; // Social scenarios

153

public static final Integer SCENE_COMMENT = 2; // Comment scenarios

154

public static final Integer SCENE_FORUM = 3; // Forum scenarios

155

public static final Integer SCENE_OPEN_API = 4; // Open API scenarios

156

157

// Security Check Versions

158

public static final Integer VERSION_LATEST = 2; // Latest version

159

160

// Risk Levels

161

public static final Integer RISK_NORMAL = 0; // Normal user

162

public static final Integer RISK_LOW = 1; // Low risk

163

public static final Integer RISK_MEDIUM = 2; // Medium risk

164

public static final Integer RISK_HIGH = 3; // High risk

165

public static final Integer RISK_VERY_HIGH = 4; // Very high risk

166

}

167

```

168

169

## Usage Examples

170

171

### Media Upload and Management

172

173

#### Upload Images

174

175

```java

176

@Service

177

public class MediaUploadService {

178

179

@Autowired

180

private WxMaService wxMaService;

181

182

public String uploadUserAvatar(File avatarFile) {

183

try {

184

// Upload as permanent image (no expiration)

185

WxMediaUploadResult result = wxMaService.getMediaService()

186

.uploadImg(avatarFile);

187

188

String mediaUrl = result.getUrl();

189

logger.info("Avatar uploaded successfully: {}", mediaUrl);

190

191

return mediaUrl;

192

193

} catch (WxErrorException e) {

194

logger.error("Avatar upload failed: {}", e.getMessage());

195

throw new MediaUploadException("Failed to upload avatar", e);

196

}

197

}

198

199

public String uploadTemporaryImage(MultipartFile file) {

200

try {

201

// Upload as temporary media (3 days retention)

202

WxMediaUploadResult result = wxMaService.getMediaService()

203

.uploadTempMedia(WxMaMediaConstants.IMAGE,

204

file.getInputStream(),

205

file.getOriginalFilename());

206

207

String mediaId = result.getMediaId();

208

logger.info("Temporary image uploaded: {}", mediaId);

209

210

return mediaId;

211

212

} catch (WxErrorException | IOException e) {

213

logger.error("Temporary image upload failed: {}", e.getMessage());

214

throw new MediaUploadException("Failed to upload temporary image", e);

215

}

216

}

217

218

public String uploadProductImage(File productImage) {

219

try {

220

// First check image content for security

221

boolean isSecure = wxMaService.getSecurityService()

222

.checkImage(productImage);

223

224

if (!isSecure) {

225

throw new SecurityCheckException("Image contains inappropriate content");

226

}

227

228

// Upload if security check passes

229

WxMediaUploadResult result = wxMaService.getMediaService()

230

.uploadImg(productImage);

231

232

return result.getUrl();

233

234

} catch (WxErrorException e) {

235

logger.error("Product image upload failed: {}", e.getMessage());

236

throw new MediaUploadException("Failed to upload product image", e);

237

}

238

}

239

}

240

```

241

242

#### Upload Audio and Video

243

244

```java

245

public class MultiMediaService {

246

247

public String uploadVoiceMessage(File voiceFile) {

248

try {

249

// Check audio content first

250

boolean isSecure = wxMaService.getSecurityService()

251

.checkAudio(voiceFile);

252

253

if (!isSecure) {

254

throw new SecurityCheckException("Audio contains inappropriate content");

255

}

256

257

// Upload voice as temporary media

258

WxMediaUploadResult result = wxMaService.getMediaService()

259

.uploadTempMedia(WxMaMediaConstants.VOICE, voiceFile);

260

261

String mediaId = result.getMediaId();

262

logger.info("Voice message uploaded: {}", mediaId);

263

264

return mediaId;

265

266

} catch (WxErrorException e) {

267

logger.error("Voice upload failed: {}", e.getMessage());

268

throw new MediaUploadException("Failed to upload voice message", e);

269

}

270

}

271

272

public String uploadVideo(File videoFile) {

273

try {

274

// Upload video as temporary media

275

WxMediaUploadResult result = wxMaService.getMediaService()

276

.uploadTempMedia(WxMaMediaConstants.VIDEO, videoFile);

277

278

String mediaId = result.getMediaId();

279

logger.info("Video uploaded: {}", mediaId);

280

281

return mediaId;

282

283

} catch (WxErrorException e) {

284

logger.error("Video upload failed: {}", e.getMessage());

285

throw new MediaUploadException("Failed to upload video", e);

286

}

287

}

288

289

public String uploadThumbnail(File thumbnailFile) {

290

try {

291

// Upload thumbnail for video

292

WxMediaUploadResult result = wxMaService.getMediaService()

293

.uploadTempMedia(WxMaMediaConstants.THUMB, thumbnailFile);

294

295

return result.getMediaId();

296

297

} catch (WxErrorException e) {

298

logger.error("Thumbnail upload failed: {}", e.getMessage());

299

throw new MediaUploadException("Failed to upload thumbnail", e);

300

}

301

}

302

}

303

```

304

305

#### Media Download and Processing

306

307

```java

308

public class MediaDownloadService {

309

310

public File downloadMedia(String mediaId, String targetDirectory) {

311

try {

312

// Create target file

313

File targetFile = new File(targetDirectory, "media_" + mediaId + ".dat");

314

315

// Download media

316

File downloadedFile = wxMaService.getMediaService()

317

.downloadMedia(mediaId, targetFile);

318

319

logger.info("Media downloaded: {} -> {}", mediaId, downloadedFile.getPath());

320

return downloadedFile;

321

322

} catch (WxErrorException e) {

323

logger.error("Media download failed for {}: {}", mediaId, e.getMessage());

324

throw new MediaDownloadException("Failed to download media", e);

325

}

326

}

327

328

public byte[] downloadMediaAsBytes(String mediaId) {

329

try (InputStream inputStream = wxMaService.getMediaService().downloadMedia(mediaId)) {

330

return IOUtils.toByteArray(inputStream);

331

332

} catch (WxErrorException | IOException e) {

333

logger.error("Media download as bytes failed for {}: {}", mediaId, e.getMessage());

334

throw new MediaDownloadException("Failed to download media as bytes", e);

335

}

336

}

337

338

@Async

339

public CompletableFuture<String> processAndUpload(File originalFile, ImageProcessingOptions options) {

340

return CompletableFuture.supplyAsync(() -> {

341

try {

342

// Process image (resize, crop, etc.)

343

File processedFile = imageProcessor.process(originalFile, options);

344

345

// Upload processed image

346

WxMediaUploadResult result = wxMaService.getMediaService()

347

.uploadImg(processedFile);

348

349

// Clean up temporary file

350

processedFile.delete();

351

352

return result.getUrl();

353

354

} catch (Exception e) {

355

logger.error("Async media processing failed: {}", e.getMessage());

356

return null;

357

}

358

});

359

}

360

}

361

```

362

363

### Content Security and Moderation

364

365

#### Text Content Security Check

366

367

```java

368

@Service

369

public class ContentModerationService {

370

371

public boolean checkTextContent(String content, ContentScene scene) {

372

try {

373

Integer sceneCode = getSceneCode(scene);

374

375

boolean isSecure = wxMaService.getSecurityService()

376

.checkText(content, sceneCode, WxMaMediaConstants.VERSION_LATEST);

377

378

if (!isSecure) {

379

logger.warn("Text content failed security check: {}",

380

content.substring(0, Math.min(50, content.length())));

381

}

382

383

return isSecure;

384

385

} catch (WxErrorException e) {

386

logger.error("Text security check failed: {}", e.getMessage());

387

// Default to rejecting on error for safety

388

return false;

389

}

390

}

391

392

public ContentModerationResult moderateUserComment(String comment, String openid) {

393

try {

394

// Check text content

395

boolean textSecure = wxMaService.getSecurityService()

396

.checkText(comment, WxMaMediaConstants.SCENE_COMMENT,

397

WxMaMediaConstants.VERSION_LATEST);

398

399

// Check user risk level

400

WxMaUserRiskRank userRisk = wxMaService.getSecurityService()

401

.getUserRiskRank(openid, WxMaMediaConstants.SCENE_COMMENT);

402

403

ContentModerationResult result = new ContentModerationResult();

404

result.setTextSecure(textSecure);

405

result.setUserRiskLevel(userRisk.getRiskRank());

406

result.setApproved(textSecure && !userRisk.isHighRisk());

407

408

if (result.isApproved()) {

409

result.setAction("approve");

410

} else if (!textSecure) {

411

result.setAction("reject_content");

412

} else if (userRisk.isHighRisk()) {

413

result.setAction("manual_review");

414

}

415

416

return result;

417

418

} catch (WxErrorException e) {

419

logger.error("Comment moderation failed: {}", e.getMessage());

420

// Default to manual review on error

421

ContentModerationResult result = new ContentModerationResult();

422

result.setAction("manual_review");

423

result.setApproved(false);

424

return result;

425

}

426

}

427

428

private Integer getSceneCode(ContentScene scene) {

429

switch (scene) {

430

case SOCIAL: return WxMaMediaConstants.SCENE_SOCIAL;

431

case COMMENT: return WxMaMediaConstants.SCENE_COMMENT;

432

case FORUM: return WxMaMediaConstants.SCENE_FORUM;

433

case OPEN_API: return WxMaMediaConstants.SCENE_OPEN_API;

434

default: return WxMaMediaConstants.SCENE_SOCIAL;

435

}

436

}

437

}

438

```

439

440

#### Image Content Security Check

441

442

```java

443

public class ImageModerationService {

444

445

public boolean checkUploadedImage(MultipartFile imageFile) {

446

try {

447

// Check image content

448

boolean isSecure = wxMaService.getSecurityService()

449

.checkImage(imageFile.getInputStream(), imageFile.getOriginalFilename());

450

451

if (!isSecure) {

452

logger.warn("Uploaded image failed security check: {}",

453

imageFile.getOriginalFilename());

454

}

455

456

return isSecure;

457

458

} catch (WxErrorException | IOException e) {

459

logger.error("Image security check failed: {}", e.getMessage());

460

return false;

461

}

462

}

463

464

public ImageModerationResult moderateUserAvatar(File avatarFile, String openid) {

465

try {

466

// Check image content

467

boolean imageSecure = wxMaService.getSecurityService()

468

.checkImage(avatarFile);

469

470

// Check user risk level

471

WxMaUserRiskRank userRisk = wxMaService.getSecurityService()

472

.getUserRiskRank(openid, WxMaMediaConstants.SCENE_SOCIAL);

473

474

ImageModerationResult result = new ImageModerationResult();

475

result.setImageSecure(imageSecure);

476

result.setUserRiskLevel(userRisk.getRiskRank());

477

478

// Decision logic

479

if (imageSecure && userRisk.getRiskRank() <= WxMaMediaConstants.RISK_LOW) {

480

result.setApproved(true);

481

result.setAction("approve");

482

} else if (!imageSecure) {

483

result.setApproved(false);

484

result.setAction("reject_inappropriate");

485

} else {

486

result.setApproved(false);

487

result.setAction("manual_review");

488

}

489

490

return result;

491

492

} catch (WxErrorException e) {

493

logger.error("Avatar moderation failed: {}", e.getMessage());

494

ImageModerationResult result = new ImageModerationResult();

495

result.setApproved(false);

496

result.setAction("error_occurred");

497

return result;

498

}

499

}

500

501

@Async

502

public void batchCheckImages(List<String> mediaIds) {

503

for (String mediaId : mediaIds) {

504

try {

505

boolean isSecure = wxMaService.getSecurityService()

506

.checkImage(mediaId);

507

508

// Update database with security status

509

mediaSecurityRepository.updateSecurityStatus(mediaId, isSecure);

510

511

if (!isSecure) {

512

// Handle inappropriate content

513

handleInappropriateMedia(mediaId);

514

}

515

516

// Rate limiting - small delay between checks

517

Thread.sleep(100);

518

519

} catch (WxErrorException | InterruptedException e) {

520

logger.error("Batch image check failed for {}: {}", mediaId, e.getMessage());

521

}

522

}

523

}

524

}

525

```

526

527

### User Risk Assessment

528

529

```java

530

@Service

531

public class UserRiskAssessmentService {

532

533

public UserRiskProfile assessUserRisk(String openid, RiskAssessmentContext context) {

534

try {

535

Integer scene = getSceneFromContext(context);

536

537

WxMaUserRiskRank riskResult = wxMaService.getSecurityService()

538

.getUserRiskRank(openid, scene);

539

540

UserRiskProfile profile = new UserRiskProfile();

541

profile.setOpenid(openid);

542

profile.setRiskRank(riskResult.getRiskRank());

543

profile.setRiskLevel(getRiskLevelDescription(riskResult.getRiskRank()));

544

profile.setAssessmentTime(new Date(riskResult.getTimestamp() * 1000));

545

profile.setRecommendations(generateRecommendations(riskResult.getRiskRank()));

546

547

// Store assessment for future reference

548

userRiskRepository.save(profile);

549

550

return profile;

551

552

} catch (WxErrorException e) {

553

logger.error("User risk assessment failed for {}: {}", openid, e.getMessage());

554

555

// Return default safe assessment on error

556

UserRiskProfile profile = new UserRiskProfile();

557

profile.setOpenid(openid);

558

profile.setRiskRank(WxMaMediaConstants.RISK_MEDIUM);

559

profile.setRiskLevel("Unknown (Assessment Failed)");

560

profile.setAssessmentTime(new Date());

561

return profile;

562

}

563

}

564

565

public boolean shouldAllowOperation(String openid, UserOperation operation) {

566

try {

567

Integer scene = getSceneFromOperation(operation);

568

WxMaUserRiskRank riskResult = wxMaService.getSecurityService()

569

.getUserRiskRank(openid, scene);

570

571

// Define operation permissions based on risk level

572

switch (operation) {

573

case POST_COMMENT:

574

return riskResult.getRiskRank() <= WxMaMediaConstants.RISK_MEDIUM;

575

case UPLOAD_IMAGE:

576

return riskResult.getRiskRank() <= WxMaMediaConstants.RISK_HIGH;

577

case SEND_MESSAGE:

578

return riskResult.getRiskRank() <= WxMaMediaConstants.RISK_LOW;

579

case CREATE_CONTENT:

580

return riskResult.getRiskRank() <= WxMaMediaConstants.RISK_MEDIUM;

581

default:

582

return riskResult.getRiskRank() <= WxMaMediaConstants.RISK_LOW;

583

}

584

585

} catch (WxErrorException e) {

586

logger.error("Risk check failed for {} operation {}: {}",

587

openid, operation, e.getMessage());

588

// Default to disallow on error for safety

589

return false;

590

}

591

}

592

593

private String getRiskLevelDescription(Integer riskRank) {

594

switch (riskRank) {

595

case 0: return "Normal";

596

case 1: return "Low Risk";

597

case 2: return "Medium Risk";

598

case 3: return "High Risk";

599

case 4: return "Very High Risk";

600

default: return "Unknown";

601

}

602

}

603

604

private List<String> generateRecommendations(Integer riskRank) {

605

List<String> recommendations = new ArrayList<>();

606

607

if (riskRank >= WxMaMediaConstants.RISK_MEDIUM) {

608

recommendations.add("Enable manual review for user-generated content");

609

recommendations.add("Increase monitoring frequency");

610

}

611

612

if (riskRank >= WxMaMediaConstants.RISK_HIGH) {

613

recommendations.add("Restrict content creation abilities");

614

recommendations.add("Require additional verification");

615

}

616

617

if (riskRank >= WxMaMediaConstants.RISK_VERY_HIGH) {

618

recommendations.add("Consider temporary restrictions");

619

recommendations.add("Flag for admin review");

620

}

621

622

return recommendations;

623

}

624

}

625

```

626

627

### Media Processing Pipeline

628

629

```java

630

@Service

631

public class MediaProcessingPipeline {

632

633

@Async

634

public CompletableFuture<ProcessedMediaResult> processUploadedMedia(

635

MultipartFile file, String openid, MediaProcessingOptions options) {

636

637

return CompletableFuture.supplyAsync(() -> {

638

try {

639

ProcessedMediaResult result = new ProcessedMediaResult();

640

641

// Step 1: Basic validation

642

if (!validateFile(file)) {

643

result.setSuccess(false);

644

result.setError("Invalid file format or size");

645

return result;

646

}

647

648

// Step 2: Security check

649

boolean isSecure = wxMaService.getSecurityService()

650

.checkImage(file.getInputStream(), file.getOriginalFilename());

651

652

if (!isSecure) {

653

result.setSuccess(false);

654

result.setError("Content security check failed");

655

return result;

656

}

657

658

// Step 3: User risk assessment

659

WxMaUserRiskRank userRisk = wxMaService.getSecurityService()

660

.getUserRiskRank(openid, WxMaMediaConstants.SCENE_SOCIAL);

661

662

if (userRisk.isHighRisk()) {

663

result.setSuccess(false);

664

result.setError("User risk level too high");

665

return result;

666

}

667

668

// Step 4: Process image if needed

669

File processedFile = file instanceof File ? (File) file :

670

convertMultipartToFile(file);

671

672

if (options.isResizeRequired()) {

673

processedFile = imageProcessor.resize(processedFile,

674

options.getTargetWidth(),

675

options.getTargetHeight());

676

}

677

678

// Step 5: Upload to WeChat

679

WxMediaUploadResult uploadResult;

680

if (options.isPermanent()) {

681

uploadResult = wxMaService.getMediaService().uploadImg(processedFile);

682

} else {

683

uploadResult = wxMaService.getMediaService()

684

.uploadTempMedia(WxMaMediaConstants.IMAGE, processedFile);

685

}

686

687

// Step 6: Build result

688

result.setSuccess(true);

689

result.setMediaId(uploadResult.getMediaId());

690

result.setMediaUrl(uploadResult.getUrl());

691

result.setProcessingTime(System.currentTimeMillis() - startTime);

692

693

// Clean up temporary files

694

if (processedFile != file) {

695

processedFile.delete();

696

}

697

698

return result;

699

700

} catch (Exception e) {

701

logger.error("Media processing pipeline failed: {}", e.getMessage());

702

ProcessedMediaResult result = new ProcessedMediaResult();

703

result.setSuccess(false);

704

result.setError("Processing pipeline error: " + e.getMessage());

705

return result;

706

}

707

});

708

}

709

710

private boolean validateFile(MultipartFile file) {

711

// Check file size (e.g., max 10MB)

712

if (file.getSize() > 10 * 1024 * 1024) {

713

return false;

714

}

715

716

// Check file type

717

String contentType = file.getContentType();

718

return contentType != null && contentType.startsWith("image/");

719

}

720

}

721

```

722

723

### Content Moderation Dashboard

724

725

```java

726

@RestController

727

@RequestMapping("/api/moderation")

728

public class ModerationController {

729

730

@PostMapping("/check/text")

731

public ResponseEntity<ModerationResult> checkText(

732

@RequestBody TextModerationRequest request) {

733

734

try {

735

boolean isSecure = wxMaService.getSecurityService()

736

.checkText(request.getContent(),

737

request.getScene(),

738

WxMaMediaConstants.VERSION_LATEST);

739

740

ModerationResult result = new ModerationResult();

741

result.setSecure(isSecure);

742

result.setAction(isSecure ? "approve" : "reject");

743

744

return ResponseEntity.ok(result);

745

746

} catch (WxErrorException e) {

747

logger.error("Text moderation API failed: {}", e.getMessage());

748

return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)

749

.body(new ModerationResult(false, "error", e.getMessage()));

750

}

751

}

752

753

@PostMapping("/check/image")

754

public ResponseEntity<ModerationResult> checkImage(

755

@RequestParam("file") MultipartFile file) {

756

757

try {

758

boolean isSecure = wxMaService.getSecurityService()

759

.checkImage(file.getInputStream(), file.getOriginalFilename());

760

761

ModerationResult result = new ModerationResult();

762

result.setSecure(isSecure);

763

result.setAction(isSecure ? "approve" : "reject");

764

765

return ResponseEntity.ok(result);

766

767

} catch (WxErrorException | IOException e) {

768

logger.error("Image moderation API failed: {}", e.getMessage());

769

return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)

770

.body(new ModerationResult(false, "error", e.getMessage()));

771

}

772

}

773

774

@GetMapping("/user/{openid}/risk")

775

public ResponseEntity<UserRiskProfile> getUserRisk(

776

@PathVariable String openid,

777

@RequestParam(defaultValue = "1") Integer scene) {

778

779

try {

780

WxMaUserRiskRank riskResult = wxMaService.getSecurityService()

781

.getUserRiskRank(openid, scene);

782

783

UserRiskProfile profile = new UserRiskProfile();

784

profile.setOpenid(openid);

785

profile.setRiskRank(riskResult.getRiskRank());

786

profile.setRiskLevel(getRiskLevelDescription(riskResult.getRiskRank()));

787

profile.setAssessmentTime(new Date(riskResult.getTimestamp() * 1000));

788

789

return ResponseEntity.ok(profile);

790

791

} catch (WxErrorException e) {

792

logger.error("User risk API failed: {}", e.getMessage());

793

return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();

794

}

795

}

796

}

797

```

798

799

This media and content module provides comprehensive functionality for media file management, content security checks, and user risk assessment with automated moderation capabilities for WeChat MiniApp applications.