fix: 新增提案规则,新增自定义后端

This commit is contained in:
Tim
2025-10-23 12:11:22 +08:00
parent 90649b422d
commit 8193c92c91
3 changed files with 120 additions and 20 deletions

View File

@@ -261,7 +261,7 @@ public class PostService {
String proposalDescription String proposalDescription
) { ) {
// 限制访问次数 // 限制访问次数
boolean limitResult = postRateLimit(username); boolean limitResult = isPostLimitReached(username);
if (!limitResult) { if (!limitResult) {
throw new RateLimitException("Too many posts"); throw new RateLimitException("Too many posts");
} }
@@ -407,6 +407,7 @@ public class PostService {
if (post.getStatus() == PostStatus.PUBLISHED) { if (post.getStatus() == PostStatus.PUBLISHED) {
searchIndexEventPublisher.publishPostSaved(post); searchIndexEventPublisher.publishPostSaved(post);
} }
markPostLimit(author.getUsername());
return post; return post;
} }
@@ -480,20 +481,23 @@ public class PostService {
} }
/** /**
* 限制发帖频率 * 检查用户是否达到发帖限制
* @param username * @param username
* @return * @return true - 允许发帖false - 已达限制
*/ */
private boolean postRateLimit(String username) { private boolean isPostLimitReached(String username) {
String key = CachingConfig.LIMIT_CACHE_NAME + ":posts:" + username; String key = CachingConfig.LIMIT_CACHE_NAME + ":posts:" + username;
String result = (String) redisTemplate.opsForValue().get(key); String result = (String) redisTemplate.opsForValue().get(key);
//最近没有创建过文章 return StringUtils.isEmpty(result);
if (StringUtils.isEmpty(result)) { }
// 限制频率为5分钟
redisTemplate.opsForValue().set(key, "1", Duration.ofMinutes(5)); /**
return true; * 标记用户发帖触发limit计时
} * @param username
return false; */
private void markPostLimit(String username) {
String key = CachingConfig.LIMIT_CACHE_NAME + ":posts:" + username;
redisTemplate.opsForValue().set(key, "1", Duration.ofMinutes(5));
} }
@CacheEvict(value = CachingConfig.POST_CACHE_NAME, allEntries = true) @CacheEvict(value = CachingConfig.POST_CACHE_NAME, allEntries = true)

View File

@@ -25,6 +25,10 @@ services:
timeout: 3s timeout: 3s
retries: 30 retries: 30
start_period: 20s start_period: 20s
profiles:
- dev
- dev_local_backend
- prod
# OpenSearch Service # OpenSearch Service
opensearch: opensearch:
@@ -61,6 +65,9 @@ services:
start_period: 60s start_period: 60s
networks: networks:
- openisle-network - openisle-network
profiles:
- dev
- dev_local_backend
dashboards: dashboards:
image: opensearchproject/opensearch-dashboards:3.0.0 image: opensearchproject/opensearch-dashboards:3.0.0
@@ -75,6 +82,10 @@ services:
restart: unless-stopped restart: unless-stopped
networks: networks:
- openisle-network - openisle-network
profiles:
- dev
- dev_local_backend
- prod
rabbitmq: rabbitmq:
image: rabbitmq:3.13-management image: rabbitmq:3.13-management
@@ -98,6 +109,10 @@ services:
start_period: 30s start_period: 30s
networks: networks:
- openisle-network - openisle-network
profiles:
- dev
- dev_local_backend
- prod
redis: redis:
image: redis:7 image: redis:7
@@ -111,6 +126,10 @@ services:
- redis-data:/data - redis-data:/data
networks: networks:
- openisle-network - openisle-network
profiles:
- dev
- dev_local_backend
- prod
# Java spring boot service (开发便捷镜像,后续可换成打包镜像) # Java spring boot service (开发便捷镜像,后续可换成打包镜像)
springboot: springboot:
@@ -155,6 +174,9 @@ services:
start_period: 60s start_period: 60s
networks: networks:
- openisle-network - openisle-network
profiles:
- dev
- prod
websocket-service: websocket-service:
image: maven:3.9-eclipse-temurin-17 image: maven:3.9-eclipse-temurin-17
@@ -186,6 +208,10 @@ services:
start_period: 60s start_period: 60s
networks: networks:
- openisle-network - openisle-network
profiles:
- dev
- dev_local_backend
- prod
frontend_dev: frontend_dev:
image: node:20 image: node:20
@@ -208,6 +234,28 @@ services:
- openisle-network - openisle-network
profiles: profiles:
- dev - dev
frontend_dev_local_backend:
image: node:20
container_name: ${COMPOSE_PROJECT_NAME}-openisle-frontend-dev-local-backend
working_dir: /app
env_file:
- ${ENV_FILE:-../.env}
command: sh -c "npm install && npm run dev"
volumes:
- ../frontend_nuxt:/app
- frontend-node-modules:/app/node_modules
ports:
- "${FRONTEND_PORT:-3000}:3000"
depends_on:
websocket-service:
condition: service_healthy
networks:
- openisle-network
profiles:
- dev_local_backend
extra_hosts:
- "host.docker.internal:host-gateway"
frontend_service: frontend_service:
build: build:
@@ -226,13 +274,13 @@ services:
websocket-service: websocket-service:
condition: service_healthy condition: service_healthy
restart: unless-stopped restart: unless-stopped
profiles: ["staging", "prod"] profiles:
- prod
# 监听“frontend_dev 容器自身的” 127.0.0.1:8080 → 转发到 springboot:8080
loopback_8080: loopback_8080:
image: alpine/socat image: alpine/socat
container_name: ${COMPOSE_PROJECT_NAME}-loopback-8080 container_name: ${COMPOSE_PROJECT_NAME}-loopback-8080
# 监听“frontend_dev 容器自身的” 127.0.0.1:8080 → 转发到 springboot:8080
command: command:
- -d - -d
- -d - -d
@@ -243,13 +291,37 @@ services:
springboot: springboot:
condition: service_healthy condition: service_healthy
network_mode: "service:frontend_dev" network_mode: "service:frontend_dev"
profiles: ["dev"]
healthcheck: healthcheck:
test: ["CMD", "sh", "-c", "nc -z 127.0.0.1 8080"] test: ["CMD", "sh", "-c", "nc -z 127.0.0.1 8080"]
interval: 5s interval: 5s
timeout: 3s timeout: 3s
retries: 20 retries: 20
start_period: 10s start_period: 10s
profiles:
- dev
# 监听“frontend_dev 容器自身的” 127.0.0.1:8080 → 转发到 启动docker的本机:8080
loopback_8080_host:
image: alpine/socat
container_name: ${COMPOSE_PROJECT_NAME}-loopback-8080-host
command:
- -d
- -d
- -ly
- TCP4-LISTEN:8080,bind=127.0.0.1,reuseaddr,fork
- TCP4:host.docker.internal:8080
network_mode: "service:frontend_dev_local_backend"
depends_on:
frontend_dev_local_backend:
condition: service_started
healthcheck:
test: ["CMD", "sh", "-c", "nc -z 127.0.0.1 8080"]
interval: 5s
timeout: 3s
retries: 20
start_period: 10s
profiles:
- dev_local_backend
loopback_8082: loopback_8082:
image: alpine/socat image: alpine/socat
@@ -265,13 +337,37 @@ services:
websocket-service: websocket-service:
condition: service_healthy condition: service_healthy
network_mode: "service:frontend_dev" network_mode: "service:frontend_dev"
profiles: ["dev"]
healthcheck: healthcheck:
test: ["CMD", "sh", "-c", "nc -z 127.0.0.1 8082"] test: ["CMD", "sh", "-c", "nc -z 127.0.0.1 8082"]
interval: 5s interval: 5s
timeout: 3s timeout: 3s
retries: 20 retries: 20
start_period: 10s start_period: 10s
profiles:
- dev
loopback_8082_host:
image: alpine/socat
container_name: ${COMPOSE_PROJECT_NAME}-loopback-8082-host
# 监听 127.0.0.1:8082 → 转发到 websocket-service:8082WS 纯 TCP 可直接过)
command:
- -d
- -d
- -ly
- TCP4-LISTEN:8082,bind=127.0.0.1,reuseaddr,fork
- TCP4:websocket-service:8082
depends_on:
websocket-service:
condition: service_healthy
network_mode: "service:frontend_dev_local_backend"
healthcheck:
test: ["CMD", "sh", "-c", "nc -z 127.0.0.1 8082"]
interval: 5s
timeout: 3s
retries: 20
start_period: 10s
profiles:
- dev_local_backend
networks: networks:
openisle-network: openisle-network:

View File

@@ -5,10 +5,10 @@
<info-icon class="proposal-description-title-icon" />提案规则说明</span <info-icon class="proposal-description-title-icon" />提案规则说明</span
> >
<div class="proposal-description-content"> <div class="proposal-description-content">
<p>提案规则1</p> <p>📛 拟议分类名称需保持唯一请勿与现有分类或正在提案中的名称重复</p>
<p>提案规则</p> <p>📝 请在下方详细说明提案目的预期价值及补充材料方便大家快速理解</p>
<p>提案规则</p> <p>🗳 提案提交后将开放 3 天投票需达到至少 60% 的赞成率并满 10 人参与方可通过</p>
<p>提案规则</p> <p>🤝 讨论请遵循社区守则保持礼貌和善欢迎附上相关案例或参考链接</p>
</div> </div>
</div> </div>
<div class="proposal-row"> <div class="proposal-row">