Merge branch 'dev' into NCBACK-34

This commit is contained in:
vladp
2026-01-15 16:55:47 +07:00
11 changed files with 160 additions and 87 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
POSTGRES_DB=no_copy_ POSTGRES_DB=no_copy_
POSTGRES_USER=postgres POSTGRES_USER=ncp_db
POSTGRES_PASSWORD=postgres POSTGRES_PASSWORD=ncpDbApp
POSTGRES_PORT=5432 POSTGRES_PORT=5432
POSTGRES_HOST=postgres POSTGRES_HOST=postgres
+48
View File
@@ -0,0 +1,48 @@
суперпользователь БД:
postgres/postgres
пользователь бд для бэка
ncp_db / ncpDbApp
Подключение к БД для приложения,если volume не существует :
Создаться автоматически.
Если уже существует volume :
docker exec -it postgres psql -U postgres -d postgres
CREATE USER ncp_db WITH PASSWORD 'ncpDbApp';
GRANT ALL PRIVILEGES ON DATABASE no_copy_ TO ncp_db;
\du
\q
-------
psql -U postgres -d no_copy_
-- база
GRANT CONNECT ON DATABASE no_copy_ TO ncp_db;
-- схема
GRANT USAGE ON SCHEMA public TO ncp_db;
-- существующие таблицы
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO ncp_db;
-- существующие sequence (очень важно для id)
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO ncp_db;
-- будущие таблицы
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT ALL ON TABLES TO ncp_db;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT ALL ON SEQUENCES TO ncp_db;
+14 -5
View File
@@ -18,7 +18,7 @@ services:
restart: unless-stopped restart: unless-stopped
db: db:
image: postgres:17 image: postgres:17.7
restart: always restart: always
deploy: deploy:
resources: resources:
@@ -30,14 +30,17 @@ services:
memory: 1G memory: 1G
environment: environment:
POSTGRES_DB: no_copy_ POSTGRES_DB: no_copy_
POSTGRES_USER: postgres # POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres # POSTGRES_PASSWORD: postgres
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_SHARED_BUFFERS: 512MB POSTGRES_SHARED_BUFFERS: 512MB
POSTGRES_EFFECTIVE_CACHE_SIZE: 1536MB POSTGRES_EFFECTIVE_CACHE_SIZE: 1536MB
ports: ports:
- "54320:5432" - "54320:5432"
volumes: volumes:
- pgdata:/var/lib/postgresql/data - pgdata:/var/lib/postgresql/data
- ./init-scripts:/docker-entrypoint-initdb.d:ro
container_name: postgres container_name: postgres
networks: networks:
app-network: app-network:
@@ -61,8 +64,10 @@ services:
# FILE_CHUNK_SIZE: 1048576 # FILE_CHUNK_SIZE: 1048576
FILE_CHUNK_SIZE: 1000000 FILE_CHUNK_SIZE: 1000000
POSTGRES_DB: no_copy_ POSTGRES_DB: no_copy_
POSTGRES_USER: postgres # POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres # POSTGRES_PASSWORD: postgres
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_PORT: 5432 POSTGRES_PORT: 5432
POSTGRES_HOST: db POSTGRES_HOST: db
STORAGE_SERVICE_URL: http://storage:8081 STORAGE_SERVICE_URL: http://storage:8081
@@ -82,6 +87,10 @@ services:
- api - api
volumes: volumes:
- uploads_data:/data/uploads:rw - uploads_data:/data/uploads:rw
healthcheck:
test: [ "CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d no_copy_" ]
interval: 10s
retries: 5
grafana: grafana:
image: grafana/grafana:10.3.1 image: grafana/grafana:10.3.1
+6 -3
View File
@@ -30,6 +30,7 @@ pipeline {
} }
} }
stage('Deploy with docker-compose') { stage('Deploy with docker-compose') {
steps { steps {
script { script {
@@ -38,7 +39,9 @@ pipeline {
credentialsId: 'server-root-password', credentialsId: 'server-root-password',
usernameVariable: 'SSH_USER', usernameVariable: 'SSH_USER',
passwordVariable: 'SSH_PASS' passwordVariable: 'SSH_PASS'
) ),
string(credentialsId: 'DB_USER', variable: 'DB_USER'),
string(credentialsId: 'DB_PASSWORD', variable: 'DB_PASSWORD')
]) { ]) {
sh """ sh """
echo "Deploying branch: ${params.BRANCH}" echo "Deploying branch: ${params.BRANCH}"
@@ -77,8 +80,8 @@ pipeline {
-p 80:8080 \\ -p 80:8080 \\
-v uploads_data:/data/uploads:rw \\ -v uploads_data:/data/uploads:rw \\
-e POSTGRES_DB=no_copy_ \\ -e POSTGRES_DB=no_copy_ \\
-e POSTGRES_USER=postgres \\ -e POSTGRES_USER=$DB_USER \\
-e POSTGRES_PASSWORD=postgres \\ -e POSTGRES_PASSWORD=$DB_PASSWORD \\
-e POSTGRES_PORT=5432 \\ -e POSTGRES_PORT=5432 \\
-e POSTGRES_HOST=db \\ -e POSTGRES_HOST=db \\
--restart unless-stopped \\ --restart unless-stopped \\
+19
View File
@@ -0,0 +1,19 @@
DO $$
BEGIN
IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'ncp_db') THEN
CREATE USER ncp_db WITH PASSWORD 'ncpDbApp';
END IF;
END
$$;
GRANT CONNECT ON DATABASE no_copy_ TO ncp_db;
GRANT USAGE ON SCHEMA public TO ncp_db;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO ncp_db;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO ncp_db;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT ALL ON TABLES TO ncp_db;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT ALL ON SEQUENCES TO ncp_db;
@@ -1,9 +1,11 @@
package ru.soune.nocopy.dto; package ru.soune.nocopy.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data; import lombok.Data;
@Data @Data
@JsonFormat(with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
public class BaseRequest { public class BaseRequest {
@JsonProperty("version") @JsonProperty("version")
Integer version; Integer version;
@@ -1,11 +1,13 @@
package ru.soune.nocopy.dto; package ru.soune.nocopy.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
@Data @Data
@AllArgsConstructor @AllArgsConstructor
@JsonFormat(with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
public class BaseResponse { public class BaseResponse {
@JsonProperty("msg_id") @JsonProperty("msg_id")
private Integer msgId; private Integer msgId;
@@ -1,5 +1,6 @@
package ru.soune.nocopy.dto; package ru.soune.nocopy.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import jakarta.validation.constraints.Email; import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
@@ -10,6 +11,7 @@ import lombok.NoArgsConstructor;
@Data @Data
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
@JsonFormat(with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
public class LoginRequest { public class LoginRequest {
@NotBlank(message = "error.not.blank") @Email(message = "error.not.email") @Size(max = 128) @NotBlank(message = "error.not.blank") @Email(message = "error.not.email") @Size(max = 128)
@@ -1,10 +1,12 @@
package ru.soune.nocopy.dto; package ru.soune.nocopy.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import jakarta.validation.constraints.*; import jakarta.validation.constraints.*;
import lombok.Data; import lombok.Data;
@Data @Data
@JsonFormat(with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
public class RegRequest { public class RegRequest {
@NotEmpty(message = "Full name is required") @NotEmpty(message = "Full name is required")
private String fullName; private String fullName;
@@ -10,6 +10,7 @@ import ru.soune.nocopy.entity.GenderType;
import java.time.LocalDate; import java.time.LocalDate;
@Data @Data
@JsonFormat(with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
public class UserRequest { public class UserRequest {
@Size(min = 2) @Size(min = 2)
private String fullName; private String fullName;
@@ -13,7 +13,7 @@ import java.util.*;
@Component @Component
public class RegRequestValidator implements Validator { public class RegRequestValidator implements Validator {
private static final String COMPANY_REGEX = "^[a-zA-Zа-яА-ЯёЁ0-9\\s\\-&.,'()]{0,200}$"; private static final String COMPANY_REGEX = "^[a-zA-Zа-яА-ЯёЁ0-9\\s\\-&.,'()\"\"«»„‟”“”‘'’‹›❛❜❝❞〝〞〟]{1,200}$";
private static final String NAME_REGEX = "^[a-zA-Zа-яА-ЯёЁ\\s\\-'.]{2,100}$"; private static final String NAME_REGEX = "^[a-zA-Zа-яА-ЯёЁ\\s\\-'.]{2,100}$";
@@ -74,21 +74,6 @@ public class RegRequestValidator implements Validator {
errors.rejectValue("companyName", "companyName.invalid.chars", errors.rejectValue("companyName", "companyName.invalid.chars",
"Company name contains invalid characters"); "Company name contains invalid characters");
} }
validateForbiddenWords(trimmedCompany, "companyName", errors,
Arrays.asList("admin", "root", "system", "test"));
}
private void validateForbiddenWords(String text, String fieldName,
Errors errors, List<String> forbiddenWords) {
String lowerText = text.toLowerCase();
for (String word : forbiddenWords) {
if (lowerText.contains(word)) {
errors.rejectValue(fieldName, fieldName + ".forbidden.word",
"Contains forbidden word: " + word);
break;
}
}
} }
private void validateEmail(String email, Errors errors) { private void validateEmail(String email, Errors errors) {