English content

This commit is contained in:
Braydon 2024-06-06 14:22:13 -04:00
parent a2c1e11f56
commit be480ead88
12 changed files with 2894 additions and 2 deletions

@ -0,0 +1,10 @@
package me.braydon.profanity.common;
/**
* A list of supported languages.
*
* @author Braydon
*/
public enum Language {
ENGLISH
}

@ -0,0 +1,48 @@
package me.braydon.profanity.controller;
import lombok.NonNull;
import me.braydon.profanity.exception.impl.BadRequestException;
import me.braydon.profanity.model.input.ContentProcessInput;
import me.braydon.profanity.model.response.ContentProcessResponse;
import me.braydon.profanity.service.FiltrationService;
import me.braydon.profanity.service.ModerationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Braydon
*/
@RestController
@RequestMapping(value = "/content", produces = MediaType.APPLICATION_JSON_VALUE)
public final class ContentController {
/**
* The filtration service to use.
*/
@NonNull private final FiltrationService filtrationService;
/**
* The moderation service to use.
*/
@NonNull private final ModerationService moderationService;
@Autowired
public ContentController(@NonNull FiltrationService filtrationService, @NonNull ModerationService moderationService) {
this.filtrationService = filtrationService;
this.moderationService = moderationService;
}
@PostMapping(path = "/process") @ResponseBody @NonNull
public ResponseEntity<ContentProcessResponse> process(ContentProcessInput input) throws BadRequestException {
if (input == null || (input.isMalformed())) { // Validate the input
throw new BadRequestException("Missing or malformed input.");
}
ContentProcessResponse response = filtrationService.process(input); // Filter the content
moderationService.handleAlerts(response); // Handle moderation
return ResponseEntity.ok(response);
}
}

@ -0,0 +1,38 @@
package me.braydon.profanity.exception;
import jakarta.servlet.http.HttpServletRequest;
import lombok.NonNull;
import me.braydon.profanity.model.response.ErrorResponse;
import org.springframework.boot.autoconfigure.web.servlet.error.AbstractErrorController;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
/**
* The route to handle errors for this app.
*
* @author Braydon
*/
@RestController
@RequestMapping(value = "/error", produces = MediaType.APPLICATION_JSON_VALUE)
public final class ExceptionController extends AbstractErrorController {
public ExceptionController(@NonNull ErrorAttributes errorAttributes) {
super(errorAttributes);
}
@RequestMapping @ResponseBody @NonNull
public ResponseEntity<ErrorResponse> onError(@NonNull HttpServletRequest request) {
Map<String, Object> error = getErrorAttributes(request, ErrorAttributeOptions.of(
ErrorAttributeOptions.Include.MESSAGE
));
HttpStatus status = getStatus(request); // The status code
return new ResponseEntity<>(new ErrorResponse(status, (String) error.get("message")), status);
}
}

@ -0,0 +1,18 @@
package me.braydon.profanity.exception.impl;
import lombok.NonNull;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
/**
* This exception is raised
* when a bad request is made.
*
* @author Braydon
*/
@ResponseStatus(HttpStatus.BAD_REQUEST)
public final class BadRequestException extends RuntimeException {
public BadRequestException(@NonNull String message) {
super(message);
}
}

@ -0,0 +1,33 @@
package me.braydon.profanity.model;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NonNull;
import me.braydon.profanity.common.Language;
import java.util.List;
import java.util.Map;
/**
* A list of profane words and
* phrases for each language.
*
* @author Braydon
*/
@AllArgsConstructor @Getter
public final class ProfanityList {
/**
* The links that are whitelisted from the filter.
*/
@NonNull private final List<String> whitelistedLinks;
/**
* Profane words for each language.
*/
@NonNull private final Map<Language, List<String>> profaneWords;
/**
* Profane phrases for each language.
*/
@NonNull private final Map<Language, List<String>> profanePhrases;
}

@ -0,0 +1,26 @@
package me.braydon.profanity.model.input;
import lombok.Getter;
import lombok.Setter;
/**
* The input to use for processing content.
*
* @author Braydon
*/
@Setter @Getter
public final class ContentProcessInput {
/**
* The content to process.
*/
private String content;
/**
* Check if this input is malformed.
*
* @return whether the input is malformed
*/
public boolean isMalformed() {
return content == null || content.isEmpty();
}
}

@ -0,0 +1,37 @@
package me.braydon.profanity.model.response;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NonNull;
import java.util.List;
/**
* @author Braydon
*/
@AllArgsConstructor @Getter
public final class ContentProcessResponse {
/**
* The replacement for the content.
*/
@NonNull private final String replacement;
/**
* The matched elements in the content.
*/
@NonNull private final List<String> matched;
/**
* The tags obtained from the content.
*/
@NonNull private final List<String> tags;
/**
* The score of the content.
* <p>
* This is a value from 0-1 representing the
* probability that the content is profane.
* </p>
*/
private final double score;
}

@ -0,0 +1,43 @@
package me.braydon.profanity.model.response;
import lombok.Getter;
import lombok.NonNull;
import lombok.ToString;
import org.springframework.http.HttpStatus;
import java.util.Date;
/**
* A response representing an error.
*
* @author Braydon
*/
@Getter @ToString
public class ErrorResponse {
/**
* The status code of this error.
*/
@NonNull private final HttpStatus status;
/**
* The HTTP code of this error.
*/
private final int code;
/**
* The message of this error.
*/
@NonNull private final String message;
/**
* The timestamp this error occurred.
*/
@NonNull private final Date timestamp;
public ErrorResponse(@NonNull HttpStatus status, @NonNull String message) {
this.status = status;
this.message = message;
this.code = status.value();
timestamp = new Date();
}
}

@ -0,0 +1,18 @@
package me.braydon.profanity.repository;
import me.braydon.profanity.model.ProfanityList;
import org.springframework.data.mongodb.repository.MongoRepository;
/**
* @author Braydon
*/
public interface ProfanityListRepository extends MongoRepository<ProfanityList, String> {
/**
* Get the profanity list.
*
* @return the profanity list
*/
default ProfanityList getProfanityList() {
return findById("primary").orElse(null);
}
}

@ -1,7 +1,14 @@
package me.braydon.profanity.service;
import lombok.NonNull;
import me.braydon.profanity.model.input.ContentProcessInput;
import me.braydon.profanity.model.response.ContentProcessResponse;
import me.braydon.profanity.repository.ProfanityListRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
/**
* This service is responsible
* for filtering text content.
@ -9,4 +16,16 @@ import org.springframework.stereotype.Service;
* @author Braydon
*/
@Service
public final class FiltrationService { }
public final class FiltrationService {
@NonNull private final ProfanityListRepository profanityListRepository;
@Autowired
public FiltrationService(@NonNull ProfanityListRepository profanityListRepository) {
this.profanityListRepository = profanityListRepository;
}
@NonNull
public ContentProcessResponse process(@NonNull ContentProcessInput input) {
return new ContentProcessResponse(input.getContent(), new ArrayList<>(), new ArrayList<>(), 0D);
}
}

@ -1,5 +1,7 @@
package me.braydon.profanity.service;
import lombok.NonNull;
import me.braydon.profanity.model.response.ContentProcessResponse;
import org.springframework.stereotype.Service;
/**
@ -9,4 +11,8 @@ import org.springframework.stereotype.Service;
* @author Braydon
*/
@Service
public final class ModerationService { }
public final class ModerationService {
public void handleAlerts(@NonNull ContentProcessResponse response) {
// TODO: handle alerting of the content to the appropriate parties
}
}

2596
lists/english.json Normal file

File diff suppressed because it is too large Load Diff