This commit is contained in:
@@ -2,7 +2,7 @@ CREATE TABLE IF NOT EXISTS entities (
|
|||||||
id UUID PRIMARY KEY DEFAULT uuidv7(),
|
id UUID PRIMARY KEY DEFAULT uuidv7(),
|
||||||
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
slug TEXT,
|
slug TEXT UNIQUE,
|
||||||
description TEXT,
|
description TEXT,
|
||||||
status SMALLINT,
|
status SMALLINT,
|
||||||
time_start INT,
|
time_start INT,
|
||||||
@@ -12,6 +12,9 @@ CREATE TABLE IF NOT EXISTS entities (
|
|||||||
updated_at TIMESTAMPTZ DEFAULT now()
|
updated_at TIMESTAMPTZ DEFAULT now()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX idx_entities_slug_not_deleted
|
||||||
|
ON entities(slug)
|
||||||
|
WHERE is_deleted = false;
|
||||||
|
|
||||||
CREATE INDEX idx_entities_name_search
|
CREATE INDEX idx_entities_name_search
|
||||||
ON entities USING GIN (name gin_trgm_ops);
|
ON entities USING GIN (name gin_trgm_ops);
|
||||||
|
|||||||
@@ -4,12 +4,16 @@ CREATE TABLE IF NOT EXISTS wikis (
|
|||||||
id UUID PRIMARY KEY DEFAULT uuidv7(),
|
id UUID PRIMARY KEY DEFAULT uuidv7(),
|
||||||
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
||||||
title TEXT,
|
title TEXT,
|
||||||
|
slug TEXT,
|
||||||
content TEXT,
|
content TEXT,
|
||||||
is_deleted BOOLEAN NOT NULL DEFAULT false,
|
is_deleted BOOLEAN NOT NULL DEFAULT false,
|
||||||
created_at TIMESTAMPTZ DEFAULT now(),
|
created_at TIMESTAMPTZ DEFAULT now(),
|
||||||
updated_at TIMESTAMPTZ DEFAULT now()
|
updated_at TIMESTAMPTZ DEFAULT now()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX idx_wikis_slug_not_deleted
|
||||||
|
ON wikis(slug)
|
||||||
|
WHERE is_deleted = false;
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS entity_wikis (
|
CREATE TABLE IF NOT EXISTS entity_wikis (
|
||||||
entity_id UUID REFERENCES entities(id) ON DELETE CASCADE,
|
entity_id UUID REFERENCES entities(id) ON DELETE CASCADE,
|
||||||
|
|||||||
@@ -60,3 +60,8 @@ WHERE project_id = $1 AND is_deleted = false;
|
|||||||
UPDATE entities
|
UPDATE entities
|
||||||
SET is_deleted = true
|
SET is_deleted = true
|
||||||
WHERE id = ANY($1::uuid[]);
|
WHERE id = ANY($1::uuid[]);
|
||||||
|
|
||||||
|
-- name: GetEntityBySlug :one
|
||||||
|
SELECT *
|
||||||
|
FROM entities
|
||||||
|
WHERE slug = $1 AND is_deleted = false;
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
-- name: CreateWiki :one
|
-- name: CreateWiki :one
|
||||||
INSERT INTO wikis (
|
INSERT INTO wikis (
|
||||||
id, title, content, project_id
|
id, title, slug, content, project_id
|
||||||
) VALUES (
|
) VALUES (
|
||||||
COALESCE(sqlc.narg('id')::uuid, uuidv7()), $1, $2, $3
|
COALESCE(sqlc.narg('id')::uuid, uuidv7()), $1, $2, $3, $4
|
||||||
)
|
)
|
||||||
RETURNING *;
|
RETURNING *;
|
||||||
|
|
||||||
@@ -15,6 +15,7 @@ WHERE id = $1 AND is_deleted = false;
|
|||||||
UPDATE wikis
|
UPDATE wikis
|
||||||
SET
|
SET
|
||||||
title = COALESCE(sqlc.narg('title'), title),
|
title = COALESCE(sqlc.narg('title'), title),
|
||||||
|
slug = COALESCE(sqlc.narg('slug'), slug),
|
||||||
content = COALESCE(sqlc.narg('content'), content),
|
content = COALESCE(sqlc.narg('content'), content),
|
||||||
project_id = COALESCE(sqlc.narg('project_id'), project_id)
|
project_id = COALESCE(sqlc.narg('project_id'), project_id)
|
||||||
WHERE id = sqlc.arg('id') AND is_deleted = false
|
WHERE id = sqlc.arg('id') AND is_deleted = false
|
||||||
@@ -84,3 +85,8 @@ WHERE wiki_id = $1;
|
|||||||
-- name: DeleteEntityWiki :exec
|
-- name: DeleteEntityWiki :exec
|
||||||
DELETE FROM entity_wikis
|
DELETE FROM entity_wikis
|
||||||
WHERE entity_id = $1 AND wiki_id = $2;
|
WHERE entity_id = $1 AND wiki_id = $2;
|
||||||
|
|
||||||
|
-- name: GetWikiBySlug :one
|
||||||
|
SELECT *
|
||||||
|
FROM wikis
|
||||||
|
WHERE slug = $1 AND is_deleted = false;
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ CREATE TABLE IF NOT EXISTS entities (
|
|||||||
id UUID PRIMARY KEY DEFAULT uuidv7(),
|
id UUID PRIMARY KEY DEFAULT uuidv7(),
|
||||||
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
slug TEXT,
|
slug TEXT UNIQUE,
|
||||||
description TEXT,
|
description TEXT,
|
||||||
status SMALLINT,
|
status SMALLINT,
|
||||||
time_start INT,
|
time_start INT,
|
||||||
@@ -101,6 +101,7 @@ CREATE TABLE IF NOT EXISTS wikis (
|
|||||||
id UUID PRIMARY KEY DEFAULT uuidv7(),
|
id UUID PRIMARY KEY DEFAULT uuidv7(),
|
||||||
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
||||||
title TEXT,
|
title TEXT,
|
||||||
|
slug TEXT UNIQUE,
|
||||||
content TEXT,
|
content TEXT,
|
||||||
is_deleted BOOLEAN NOT NULL DEFAULT false,
|
is_deleted BOOLEAN NOT NULL DEFAULT false,
|
||||||
created_at TIMESTAMPTZ DEFAULT now(),
|
created_at TIMESTAMPTZ DEFAULT now(),
|
||||||
@@ -114,8 +115,6 @@ CREATE TABLE IF NOT EXISTS entity_wikis (
|
|||||||
PRIMARY KEY (entity_id, wiki_id)
|
PRIMARY KEY (entity_id, wiki_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE INDEX idx_entity_wikis_project_id ON entity_wikis(project_id);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS geometries (
|
CREATE TABLE IF NOT EXISTS geometries (
|
||||||
id UUID PRIMARY KEY DEFAULT uuidv7(),
|
id UUID PRIMARY KEY DEFAULT uuidv7(),
|
||||||
geo_type SMALLINT NOT NULL DEFAULT 1,
|
geo_type SMALLINT NOT NULL DEFAULT 1,
|
||||||
@@ -137,8 +136,6 @@ CREATE TABLE IF NOT EXISTS entity_geometries (
|
|||||||
PRIMARY KEY (entity_id, geometry_id)
|
PRIMARY KEY (entity_id, geometry_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE INDEX idx_entity_geometries_project_id ON entity_geometries(project_id);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS commits (
|
CREATE TABLE IF NOT EXISTS commits (
|
||||||
id UUID PRIMARY KEY DEFAULT uuidv7(),
|
id UUID PRIMARY KEY DEFAULT uuidv7(),
|
||||||
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
||||||
|
|||||||
160
docs/docs.go
160
docs/docs.go
@@ -403,7 +403,7 @@ const docTemplate = `{
|
|||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
"ApiKeyAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "Ask a history question based on project context or global knowledge using RAG",
|
"description": "Ask a history question based on project context or global knowledge using RAG",
|
||||||
@@ -516,6 +516,82 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/entities/slug/exists": {
|
||||||
|
"get": {
|
||||||
|
"description": "Check if a given slug already exists for entities",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Entities"
|
||||||
|
],
|
||||||
|
"summary": "Check entity slug existence",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Slug to check",
|
||||||
|
"name": "slug",
|
||||||
|
"in": "query",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/history-api_internal_dtos_response.CommonResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/history-api_internal_dtos_response.CommonResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/entities/slug/{slug}": {
|
||||||
|
"get": {
|
||||||
|
"description": "Get detailed information about a specific entity by its unique slug",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Entities"
|
||||||
|
],
|
||||||
|
"summary": "Get entity by slug",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Entity Slug",
|
||||||
|
"name": "slug",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/history-api_internal_dtos_response.CommonResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Not Found",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/history-api_internal_dtos_response.CommonResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/entities/{id}": {
|
"/entities/{id}": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Get detailed information about a specific entity",
|
"description": "Get detailed information about a specific entity",
|
||||||
@@ -3519,6 +3595,82 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/wikis/slug/exists": {
|
||||||
|
"get": {
|
||||||
|
"description": "Check if a given slug already exists for wikis",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Wikis"
|
||||||
|
],
|
||||||
|
"summary": "Check wiki slug existence",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Slug to check",
|
||||||
|
"name": "slug",
|
||||||
|
"in": "query",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/history-api_internal_dtos_response.CommonResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/history-api_internal_dtos_response.CommonResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/wikis/slug/{slug}": {
|
||||||
|
"get": {
|
||||||
|
"description": "Get detailed information about a specific wiki by its unique slug",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Wikis"
|
||||||
|
],
|
||||||
|
"summary": "Get wiki by slug",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Wiki Slug",
|
||||||
|
"name": "slug",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/history-api_internal_dtos_response.CommonResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Not Found",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/history-api_internal_dtos_response.CommonResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/wikis/{id}": {
|
"/wikis/{id}": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Get detailed information about a specific wiki",
|
"description": "Get detailed information about a specific wiki",
|
||||||
@@ -3847,7 +3999,8 @@ const docTemplate = `{
|
|||||||
"history-api_internal_dtos_request.EntitySnapshot": {
|
"history-api_internal_dtos_request.EntitySnapshot": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"id"
|
"id",
|
||||||
|
"name"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"base_hash": {
|
"base_hash": {
|
||||||
@@ -4360,6 +4513,9 @@ const docTemplate = `{
|
|||||||
"reference"
|
"reference"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"slug": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"source": {
|
"source": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
|
|||||||
@@ -396,7 +396,7 @@
|
|||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
"ApiKeyAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "Ask a history question based on project context or global knowledge using RAG",
|
"description": "Ask a history question based on project context or global knowledge using RAG",
|
||||||
@@ -509,6 +509,82 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/entities/slug/exists": {
|
||||||
|
"get": {
|
||||||
|
"description": "Check if a given slug already exists for entities",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Entities"
|
||||||
|
],
|
||||||
|
"summary": "Check entity slug existence",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Slug to check",
|
||||||
|
"name": "slug",
|
||||||
|
"in": "query",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/history-api_internal_dtos_response.CommonResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/history-api_internal_dtos_response.CommonResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/entities/slug/{slug}": {
|
||||||
|
"get": {
|
||||||
|
"description": "Get detailed information about a specific entity by its unique slug",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Entities"
|
||||||
|
],
|
||||||
|
"summary": "Get entity by slug",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Entity Slug",
|
||||||
|
"name": "slug",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/history-api_internal_dtos_response.CommonResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Not Found",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/history-api_internal_dtos_response.CommonResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/entities/{id}": {
|
"/entities/{id}": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Get detailed information about a specific entity",
|
"description": "Get detailed information about a specific entity",
|
||||||
@@ -3512,6 +3588,82 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/wikis/slug/exists": {
|
||||||
|
"get": {
|
||||||
|
"description": "Check if a given slug already exists for wikis",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Wikis"
|
||||||
|
],
|
||||||
|
"summary": "Check wiki slug existence",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Slug to check",
|
||||||
|
"name": "slug",
|
||||||
|
"in": "query",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/history-api_internal_dtos_response.CommonResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/history-api_internal_dtos_response.CommonResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/wikis/slug/{slug}": {
|
||||||
|
"get": {
|
||||||
|
"description": "Get detailed information about a specific wiki by its unique slug",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Wikis"
|
||||||
|
],
|
||||||
|
"summary": "Get wiki by slug",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Wiki Slug",
|
||||||
|
"name": "slug",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/history-api_internal_dtos_response.CommonResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Not Found",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/history-api_internal_dtos_response.CommonResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/wikis/{id}": {
|
"/wikis/{id}": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Get detailed information about a specific wiki",
|
"description": "Get detailed information about a specific wiki",
|
||||||
@@ -3840,7 +3992,8 @@
|
|||||||
"history-api_internal_dtos_request.EntitySnapshot": {
|
"history-api_internal_dtos_request.EntitySnapshot": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"id"
|
"id",
|
||||||
|
"name"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"base_hash": {
|
"base_hash": {
|
||||||
@@ -4353,6 +4506,9 @@
|
|||||||
"reference"
|
"reference"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"slug": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"source": {
|
"source": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
|
|||||||
@@ -232,6 +232,7 @@ definitions:
|
|||||||
type: number
|
type: number
|
||||||
required:
|
required:
|
||||||
- id
|
- id
|
||||||
|
- name
|
||||||
type: object
|
type: object
|
||||||
history-api_internal_dtos_request.EntityWikiLinkSnapshot:
|
history-api_internal_dtos_request.EntityWikiLinkSnapshot:
|
||||||
properties:
|
properties:
|
||||||
@@ -550,6 +551,8 @@ definitions:
|
|||||||
- delete
|
- delete
|
||||||
- reference
|
- reference
|
||||||
type: string
|
type: string
|
||||||
|
slug:
|
||||||
|
type: string
|
||||||
source:
|
source:
|
||||||
enum:
|
enum:
|
||||||
- inline
|
- inline
|
||||||
@@ -899,7 +902,7 @@ paths:
|
|||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/history-api_internal_dtos_response.CommonResponse'
|
$ref: '#/definitions/history-api_internal_dtos_response.CommonResponse'
|
||||||
security:
|
security:
|
||||||
- ApiKeyAuth: []
|
- BearerAuth: []
|
||||||
summary: Ask the AI chatbot
|
summary: Ask the AI chatbot
|
||||||
tags:
|
tags:
|
||||||
- Chatbot
|
- Chatbot
|
||||||
@@ -963,6 +966,57 @@ paths:
|
|||||||
summary: Get entity by ID
|
summary: Get entity by ID
|
||||||
tags:
|
tags:
|
||||||
- Entities
|
- Entities
|
||||||
|
/entities/slug/{slug}:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Get detailed information about a specific entity by its unique
|
||||||
|
slug
|
||||||
|
parameters:
|
||||||
|
- description: Entity Slug
|
||||||
|
in: path
|
||||||
|
name: slug
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/history-api_internal_dtos_response.CommonResponse'
|
||||||
|
"404":
|
||||||
|
description: Not Found
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/history-api_internal_dtos_response.CommonResponse'
|
||||||
|
summary: Get entity by slug
|
||||||
|
tags:
|
||||||
|
- Entities
|
||||||
|
/entities/slug/exists:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Check if a given slug already exists for entities
|
||||||
|
parameters:
|
||||||
|
- description: Slug to check
|
||||||
|
in: query
|
||||||
|
name: slug
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/history-api_internal_dtos_response.CommonResponse'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/history-api_internal_dtos_response.CommonResponse'
|
||||||
|
summary: Check entity slug existence
|
||||||
|
tags:
|
||||||
|
- Entities
|
||||||
/geometries:
|
/geometries:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
@@ -2902,6 +2956,56 @@ paths:
|
|||||||
summary: Get wiki by ID
|
summary: Get wiki by ID
|
||||||
tags:
|
tags:
|
||||||
- Wikis
|
- Wikis
|
||||||
|
/wikis/slug/{slug}:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Get detailed information about a specific wiki by its unique slug
|
||||||
|
parameters:
|
||||||
|
- description: Wiki Slug
|
||||||
|
in: path
|
||||||
|
name: slug
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/history-api_internal_dtos_response.CommonResponse'
|
||||||
|
"404":
|
||||||
|
description: Not Found
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/history-api_internal_dtos_response.CommonResponse'
|
||||||
|
summary: Get wiki by slug
|
||||||
|
tags:
|
||||||
|
- Wikis
|
||||||
|
/wikis/slug/exists:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Check if a given slug already exists for wikis
|
||||||
|
parameters:
|
||||||
|
- description: Slug to check
|
||||||
|
in: query
|
||||||
|
name: slug
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/history-api_internal_dtos_response.CommonResponse'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/history-api_internal_dtos_response.CommonResponse'
|
||||||
|
summary: Check wiki slug existence
|
||||||
|
tags:
|
||||||
|
- Wikis
|
||||||
securityDefinitions:
|
securityDefinitions:
|
||||||
BearerAuth:
|
BearerAuth:
|
||||||
description: Type "Bearer " followed by a space and JWT token.
|
description: Type "Bearer " followed by a space and JWT token.
|
||||||
|
|||||||
@@ -46,6 +46,60 @@ func (h *EntityController) GetEntityById(c fiber.Ctx) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetEntityBySlug handles fetching a single entity by slug.
|
||||||
|
// @Summary Get entity by slug
|
||||||
|
// @Description Get detailed information about a specific entity by its unique slug
|
||||||
|
// @Tags Entities
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param slug path string true "Entity Slug"
|
||||||
|
// @Success 200 {object} response.CommonResponse
|
||||||
|
// @Failure 404 {object} response.CommonResponse
|
||||||
|
// @Router /entities/slug/{slug} [get]
|
||||||
|
func (h *EntityController) GetEntityBySlug(c fiber.Ctx) error {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
slug := c.Params("slug")
|
||||||
|
res, err := h.service.GetEntityBySlug(ctx, slug)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(err.Code).JSON(response.CommonResponse{
|
||||||
|
Status: false,
|
||||||
|
Message: err.Message,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return c.Status(fiber.StatusOK).JSON(response.CommonResponse{
|
||||||
|
Status: true,
|
||||||
|
Data: res,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsExistEntitySlug checks if an entity slug already exists.
|
||||||
|
// @Summary Check entity slug existence
|
||||||
|
// @Description Check if a given slug already exists for entities
|
||||||
|
// @Tags Entities
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param slug query string true "Slug to check"
|
||||||
|
// @Success 200 {object} response.CommonResponse
|
||||||
|
// @Failure 400 {object} response.CommonResponse
|
||||||
|
// @Router /entities/slug/exists [get]
|
||||||
|
func (h *EntityController) IsExistEntitySlug(c fiber.Ctx) error {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
slug := c.Query("slug")
|
||||||
|
exists, err := h.service.IsExistEntitySlug(ctx, slug)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(err.Code).JSON(response.CommonResponse{
|
||||||
|
Status: false,
|
||||||
|
Message: err.Message,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return c.Status(fiber.StatusOK).JSON(response.CommonResponse{
|
||||||
|
Status: true,
|
||||||
|
Data: map[string]bool{"exists": exists},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// SearchEntities handles searching for entities.
|
// SearchEntities handles searching for entities.
|
||||||
// @Summary Search entities
|
// @Summary Search entities
|
||||||
// @Description Search entities with cursor pagination
|
// @Description Search entities with cursor pagination
|
||||||
@@ -81,3 +135,4 @@ func (h *EntityController) SearchEntities(c fiber.Ctx) error {
|
|||||||
Data: res,
|
Data: res,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,60 @@ func (h *WikiController) GetWikiById(c fiber.Ctx) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetWikiBySlug handles fetching a single wiki by slug.
|
||||||
|
// @Summary Get wiki by slug
|
||||||
|
// @Description Get detailed information about a specific wiki by its unique slug
|
||||||
|
// @Tags Wikis
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param slug path string true "Wiki Slug"
|
||||||
|
// @Success 200 {object} response.CommonResponse
|
||||||
|
// @Failure 404 {object} response.CommonResponse
|
||||||
|
// @Router /wikis/slug/{slug} [get]
|
||||||
|
func (h *WikiController) GetWikiBySlug(c fiber.Ctx) error {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
slug := c.Params("slug")
|
||||||
|
res, err := h.service.GetWikiBySlug(ctx, slug)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(err.Code).JSON(response.CommonResponse{
|
||||||
|
Status: false,
|
||||||
|
Message: err.Message,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return c.Status(fiber.StatusOK).JSON(response.CommonResponse{
|
||||||
|
Status: true,
|
||||||
|
Data: res,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsExistWikiSlug checks if a wiki slug already exists.
|
||||||
|
// @Summary Check wiki slug existence
|
||||||
|
// @Description Check if a given slug already exists for wikis
|
||||||
|
// @Tags Wikis
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param slug query string true "Slug to check"
|
||||||
|
// @Success 200 {object} response.CommonResponse
|
||||||
|
// @Failure 400 {object} response.CommonResponse
|
||||||
|
// @Router /wikis/slug/exists [get]
|
||||||
|
func (h *WikiController) IsExistWikiSlug(c fiber.Ctx) error {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
slug := c.Query("slug")
|
||||||
|
exists, err := h.service.IsExistWikiSlug(ctx, slug)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(err.Code).JSON(response.CommonResponse{
|
||||||
|
Status: false,
|
||||||
|
Message: err.Message,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return c.Status(fiber.StatusOK).JSON(response.CommonResponse{
|
||||||
|
Status: true,
|
||||||
|
Data: map[string]bool{"exists": exists},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// SearchWikis handles searching for wikis.
|
// SearchWikis handles searching for wikis.
|
||||||
// @Summary Search wikis
|
// @Summary Search wikis
|
||||||
// @Description Search wikis with cursor pagination
|
// @Description Search wikis with cursor pagination
|
||||||
@@ -81,3 +135,4 @@ func (h *WikiController) SearchWikis(c fiber.Ctx) error {
|
|||||||
Data: res,
|
Data: res,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ type EntitySnapshot struct {
|
|||||||
ID string `json:"id" validate:"required,uuidv7"`
|
ID string `json:"id" validate:"required,uuidv7"`
|
||||||
Source string `json:"source,omitempty" validate:"omitempty,oneof=inline ref"`
|
Source string `json:"source,omitempty" validate:"omitempty,oneof=inline ref"`
|
||||||
Operation string `json:"operation,omitempty" validate:"omitempty,oneof=create update delete reference"`
|
Operation string `json:"operation,omitempty" validate:"omitempty,oneof=create update delete reference"`
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name" validate:"required"`
|
||||||
Slug *string `json:"slug,omitempty"`
|
Slug *string `json:"slug" validate:"omitempty,slug"`
|
||||||
Description string `json:"description,omitempty"`
|
Description string `json:"description,omitempty"`
|
||||||
Status *int `json:"status,omitempty" validate:"omitempty,oneof=0 1"`
|
Status *int `json:"status,omitempty" validate:"omitempty,oneof=0 1"`
|
||||||
TimeStart *float64 `json:"time_start,omitempty"`
|
TimeStart *float64 `json:"time_start,omitempty"`
|
||||||
@@ -79,12 +79,13 @@ type GeometryEntitySnapshot struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type WikiSnapshot struct {
|
type WikiSnapshot struct {
|
||||||
ID string `json:"id" validate:"required,uuidv7"`
|
ID string `json:"id" validate:"required,uuidv7"`
|
||||||
Source string `json:"source,omitempty" validate:"omitempty,oneof=inline ref"`
|
Source string `json:"source,omitempty" validate:"omitempty,oneof=inline ref"`
|
||||||
Operation string `json:"operation,omitempty" validate:"omitempty,oneof=create update delete reference"`
|
Operation string `json:"operation,omitempty" validate:"omitempty,oneof=create update delete reference"`
|
||||||
Title string `json:"title" validate:"required"`
|
Title string `json:"title" validate:"required"`
|
||||||
Doc string `json:"doc,omitempty"`
|
Slug *string `json:"slug" validate:"omitempty,slug"`
|
||||||
UpdatedAt string `json:"updated_at,omitempty"`
|
Doc string `json:"doc,omitempty" validate:"omitempty"`
|
||||||
|
UpdatedAt string `json:"updated_at,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type EntityWikiLinkSnapshot struct {
|
type EntityWikiLinkSnapshot struct {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
type WikiResponse struct {
|
type WikiResponse struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Title string `json:"title,omitempty"`
|
Title string `json:"title,omitempty"`
|
||||||
|
Slug string `json:"slug,omitempty"`
|
||||||
Content string `json:"content,omitempty"`
|
Content string `json:"content,omitempty"`
|
||||||
ProjectID string `json:"project_id"`
|
ProjectID string `json:"project_id"`
|
||||||
IsDeleted bool `json:"is_deleted,omitempty"`
|
IsDeleted bool `json:"is_deleted,omitempty"`
|
||||||
|
|||||||
@@ -181,6 +181,31 @@ func (q *Queries) GetEntityById(ctx context.Context, id pgtype.UUID) (Entity, er
|
|||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getEntityBySlug = `-- name: GetEntityBySlug :one
|
||||||
|
SELECT id, project_id, name, slug, description, status, time_start, time_end, is_deleted, created_at, updated_at
|
||||||
|
FROM entities
|
||||||
|
WHERE slug = $1 AND is_deleted = false
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetEntityBySlug(ctx context.Context, slug pgtype.Text) (Entity, error) {
|
||||||
|
row := q.db.QueryRow(ctx, getEntityBySlug, slug)
|
||||||
|
var i Entity
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.ProjectID,
|
||||||
|
&i.Name,
|
||||||
|
&i.Slug,
|
||||||
|
&i.Description,
|
||||||
|
&i.Status,
|
||||||
|
&i.TimeStart,
|
||||||
|
&i.TimeEnd,
|
||||||
|
&i.IsDeleted,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
const searchEntities = `-- name: SearchEntities :many
|
const searchEntities = `-- name: SearchEntities :many
|
||||||
SELECT id, project_id, name, slug, description, status, time_start, time_end, is_deleted, created_at, updated_at
|
SELECT id, project_id, name, slug, description, status, time_start, time_end, is_deleted, created_at, updated_at
|
||||||
FROM entities
|
FROM entities
|
||||||
|
|||||||
@@ -183,6 +183,7 @@ type Wiki struct {
|
|||||||
ID pgtype.UUID `json:"id"`
|
ID pgtype.UUID `json:"id"`
|
||||||
ProjectID pgtype.UUID `json:"project_id"`
|
ProjectID pgtype.UUID `json:"project_id"`
|
||||||
Title pgtype.Text `json:"title"`
|
Title pgtype.Text `json:"title"`
|
||||||
|
Slug pgtype.Text `json:"slug"`
|
||||||
Content pgtype.Text `json:"content"`
|
Content pgtype.Text `json:"content"`
|
||||||
IsDeleted bool `json:"is_deleted"`
|
IsDeleted bool `json:"is_deleted"`
|
||||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
|
|||||||
@@ -68,15 +68,16 @@ func (q *Queries) CreateEntityWikis(ctx context.Context, arg CreateEntityWikisPa
|
|||||||
|
|
||||||
const createWiki = `-- name: CreateWiki :one
|
const createWiki = `-- name: CreateWiki :one
|
||||||
INSERT INTO wikis (
|
INSERT INTO wikis (
|
||||||
id, title, content, project_id
|
id, title, slug, content, project_id
|
||||||
) VALUES (
|
) VALUES (
|
||||||
COALESCE($4::uuid, uuidv7()), $1, $2, $3
|
COALESCE($5::uuid, uuidv7()), $1, $2, $3, $4
|
||||||
)
|
)
|
||||||
RETURNING id, project_id, title, content, is_deleted, created_at, updated_at
|
RETURNING id, project_id, title, slug, content, is_deleted, created_at, updated_at
|
||||||
`
|
`
|
||||||
|
|
||||||
type CreateWikiParams struct {
|
type CreateWikiParams struct {
|
||||||
Title pgtype.Text `json:"title"`
|
Title pgtype.Text `json:"title"`
|
||||||
|
Slug pgtype.Text `json:"slug"`
|
||||||
Content pgtype.Text `json:"content"`
|
Content pgtype.Text `json:"content"`
|
||||||
ProjectID pgtype.UUID `json:"project_id"`
|
ProjectID pgtype.UUID `json:"project_id"`
|
||||||
ID pgtype.UUID `json:"id"`
|
ID pgtype.UUID `json:"id"`
|
||||||
@@ -85,6 +86,7 @@ type CreateWikiParams struct {
|
|||||||
func (q *Queries) CreateWiki(ctx context.Context, arg CreateWikiParams) (Wiki, error) {
|
func (q *Queries) CreateWiki(ctx context.Context, arg CreateWikiParams) (Wiki, error) {
|
||||||
row := q.db.QueryRow(ctx, createWiki,
|
row := q.db.QueryRow(ctx, createWiki,
|
||||||
arg.Title,
|
arg.Title,
|
||||||
|
arg.Slug,
|
||||||
arg.Content,
|
arg.Content,
|
||||||
arg.ProjectID,
|
arg.ProjectID,
|
||||||
arg.ID,
|
arg.ID,
|
||||||
@@ -94,6 +96,7 @@ func (q *Queries) CreateWiki(ctx context.Context, arg CreateWikiParams) (Wiki, e
|
|||||||
&i.ID,
|
&i.ID,
|
||||||
&i.ProjectID,
|
&i.ProjectID,
|
||||||
&i.Title,
|
&i.Title,
|
||||||
|
&i.Slug,
|
||||||
&i.Content,
|
&i.Content,
|
||||||
&i.IsDeleted,
|
&i.IsDeleted,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
@@ -151,7 +154,7 @@ func (q *Queries) DeleteWikisByIDs(ctx context.Context, dollar_1 []pgtype.UUID)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getWikiById = `-- name: GetWikiById :one
|
const getWikiById = `-- name: GetWikiById :one
|
||||||
SELECT id, project_id, title, content, is_deleted, created_at, updated_at
|
SELECT id, project_id, title, slug, content, is_deleted, created_at, updated_at
|
||||||
FROM wikis
|
FROM wikis
|
||||||
WHERE id = $1 AND is_deleted = false
|
WHERE id = $1 AND is_deleted = false
|
||||||
`
|
`
|
||||||
@@ -163,6 +166,29 @@ func (q *Queries) GetWikiById(ctx context.Context, id pgtype.UUID) (Wiki, error)
|
|||||||
&i.ID,
|
&i.ID,
|
||||||
&i.ProjectID,
|
&i.ProjectID,
|
||||||
&i.Title,
|
&i.Title,
|
||||||
|
&i.Slug,
|
||||||
|
&i.Content,
|
||||||
|
&i.IsDeleted,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getWikiBySlug = `-- name: GetWikiBySlug :one
|
||||||
|
SELECT id, project_id, title, slug, content, is_deleted, created_at, updated_at
|
||||||
|
FROM wikis
|
||||||
|
WHERE slug = $1 AND is_deleted = false
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetWikiBySlug(ctx context.Context, slug pgtype.Text) (Wiki, error) {
|
||||||
|
row := q.db.QueryRow(ctx, getWikiBySlug, slug)
|
||||||
|
var i Wiki
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.ProjectID,
|
||||||
|
&i.Title,
|
||||||
|
&i.Slug,
|
||||||
&i.Content,
|
&i.Content,
|
||||||
&i.IsDeleted,
|
&i.IsDeleted,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
@@ -172,7 +198,7 @@ func (q *Queries) GetWikiById(ctx context.Context, id pgtype.UUID) (Wiki, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getWikisByIDs = `-- name: GetWikisByIDs :many
|
const getWikisByIDs = `-- name: GetWikisByIDs :many
|
||||||
SELECT id, project_id, title, content, is_deleted, created_at, updated_at FROM wikis WHERE id = ANY($1::uuid[]) AND is_deleted = false
|
SELECT id, project_id, title, slug, content, is_deleted, created_at, updated_at FROM wikis WHERE id = ANY($1::uuid[]) AND is_deleted = false
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetWikisByIDs(ctx context.Context, dollar_1 []pgtype.UUID) ([]Wiki, error) {
|
func (q *Queries) GetWikisByIDs(ctx context.Context, dollar_1 []pgtype.UUID) ([]Wiki, error) {
|
||||||
@@ -188,6 +214,7 @@ func (q *Queries) GetWikisByIDs(ctx context.Context, dollar_1 []pgtype.UUID) ([]
|
|||||||
&i.ID,
|
&i.ID,
|
||||||
&i.ProjectID,
|
&i.ProjectID,
|
||||||
&i.Title,
|
&i.Title,
|
||||||
|
&i.Slug,
|
||||||
&i.Content,
|
&i.Content,
|
||||||
&i.IsDeleted,
|
&i.IsDeleted,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
@@ -204,7 +231,7 @@ func (q *Queries) GetWikisByIDs(ctx context.Context, dollar_1 []pgtype.UUID) ([]
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getWikisByProjectId = `-- name: GetWikisByProjectId :many
|
const getWikisByProjectId = `-- name: GetWikisByProjectId :many
|
||||||
SELECT id, project_id, title, content, is_deleted, created_at, updated_at
|
SELECT id, project_id, title, slug, content, is_deleted, created_at, updated_at
|
||||||
FROM wikis
|
FROM wikis
|
||||||
WHERE project_id = $1 AND is_deleted = false
|
WHERE project_id = $1 AND is_deleted = false
|
||||||
`
|
`
|
||||||
@@ -222,6 +249,7 @@ func (q *Queries) GetWikisByProjectId(ctx context.Context, projectID pgtype.UUID
|
|||||||
&i.ID,
|
&i.ID,
|
||||||
&i.ProjectID,
|
&i.ProjectID,
|
||||||
&i.Title,
|
&i.Title,
|
||||||
|
&i.Slug,
|
||||||
&i.Content,
|
&i.Content,
|
||||||
&i.IsDeleted,
|
&i.IsDeleted,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
@@ -238,7 +266,7 @@ func (q *Queries) GetWikisByProjectId(ctx context.Context, projectID pgtype.UUID
|
|||||||
}
|
}
|
||||||
|
|
||||||
const searchWikis = `-- name: SearchWikis :many
|
const searchWikis = `-- name: SearchWikis :many
|
||||||
SELECT w.id, w.project_id, w.title, w.content, w.is_deleted, w.created_at, w.updated_at
|
SELECT w.id, w.project_id, w.title, w.slug, w.content, w.is_deleted, w.created_at, w.updated_at
|
||||||
FROM wikis w
|
FROM wikis w
|
||||||
WHERE w.is_deleted = false
|
WHERE w.is_deleted = false
|
||||||
AND ($1::uuid IS NULL OR w.project_id = $1::uuid)
|
AND ($1::uuid IS NULL OR w.project_id = $1::uuid)
|
||||||
@@ -285,6 +313,7 @@ func (q *Queries) SearchWikis(ctx context.Context, arg SearchWikisParams) ([]Wik
|
|||||||
&i.ID,
|
&i.ID,
|
||||||
&i.ProjectID,
|
&i.ProjectID,
|
||||||
&i.Title,
|
&i.Title,
|
||||||
|
&i.Slug,
|
||||||
&i.Content,
|
&i.Content,
|
||||||
&i.IsDeleted,
|
&i.IsDeleted,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
@@ -304,14 +333,16 @@ const updateWiki = `-- name: UpdateWiki :one
|
|||||||
UPDATE wikis
|
UPDATE wikis
|
||||||
SET
|
SET
|
||||||
title = COALESCE($1, title),
|
title = COALESCE($1, title),
|
||||||
content = COALESCE($2, content),
|
slug = COALESCE($2, slug),
|
||||||
project_id = COALESCE($3, project_id)
|
content = COALESCE($3, content),
|
||||||
WHERE id = $4 AND is_deleted = false
|
project_id = COALESCE($4, project_id)
|
||||||
RETURNING id, project_id, title, content, is_deleted, created_at, updated_at
|
WHERE id = $5 AND is_deleted = false
|
||||||
|
RETURNING id, project_id, title, slug, content, is_deleted, created_at, updated_at
|
||||||
`
|
`
|
||||||
|
|
||||||
type UpdateWikiParams struct {
|
type UpdateWikiParams struct {
|
||||||
Title pgtype.Text `json:"title"`
|
Title pgtype.Text `json:"title"`
|
||||||
|
Slug pgtype.Text `json:"slug"`
|
||||||
Content pgtype.Text `json:"content"`
|
Content pgtype.Text `json:"content"`
|
||||||
ProjectID pgtype.UUID `json:"project_id"`
|
ProjectID pgtype.UUID `json:"project_id"`
|
||||||
ID pgtype.UUID `json:"id"`
|
ID pgtype.UUID `json:"id"`
|
||||||
@@ -320,6 +351,7 @@ type UpdateWikiParams struct {
|
|||||||
func (q *Queries) UpdateWiki(ctx context.Context, arg UpdateWikiParams) (Wiki, error) {
|
func (q *Queries) UpdateWiki(ctx context.Context, arg UpdateWikiParams) (Wiki, error) {
|
||||||
row := q.db.QueryRow(ctx, updateWiki,
|
row := q.db.QueryRow(ctx, updateWiki,
|
||||||
arg.Title,
|
arg.Title,
|
||||||
|
arg.Slug,
|
||||||
arg.Content,
|
arg.Content,
|
||||||
arg.ProjectID,
|
arg.ProjectID,
|
||||||
arg.ID,
|
arg.ID,
|
||||||
@@ -329,6 +361,7 @@ func (q *Queries) UpdateWiki(ctx context.Context, arg UpdateWikiParams) (Wiki, e
|
|||||||
&i.ID,
|
&i.ID,
|
||||||
&i.ProjectID,
|
&i.ProjectID,
|
||||||
&i.Title,
|
&i.Title,
|
||||||
|
&i.Slug,
|
||||||
&i.Content,
|
&i.Content,
|
||||||
&i.IsDeleted,
|
&i.IsDeleted,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
type WikiEntity struct {
|
type WikiEntity struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
|
Slug string `json:"slug"`
|
||||||
Content string `json:"content"`
|
Content string `json:"content"`
|
||||||
ProjectID string `json:"project_id"`
|
ProjectID string `json:"project_id"`
|
||||||
IsDeleted bool `json:"is_deleted"`
|
IsDeleted bool `json:"is_deleted"`
|
||||||
@@ -22,6 +23,7 @@ func (w *WikiEntity) ToResponse() *response.WikiResponse {
|
|||||||
return &response.WikiResponse{
|
return &response.WikiResponse{
|
||||||
ID: w.ID,
|
ID: w.ID,
|
||||||
Title: w.Title,
|
Title: w.Title,
|
||||||
|
Slug: w.Slug,
|
||||||
Content: w.Content,
|
Content: w.Content,
|
||||||
ProjectID: w.ProjectID,
|
ProjectID: w.ProjectID,
|
||||||
IsDeleted: w.IsDeleted,
|
IsDeleted: w.IsDeleted,
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
type EntityRepository interface {
|
type EntityRepository interface {
|
||||||
GetByID(ctx context.Context, id pgtype.UUID) (*models.EntityEntity, error)
|
GetByID(ctx context.Context, id pgtype.UUID) (*models.EntityEntity, error)
|
||||||
GetByIDs(ctx context.Context, ids []string) ([]*models.EntityEntity, error)
|
GetByIDs(ctx context.Context, ids []string) ([]*models.EntityEntity, error)
|
||||||
|
GetBySlug(ctx context.Context, slug string) (*models.EntityEntity, error)
|
||||||
Search(ctx context.Context, params sqlc.SearchEntitiesParams) ([]*models.EntityEntity, error)
|
Search(ctx context.Context, params sqlc.SearchEntitiesParams) ([]*models.EntityEntity, error)
|
||||||
Create(ctx context.Context, params sqlc.CreateEntityParams) (*models.EntityEntity, error)
|
Create(ctx context.Context, params sqlc.CreateEntityParams) (*models.EntityEntity, error)
|
||||||
Update(ctx context.Context, params sqlc.UpdateEntityParams) (*models.EntityEntity, error)
|
Update(ctx context.Context, params sqlc.UpdateEntityParams) (*models.EntityEntity, error)
|
||||||
@@ -83,17 +84,17 @@ func (r *entityRepository) getByIDsWithFallback(ctx context.Context, ids []strin
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
for _, row := range dbRows {
|
for _, row := range dbRows {
|
||||||
item := models.EntityEntity{
|
item := models.EntityEntity{
|
||||||
ID: convert.UUIDToString(row.ID),
|
ID: convert.UUIDToString(row.ID),
|
||||||
Name: row.Name,
|
Name: row.Name,
|
||||||
Slug: convert.TextToString(row.Slug),
|
Slug: convert.TextToString(row.Slug),
|
||||||
Description: convert.TextToString(row.Description),
|
Description: convert.TextToString(row.Description),
|
||||||
ProjectID: convert.UUIDToString(row.ProjectID),
|
ProjectID: convert.UUIDToString(row.ProjectID),
|
||||||
Status: convert.Int2ToInt16Ptr(row.Status),
|
Status: convert.Int2ToInt16Ptr(row.Status),
|
||||||
TimeStart: convert.Int4ToPtr(row.TimeStart),
|
TimeStart: convert.Int4ToPtr(row.TimeStart),
|
||||||
TimeEnd: convert.Int4ToPtr(row.TimeEnd),
|
TimeEnd: convert.Int4ToPtr(row.TimeEnd),
|
||||||
IsDeleted: row.IsDeleted,
|
IsDeleted: row.IsDeleted,
|
||||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||||
}
|
}
|
||||||
dbMap[item.ID] = &item
|
dbMap[item.ID] = &item
|
||||||
}
|
}
|
||||||
@@ -140,17 +141,17 @@ func (r *entityRepository) GetByID(ctx context.Context, id pgtype.UUID) (*models
|
|||||||
}
|
}
|
||||||
|
|
||||||
entity = models.EntityEntity{
|
entity = models.EntityEntity{
|
||||||
ID: convert.UUIDToString(row.ID),
|
ID: convert.UUIDToString(row.ID),
|
||||||
Name: row.Name,
|
Name: row.Name,
|
||||||
Slug: convert.TextToString(row.Slug),
|
Slug: convert.TextToString(row.Slug),
|
||||||
Description: convert.TextToString(row.Description),
|
Description: convert.TextToString(row.Description),
|
||||||
ProjectID: convert.UUIDToString(row.ProjectID),
|
ProjectID: convert.UUIDToString(row.ProjectID),
|
||||||
Status: convert.Int2ToInt16Ptr(row.Status),
|
Status: convert.Int2ToInt16Ptr(row.Status),
|
||||||
TimeStart: convert.Int4ToPtr(row.TimeStart),
|
TimeStart: convert.Int4ToPtr(row.TimeStart),
|
||||||
TimeEnd: convert.Int4ToPtr(row.TimeEnd),
|
TimeEnd: convert.Int4ToPtr(row.TimeEnd),
|
||||||
IsDeleted: row.IsDeleted,
|
IsDeleted: row.IsDeleted,
|
||||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||||
}
|
}
|
||||||
_ = r.c.Set(ctx, cacheId, entity, constants.NormalCacheDuration)
|
_ = r.c.Set(ctx, cacheId, entity, constants.NormalCacheDuration)
|
||||||
|
|
||||||
@@ -174,17 +175,17 @@ func (r *entityRepository) Search(ctx context.Context, params sqlc.SearchEntitie
|
|||||||
|
|
||||||
for _, row := range rows {
|
for _, row := range rows {
|
||||||
entity := &models.EntityEntity{
|
entity := &models.EntityEntity{
|
||||||
ID: convert.UUIDToString(row.ID),
|
ID: convert.UUIDToString(row.ID),
|
||||||
Name: row.Name,
|
Name: row.Name,
|
||||||
Slug: convert.TextToString(row.Slug),
|
Slug: convert.TextToString(row.Slug),
|
||||||
Description: convert.TextToString(row.Description),
|
Description: convert.TextToString(row.Description),
|
||||||
ProjectID: convert.UUIDToString(row.ProjectID),
|
ProjectID: convert.UUIDToString(row.ProjectID),
|
||||||
Status: convert.Int2ToInt16Ptr(row.Status),
|
Status: convert.Int2ToInt16Ptr(row.Status),
|
||||||
TimeStart: convert.Int4ToPtr(row.TimeStart),
|
TimeStart: convert.Int4ToPtr(row.TimeStart),
|
||||||
TimeEnd: convert.Int4ToPtr(row.TimeEnd),
|
TimeEnd: convert.Int4ToPtr(row.TimeEnd),
|
||||||
IsDeleted: row.IsDeleted,
|
IsDeleted: row.IsDeleted,
|
||||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||||
}
|
}
|
||||||
ids = append(ids, entity.ID)
|
ids = append(ids, entity.ID)
|
||||||
entities = append(entities, entity)
|
entities = append(entities, entity)
|
||||||
@@ -209,17 +210,17 @@ func (r *entityRepository) Create(ctx context.Context, params sqlc.CreateEntityP
|
|||||||
}
|
}
|
||||||
|
|
||||||
entity := models.EntityEntity{
|
entity := models.EntityEntity{
|
||||||
ID: convert.UUIDToString(row.ID),
|
ID: convert.UUIDToString(row.ID),
|
||||||
Name: row.Name,
|
Name: row.Name,
|
||||||
Slug: convert.TextToString(row.Slug),
|
Slug: convert.TextToString(row.Slug),
|
||||||
Description: convert.TextToString(row.Description),
|
Description: convert.TextToString(row.Description),
|
||||||
ProjectID: convert.UUIDToString(row.ProjectID),
|
ProjectID: convert.UUIDToString(row.ProjectID),
|
||||||
Status: convert.Int2ToInt16Ptr(row.Status),
|
Status: convert.Int2ToInt16Ptr(row.Status),
|
||||||
TimeStart: convert.Int4ToPtr(row.TimeStart),
|
TimeStart: convert.Int4ToPtr(row.TimeStart),
|
||||||
TimeEnd: convert.Int4ToPtr(row.TimeEnd),
|
TimeEnd: convert.Int4ToPtr(row.TimeEnd),
|
||||||
IsDeleted: row.IsDeleted,
|
IsDeleted: row.IsDeleted,
|
||||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||||
}
|
}
|
||||||
|
|
||||||
return &entity, nil
|
return &entity, nil
|
||||||
@@ -231,19 +232,20 @@ func (r *entityRepository) Update(ctx context.Context, params sqlc.UpdateEntityP
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
entity := models.EntityEntity{
|
entity := models.EntityEntity{
|
||||||
ID: convert.UUIDToString(row.ID),
|
ID: convert.UUIDToString(row.ID),
|
||||||
Name: row.Name,
|
Name: row.Name,
|
||||||
Slug: convert.TextToString(row.Slug),
|
Slug: convert.TextToString(row.Slug),
|
||||||
Description: convert.TextToString(row.Description),
|
Description: convert.TextToString(row.Description),
|
||||||
ProjectID: convert.UUIDToString(row.ProjectID),
|
ProjectID: convert.UUIDToString(row.ProjectID),
|
||||||
Status: convert.Int2ToInt16Ptr(row.Status),
|
Status: convert.Int2ToInt16Ptr(row.Status),
|
||||||
TimeStart: convert.Int4ToPtr(row.TimeStart),
|
TimeStart: convert.Int4ToPtr(row.TimeStart),
|
||||||
TimeEnd: convert.Int4ToPtr(row.TimeEnd),
|
TimeEnd: convert.Int4ToPtr(row.TimeEnd),
|
||||||
IsDeleted: row.IsDeleted,
|
IsDeleted: row.IsDeleted,
|
||||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||||
}
|
}
|
||||||
_ = r.c.Del(ctx, fmt.Sprintf("entity:id:%s", entity.ID))
|
_ = r.c.Del(ctx, fmt.Sprintf("entity:id:%s", entity.ID))
|
||||||
|
_ = r.c.Del(ctx, fmt.Sprintf("entity:slug:%s", entity.Slug))
|
||||||
return &entity, nil
|
return &entity, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,17 +276,17 @@ func (r *entityRepository) GetByProjectID(ctx context.Context, projectID pgtype.
|
|||||||
|
|
||||||
for _, row := range rows {
|
for _, row := range rows {
|
||||||
entity := &models.EntityEntity{
|
entity := &models.EntityEntity{
|
||||||
ID: convert.UUIDToString(row.ID),
|
ID: convert.UUIDToString(row.ID),
|
||||||
Name: row.Name,
|
Name: row.Name,
|
||||||
Slug: convert.TextToString(row.Slug),
|
Slug: convert.TextToString(row.Slug),
|
||||||
Description: convert.TextToString(row.Description),
|
Description: convert.TextToString(row.Description),
|
||||||
ProjectID: convert.UUIDToString(row.ProjectID),
|
ProjectID: convert.UUIDToString(row.ProjectID),
|
||||||
Status: convert.Int2ToInt16Ptr(row.Status),
|
Status: convert.Int2ToInt16Ptr(row.Status),
|
||||||
TimeStart: convert.Int4ToPtr(row.TimeStart),
|
TimeStart: convert.Int4ToPtr(row.TimeStart),
|
||||||
TimeEnd: convert.Int4ToPtr(row.TimeEnd),
|
TimeEnd: convert.Int4ToPtr(row.TimeEnd),
|
||||||
IsDeleted: row.IsDeleted,
|
IsDeleted: row.IsDeleted,
|
||||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||||
}
|
}
|
||||||
ids = append(ids, entity.ID)
|
ids = append(ids, entity.ID)
|
||||||
entities = append(entities, entity)
|
entities = append(entities, entity)
|
||||||
@@ -315,3 +317,35 @@ func (r *entityRepository) DeleteByIDs(ctx context.Context, ids []pgtype.UUID) e
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *entityRepository) GetBySlug(ctx context.Context, slug string) (*models.EntityEntity, error) {
|
||||||
|
cacheKey := fmt.Sprintf("entity:slug:%s", slug)
|
||||||
|
var entity models.EntityEntity
|
||||||
|
err := r.c.Get(ctx, cacheKey, &entity)
|
||||||
|
if err == nil {
|
||||||
|
_ = r.c.Set(ctx, cacheKey, entity, constants.NormalCacheDuration)
|
||||||
|
return &entity, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
row, err := r.q.GetEntityBySlug(ctx, convert.StringToText(slug))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
entity = models.EntityEntity{
|
||||||
|
ID: convert.UUIDToString(row.ID),
|
||||||
|
Name: row.Name,
|
||||||
|
Slug: convert.TextToString(row.Slug),
|
||||||
|
Description: convert.TextToString(row.Description),
|
||||||
|
ProjectID: convert.UUIDToString(row.ProjectID),
|
||||||
|
Status: convert.Int2ToInt16Ptr(row.Status),
|
||||||
|
TimeStart: convert.Int4ToPtr(row.TimeStart),
|
||||||
|
TimeEnd: convert.Int4ToPtr(row.TimeEnd),
|
||||||
|
IsDeleted: row.IsDeleted,
|
||||||
|
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||||
|
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||||
|
}
|
||||||
|
_ = r.c.Set(ctx, cacheKey, entity, constants.NormalCacheDuration)
|
||||||
|
|
||||||
|
return &entity, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
type WikiRepository interface {
|
type WikiRepository interface {
|
||||||
GetByID(ctx context.Context, id pgtype.UUID) (*models.WikiEntity, error)
|
GetByID(ctx context.Context, id pgtype.UUID) (*models.WikiEntity, error)
|
||||||
GetByIDs(ctx context.Context, ids []string) ([]*models.WikiEntity, error)
|
GetByIDs(ctx context.Context, ids []string) ([]*models.WikiEntity, error)
|
||||||
|
GetBySlug(ctx context.Context, slug string) (*models.WikiEntity, error)
|
||||||
Search(ctx context.Context, params sqlc.SearchWikisParams) ([]*models.WikiEntity, error)
|
Search(ctx context.Context, params sqlc.SearchWikisParams) ([]*models.WikiEntity, error)
|
||||||
Create(ctx context.Context, params sqlc.CreateWikiParams) (*models.WikiEntity, error)
|
Create(ctx context.Context, params sqlc.CreateWikiParams) (*models.WikiEntity, error)
|
||||||
Update(ctx context.Context, params sqlc.UpdateWikiParams) (*models.WikiEntity, error)
|
Update(ctx context.Context, params sqlc.UpdateWikiParams) (*models.WikiEntity, error)
|
||||||
@@ -90,6 +91,7 @@ func (r *wikiRepository) getByIDsWithFallback(ctx context.Context, ids []string)
|
|||||||
item := models.WikiEntity{
|
item := models.WikiEntity{
|
||||||
ID: convert.UUIDToString(row.ID),
|
ID: convert.UUIDToString(row.ID),
|
||||||
Title: convert.TextToString(row.Title),
|
Title: convert.TextToString(row.Title),
|
||||||
|
Slug: convert.TextToString(row.Slug),
|
||||||
Content: convert.TextToString(row.Content),
|
Content: convert.TextToString(row.Content),
|
||||||
IsDeleted: row.IsDeleted,
|
IsDeleted: row.IsDeleted,
|
||||||
ProjectID: convert.UUIDToString(row.ProjectID),
|
ProjectID: convert.UUIDToString(row.ProjectID),
|
||||||
@@ -143,8 +145,10 @@ func (r *wikiRepository) GetByID(ctx context.Context, id pgtype.UUID) (*models.W
|
|||||||
wiki = models.WikiEntity{
|
wiki = models.WikiEntity{
|
||||||
ID: convert.UUIDToString(row.ID),
|
ID: convert.UUIDToString(row.ID),
|
||||||
Title: convert.TextToString(row.Title),
|
Title: convert.TextToString(row.Title),
|
||||||
|
Slug: convert.TextToString(row.Slug),
|
||||||
Content: convert.TextToString(row.Content),
|
Content: convert.TextToString(row.Content),
|
||||||
IsDeleted: row.IsDeleted,
|
IsDeleted: row.IsDeleted,
|
||||||
|
ProjectID: convert.UUIDToString(row.ProjectID),
|
||||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||||
}
|
}
|
||||||
@@ -172,8 +176,10 @@ func (r *wikiRepository) Search(ctx context.Context, params sqlc.SearchWikisPara
|
|||||||
wiki := &models.WikiEntity{
|
wiki := &models.WikiEntity{
|
||||||
ID: convert.UUIDToString(row.ID),
|
ID: convert.UUIDToString(row.ID),
|
||||||
Title: convert.TextToString(row.Title),
|
Title: convert.TextToString(row.Title),
|
||||||
|
Slug: convert.TextToString(row.Slug),
|
||||||
Content: convert.TextToString(row.Content),
|
Content: convert.TextToString(row.Content),
|
||||||
IsDeleted: row.IsDeleted,
|
IsDeleted: row.IsDeleted,
|
||||||
|
ProjectID: convert.UUIDToString(row.ProjectID),
|
||||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||||
}
|
}
|
||||||
@@ -201,8 +207,10 @@ func (r *wikiRepository) Create(ctx context.Context, params sqlc.CreateWikiParam
|
|||||||
wiki := models.WikiEntity{
|
wiki := models.WikiEntity{
|
||||||
ID: convert.UUIDToString(row.ID),
|
ID: convert.UUIDToString(row.ID),
|
||||||
Title: convert.TextToString(row.Title),
|
Title: convert.TextToString(row.Title),
|
||||||
|
Slug: convert.TextToString(row.Slug),
|
||||||
Content: convert.TextToString(row.Content),
|
Content: convert.TextToString(row.Content),
|
||||||
IsDeleted: row.IsDeleted,
|
IsDeleted: row.IsDeleted,
|
||||||
|
ProjectID: convert.UUIDToString(row.ProjectID),
|
||||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||||
}
|
}
|
||||||
@@ -218,12 +226,15 @@ func (r *wikiRepository) Update(ctx context.Context, params sqlc.UpdateWikiParam
|
|||||||
wiki := models.WikiEntity{
|
wiki := models.WikiEntity{
|
||||||
ID: convert.UUIDToString(row.ID),
|
ID: convert.UUIDToString(row.ID),
|
||||||
Title: convert.TextToString(row.Title),
|
Title: convert.TextToString(row.Title),
|
||||||
|
Slug: convert.TextToString(row.Slug),
|
||||||
Content: convert.TextToString(row.Content),
|
Content: convert.TextToString(row.Content),
|
||||||
IsDeleted: row.IsDeleted,
|
IsDeleted: row.IsDeleted,
|
||||||
|
ProjectID: convert.UUIDToString(row.ProjectID),
|
||||||
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||||
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||||
}
|
}
|
||||||
_ = r.c.Del(ctx, fmt.Sprintf("wiki:id:%s", wiki.ID))
|
_ = r.c.Del(ctx, fmt.Sprintf("wiki:id:%s", wiki.ID))
|
||||||
|
_ = r.c.Del(ctx, fmt.Sprintf("wiki:slug:%s", wiki.Slug))
|
||||||
return &wiki, nil
|
return &wiki, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,6 +283,7 @@ func (r *wikiRepository) GetByProjectID(ctx context.Context, projectID pgtype.UU
|
|||||||
wiki := &models.WikiEntity{
|
wiki := &models.WikiEntity{
|
||||||
ID: convert.UUIDToString(row.ID),
|
ID: convert.UUIDToString(row.ID),
|
||||||
Title: convert.TextToString(row.Title),
|
Title: convert.TextToString(row.Title),
|
||||||
|
Slug: convert.TextToString(row.Slug),
|
||||||
Content: convert.TextToString(row.Content),
|
Content: convert.TextToString(row.Content),
|
||||||
IsDeleted: row.IsDeleted,
|
IsDeleted: row.IsDeleted,
|
||||||
ProjectID: convert.UUIDToString(row.ProjectID),
|
ProjectID: convert.UUIDToString(row.ProjectID),
|
||||||
@@ -318,3 +330,32 @@ func (r *wikiRepository) DeleteEntityWiki(ctx context.Context, entityID pgtype.U
|
|||||||
WikiID: wikiID,
|
WikiID: wikiID,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *wikiRepository) GetBySlug(ctx context.Context, slug string) (*models.WikiEntity, error) {
|
||||||
|
cacheKey := fmt.Sprintf("wiki:slug:%s", slug)
|
||||||
|
var wiki models.WikiEntity
|
||||||
|
err := r.c.Get(ctx, cacheKey, &wiki)
|
||||||
|
if err == nil {
|
||||||
|
_ = r.c.Set(ctx, cacheKey, wiki, constants.NormalCacheDuration)
|
||||||
|
return &wiki, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
row, err := r.q.GetWikiBySlug(ctx, convert.StringToText(slug))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
wiki = models.WikiEntity{
|
||||||
|
ID: convert.UUIDToString(row.ID),
|
||||||
|
Title: convert.TextToString(row.Title),
|
||||||
|
Slug: convert.TextToString(row.Slug),
|
||||||
|
Content: convert.TextToString(row.Content),
|
||||||
|
IsDeleted: row.IsDeleted,
|
||||||
|
ProjectID: convert.UUIDToString(row.ProjectID),
|
||||||
|
CreatedAt: convert.TimeToPtr(row.CreatedAt),
|
||||||
|
UpdatedAt: convert.TimeToPtr(row.UpdatedAt),
|
||||||
|
}
|
||||||
|
_ = r.c.Set(ctx, cacheKey, wiki, constants.NormalCacheDuration)
|
||||||
|
|
||||||
|
return &wiki, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,5 +9,8 @@ import (
|
|||||||
func EntityRoutes(router fiber.Router, entityController *controllers.EntityController) {
|
func EntityRoutes(router fiber.Router, entityController *controllers.EntityController) {
|
||||||
entity := router.Group("/entities")
|
entity := router.Group("/entities")
|
||||||
entity.Get("/", entityController.SearchEntities)
|
entity.Get("/", entityController.SearchEntities)
|
||||||
|
entity.Get("/slug/exists", entityController.IsExistEntitySlug)
|
||||||
|
entity.Get("/slug/:slug", entityController.GetEntityBySlug)
|
||||||
entity.Get("/:id", entityController.GetEntityById)
|
entity.Get("/:id", entityController.GetEntityById)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,5 +9,8 @@ import (
|
|||||||
func WikiRoutes(router fiber.Router, wikiController *controllers.WikiController) {
|
func WikiRoutes(router fiber.Router, wikiController *controllers.WikiController) {
|
||||||
wiki := router.Group("/wikis")
|
wiki := router.Group("/wikis")
|
||||||
wiki.Get("/", wikiController.SearchWikis)
|
wiki.Get("/", wikiController.SearchWikis)
|
||||||
|
wiki.Get("/slug/exists", wikiController.IsExistWikiSlug)
|
||||||
|
wiki.Get("/slug/:slug", wikiController.GetWikiBySlug)
|
||||||
wiki.Get("/:id", wikiController.GetWikiById)
|
wiki.Get("/:id", wikiController.GetWikiById)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package services
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
"history-api/internal/dtos/request"
|
"history-api/internal/dtos/request"
|
||||||
"history-api/internal/dtos/response"
|
"history-api/internal/dtos/response"
|
||||||
"history-api/internal/gen/sqlc"
|
"history-api/internal/gen/sqlc"
|
||||||
@@ -14,6 +16,8 @@ import (
|
|||||||
|
|
||||||
type EntityService interface {
|
type EntityService interface {
|
||||||
GetEntityByID(ctx context.Context, id string) (*response.EntityResponse, *fiber.Error)
|
GetEntityByID(ctx context.Context, id string) (*response.EntityResponse, *fiber.Error)
|
||||||
|
GetEntityBySlug(ctx context.Context, slug string) (*response.EntityResponse, *fiber.Error)
|
||||||
|
IsExistEntitySlug(ctx context.Context, slug string) (bool, *fiber.Error)
|
||||||
SearchEntities(ctx context.Context, req *request.SearchEntityDto) ([]*response.EntityResponse, *fiber.Error)
|
SearchEntities(ctx context.Context, req *request.SearchEntityDto) ([]*response.EntityResponse, *fiber.Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,6 +44,29 @@ func (s *entityService) GetEntityByID(ctx context.Context, id string) (*response
|
|||||||
return entity.ToResponse(), nil
|
return entity.ToResponse(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *entityService) GetEntityBySlug(ctx context.Context, slug string) (*response.EntityResponse, *fiber.Error) {
|
||||||
|
if slug == "" {
|
||||||
|
return nil, fiber.NewError(fiber.StatusBadRequest, "Slug is required")
|
||||||
|
}
|
||||||
|
entity, err := s.entityRepo.GetBySlug(ctx, slug)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fiber.NewError(fiber.StatusNotFound, "Entity not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return entity.ToResponse(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *entityService) IsExistEntitySlug(ctx context.Context, slug string) (bool, *fiber.Error) {
|
||||||
|
if slug == "" {
|
||||||
|
return false, fiber.NewError(fiber.StatusBadRequest, "Slug is required")
|
||||||
|
}
|
||||||
|
entity, err := s.entityRepo.GetBySlug(ctx, slug)
|
||||||
|
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return false, fiber.NewError(fiber.StatusInternalServerError, "Failed to check slug existence")
|
||||||
|
}
|
||||||
|
return entity != nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *entityService) SearchEntities(ctx context.Context, req *request.SearchEntityDto) ([]*response.EntityResponse, *fiber.Error) {
|
func (s *entityService) SearchEntities(ctx context.Context, req *request.SearchEntityDto) ([]*response.EntityResponse, *fiber.Error) {
|
||||||
limit := int32(25)
|
limit := int32(25)
|
||||||
if req.Limit > 0 {
|
if req.Limit > 0 {
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ package services
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"history-api/internal/dtos/request"
|
"history-api/internal/dtos/request"
|
||||||
"history-api/internal/dtos/response"
|
"history-api/internal/dtos/response"
|
||||||
@@ -95,6 +97,35 @@ func (s *submissionService) CreateSubmission(ctx context.Context, userID string,
|
|||||||
return nil, fiber.NewError(fiber.StatusBadRequest, "Commit does not belong to project")
|
return nil, fiber.NewError(fiber.StatusBadRequest, "Commit does not belong to project")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var snapshotData request.CommitSnapshot
|
||||||
|
if err := json.Unmarshal(commit.SnapshotJson, &snapshotData); err != nil {
|
||||||
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to parse commit snapshot")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, entity := range snapshotData.Entities {
|
||||||
|
if entity.Slug != nil {
|
||||||
|
exist, err := s.entityRepo.GetBySlug(ctx, *entity.Slug)
|
||||||
|
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to get entity")
|
||||||
|
}
|
||||||
|
if exist != nil {
|
||||||
|
return nil, fiber.NewError(fiber.StatusConflict, fmt.Sprintf("Entity %s already exists", *entity.Slug))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, wiki := range snapshotData.Wikis {
|
||||||
|
if wiki.Slug != nil {
|
||||||
|
exist, err := s.wikiRepo.GetBySlug(ctx, *wiki.Slug)
|
||||||
|
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to get wiki")
|
||||||
|
}
|
||||||
|
if exist != nil {
|
||||||
|
return nil, fiber.NewError(fiber.StatusConflict, fmt.Sprintf("Wiki %s already exists", *wiki.Slug))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
project, err := s.projectRepo.GetByID(ctx, projectUUID)
|
project, err := s.projectRepo.GetByID(ctx, projectUUID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fiber.NewError(fiber.StatusNotFound, "Project not found")
|
return nil, fiber.NewError(fiber.StatusNotFound, "Project not found")
|
||||||
@@ -178,12 +209,12 @@ func (s *submissionService) UpdateSubmissionStatus(ctx context.Context, reviewer
|
|||||||
listDeleteWikis := make([]pgtype.UUID, 0)
|
listDeleteWikis := make([]pgtype.UUID, 0)
|
||||||
listDeleteGeometries := make([]pgtype.UUID, 0)
|
listDeleteGeometries := make([]pgtype.UUID, 0)
|
||||||
var snapshotData request.CommitSnapshot
|
var snapshotData request.CommitSnapshot
|
||||||
if status == constants.StatusTypeApproved {
|
err = json.Unmarshal(commit.SnapshotJson, &snapshotData)
|
||||||
err = json.Unmarshal(commit.SnapshotJson, &snapshotData)
|
if err != nil {
|
||||||
if err != nil {
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to parse commit snapshot")
|
||||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to parse commit snapshot")
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
if status == constants.StatusTypeApproved {
|
||||||
projectUUID, err := convert.StringToUUID(commit.ProjectID)
|
projectUUID, err := convert.StringToUUID(commit.ProjectID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid project ID")
|
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid project ID")
|
||||||
@@ -312,7 +343,7 @@ func (s *submissionService) UpdateSubmissionStatus(ctx context.Context, reviewer
|
|||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to update entity: "+entity.ID)
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to update entity: "+err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
newEntities = append(newEntities, snapshotData.Entities[i])
|
newEntities = append(newEntities, snapshotData.Entities[i])
|
||||||
@@ -330,7 +361,7 @@ func (s *submissionService) UpdateSubmissionStatus(ctx context.Context, reviewer
|
|||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to create entity: "+entity.ID)
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to create entity: "+err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
newEntities = append(newEntities, snapshotData.Entities[i])
|
newEntities = append(newEntities, snapshotData.Entities[i])
|
||||||
@@ -390,7 +421,7 @@ func (s *submissionService) UpdateSubmissionStatus(ctx context.Context, reviewer
|
|||||||
|
|
||||||
_, err := geometryRepo.Update(ctx, params)
|
_, err := geometryRepo.Update(ctx, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to update geometry: "+geo.ID)
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to update geometry: "+err.Error())
|
||||||
}
|
}
|
||||||
newGeometries = append(newGeometries, snapshotData.Geometries[i])
|
newGeometries = append(newGeometries, snapshotData.Geometries[i])
|
||||||
|
|
||||||
@@ -413,7 +444,7 @@ func (s *submissionService) UpdateSubmissionStatus(ctx context.Context, reviewer
|
|||||||
|
|
||||||
_, err := geometryRepo.Create(ctx, params)
|
_, err := geometryRepo.Create(ctx, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to create geometry: "+geo.ID)
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to create geometry: "+err.Error())
|
||||||
}
|
}
|
||||||
newGeometries = append(newGeometries, snapshotData.Geometries[i])
|
newGeometries = append(newGeometries, snapshotData.Geometries[i])
|
||||||
|
|
||||||
@@ -453,11 +484,12 @@ func (s *submissionService) UpdateSubmissionStatus(ctx context.Context, reviewer
|
|||||||
_, err := wikiRepo.Update(ctx, sqlc.UpdateWikiParams{
|
_, err := wikiRepo.Update(ctx, sqlc.UpdateWikiParams{
|
||||||
ID: wikiUUID,
|
ID: wikiUUID,
|
||||||
Title: convert.StringToText(wiki.Title),
|
Title: convert.StringToText(wiki.Title),
|
||||||
|
Slug: convert.PtrToText(wiki.Slug),
|
||||||
Content: convert.StringToText(wiki.Doc),
|
Content: convert.StringToText(wiki.Doc),
|
||||||
ProjectID: projectUUID,
|
ProjectID: projectUUID,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to update wiki: "+wiki.ID)
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to update wiki: "+err.Error())
|
||||||
}
|
}
|
||||||
newWikis = append(newWikis, snapshotData.Wikis[i])
|
newWikis = append(newWikis, snapshotData.Wikis[i])
|
||||||
|
|
||||||
@@ -465,11 +497,12 @@ func (s *submissionService) UpdateSubmissionStatus(ctx context.Context, reviewer
|
|||||||
_, err := wikiRepo.Create(ctx, sqlc.CreateWikiParams{
|
_, err := wikiRepo.Create(ctx, sqlc.CreateWikiParams{
|
||||||
ID: wikiUUID,
|
ID: wikiUUID,
|
||||||
Title: convert.StringToText(wiki.Title),
|
Title: convert.StringToText(wiki.Title),
|
||||||
|
Slug: convert.PtrToText(wiki.Slug),
|
||||||
Content: convert.StringToText(wiki.Doc),
|
Content: convert.StringToText(wiki.Doc),
|
||||||
ProjectID: projectUUID,
|
ProjectID: projectUUID,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to create wiki: "+wiki.ID)
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to create wiki: "+err.Error())
|
||||||
}
|
}
|
||||||
newWikis = append(newWikis, snapshotData.Wikis[i])
|
newWikis = append(newWikis, snapshotData.Wikis[i])
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package services
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
"history-api/internal/dtos/request"
|
"history-api/internal/dtos/request"
|
||||||
"history-api/internal/dtos/response"
|
"history-api/internal/dtos/response"
|
||||||
"history-api/internal/gen/sqlc"
|
"history-api/internal/gen/sqlc"
|
||||||
@@ -14,6 +16,8 @@ import (
|
|||||||
|
|
||||||
type WikiService interface {
|
type WikiService interface {
|
||||||
GetWikiByID(ctx context.Context, id string) (*response.WikiResponse, *fiber.Error)
|
GetWikiByID(ctx context.Context, id string) (*response.WikiResponse, *fiber.Error)
|
||||||
|
GetWikiBySlug(ctx context.Context, slug string) (*response.WikiResponse, *fiber.Error)
|
||||||
|
IsExistWikiSlug(ctx context.Context, slug string) (bool, *fiber.Error)
|
||||||
SearchWikis(ctx context.Context, req *request.SearchWikiDto) ([]*response.WikiResponse, *fiber.Error)
|
SearchWikis(ctx context.Context, req *request.SearchWikiDto) ([]*response.WikiResponse, *fiber.Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,6 +44,29 @@ func (s *wikiService) GetWikiByID(ctx context.Context, id string) (*response.Wik
|
|||||||
return wiki.ToResponse(), nil
|
return wiki.ToResponse(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *wikiService) GetWikiBySlug(ctx context.Context, slug string) (*response.WikiResponse, *fiber.Error) {
|
||||||
|
if slug == "" {
|
||||||
|
return nil, fiber.NewError(fiber.StatusBadRequest, "Slug is required")
|
||||||
|
}
|
||||||
|
wiki, err := s.wikiRepo.GetBySlug(ctx, slug)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fiber.NewError(fiber.StatusNotFound, "Wiki not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return wiki.ToResponse(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *wikiService) IsExistWikiSlug(ctx context.Context, slug string) (bool, *fiber.Error) {
|
||||||
|
if slug == "" {
|
||||||
|
return false, fiber.NewError(fiber.StatusBadRequest, "Slug is required")
|
||||||
|
}
|
||||||
|
wiki, err := s.wikiRepo.GetBySlug(ctx, slug)
|
||||||
|
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return false, fiber.NewError(fiber.StatusInternalServerError, "Failed to check slug existence")
|
||||||
|
}
|
||||||
|
return wiki != nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *wikiService) SearchWikis(ctx context.Context, req *request.SearchWikiDto) ([]*response.WikiResponse, *fiber.Error) {
|
func (s *wikiService) SearchWikis(ctx context.Context, req *request.SearchWikiDto) ([]*response.WikiResponse, *fiber.Error) {
|
||||||
limit := int32(25)
|
limit := int32(25)
|
||||||
if req.Limit > 0 {
|
if req.Limit > 0 {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ var (
|
|||||||
EMAIL_REGEX = regexp.MustCompile(`^[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,4}$`)
|
EMAIL_REGEX = regexp.MustCompile(`^[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,4}$`)
|
||||||
YOUTUBE_VIDEO_ID_REGEX = regexp.MustCompile(`(?:\/|v=|\/v\/|embed\/|watch\?v=|watch\?.+&v=)([\w-]{11})`)
|
YOUTUBE_VIDEO_ID_REGEX = regexp.MustCompile(`(?:\/|v=|\/v\/|embed\/|watch\?v=|watch\?.+&v=)([\w-]{11})`)
|
||||||
BANK_INPUT = regexp.MustCompile(`[__]{2,}`)
|
BANK_INPUT = regexp.MustCompile(`[__]{2,}`)
|
||||||
|
SLUG_REGEX = regexp.MustCompile(`^[a-z0-9]+(?:-[a-z0-9]+)*$`)
|
||||||
)
|
)
|
||||||
|
|
||||||
func ValidatePassword(password string) error {
|
func ValidatePassword(password string) error {
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"history-api/pkg/constants"
|
||||||
|
|
||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
"github.com/gofiber/fiber/v3"
|
"github.com/gofiber/fiber/v3"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
@@ -53,6 +55,14 @@ func init() {
|
|||||||
}
|
}
|
||||||
return u.Version() == 7
|
return u.Version() == 7
|
||||||
})
|
})
|
||||||
|
|
||||||
|
validate.RegisterValidation("slug", func(fl validator.FieldLevel) bool {
|
||||||
|
val := fl.Field().String()
|
||||||
|
if val == "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return constants.SLUG_REGEX.MatchString(val)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func isValidURL(s string) bool {
|
func isValidURL(s string) bool {
|
||||||
|
|||||||
Reference in New Issue
Block a user