mirror of
https://github.com/zen-browser/rices.git
synced 2025-07-07 17:05:40 +02:00
feat(rices): mejorar reglas de publicación de rices
- Permitir publicar un rice con un token existente si no excede el límite. - Configurar límite de 5 rices por token a través de variable de entorno (env.MAX_RICES_BY_TOKEN). - Validar duplicidad de nombres al crear un nuevo rice.
This commit is contained in:
parent
612e27a55c
commit
9bf1fe8e0d
7 changed files with 122 additions and 9 deletions
|
@ -5,4 +5,6 @@ GITHUB_REPO_NAME=rices-store
|
|||
SUPABASE_URL=https://xxxxxxxxxxxxx.supabase.co
|
||||
SUPABASE_KEY=XXXXXXXXXXXXXXXXXXX
|
||||
|
||||
MAX_RICES_BY_TOKEN=5
|
||||
|
||||
MODERATION_SECRET=superSecret123
|
||||
|
|
|
@ -12,9 +12,8 @@ CREATE TABLE rices (
|
|||
level INTEGER DEFAULT 0 NOT NULL, -- Level: 0 (Public), 1 (Verified)
|
||||
created_at TIMESTAMP DEFAULT NOW(), -- Creation date
|
||||
updated_at TIMESTAMP, -- Last update date
|
||||
PRIMARY KEY (id, slug), -- Composite primary key
|
||||
UNIQUE (slug), -- Ensure slug is unique
|
||||
UNIQUE (name) -- Ensure name is unique
|
||||
PRIMARY KEY (id), -- Composite primary key
|
||||
UNIQUE (slug) -- Ensure slug is unique
|
||||
);
|
||||
|
||||
CREATE OR REPLACE FUNCTION increment_visits(slug_param TEXT)
|
||||
|
|
|
@ -41,10 +41,11 @@ export class RicesController {
|
|||
async createRice(
|
||||
@Body() content: string,
|
||||
@Headers() headers: Record<string, string>,
|
||||
@Headers('x-zen-rices-token') token: string,
|
||||
) {
|
||||
const contentString =
|
||||
typeof content === 'string' ? content : JSON.stringify(content);
|
||||
return this.ricesService.create(contentString, headers);
|
||||
return this.ricesService.create(contentString, token, headers);
|
||||
}
|
||||
|
||||
@ApiOperation({ summary: 'Get information about a Rice' })
|
||||
|
|
|
@ -7,6 +7,7 @@ import {
|
|||
} from '@nestjs/common';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { generateSlug } from './utils/slug.util';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { GitHubService } from '../github/github.service';
|
||||
import { SupabaseService } from '../supabase/supabase.service';
|
||||
|
||||
|
@ -17,9 +18,14 @@ export class RicesService {
|
|||
constructor(
|
||||
private readonly gitHubService: GitHubService,
|
||||
private readonly supabaseService: SupabaseService,
|
||||
private readonly configService: ConfigService,
|
||||
) {}
|
||||
|
||||
async create(content: string, headers: Record<string, string>) {
|
||||
async create(
|
||||
content: string,
|
||||
token: string | null,
|
||||
headers: Record<string, string>,
|
||||
) {
|
||||
try {
|
||||
// Validate headers
|
||||
const name = headers['x-zen-rice-name'];
|
||||
|
@ -77,12 +83,12 @@ export class RicesService {
|
|||
}
|
||||
|
||||
// Check if a rice with the same name already exists
|
||||
const existingRice = await this.supabaseService.getRiceByName(name);
|
||||
/*const existingRice = await this.supabaseService.getRiceByName(name);
|
||||
if (existingRice) {
|
||||
throw new ConflictException(
|
||||
`A rice with the name '${name}' already exists.`,
|
||||
);
|
||||
}
|
||||
}*/
|
||||
|
||||
let slug: string;
|
||||
try {
|
||||
|
@ -93,7 +99,21 @@ export class RicesService {
|
|||
throw new BadRequestException(`Invalid name provided`);
|
||||
}
|
||||
|
||||
const token = uuidv4();
|
||||
if (!token) {
|
||||
token = uuidv4();
|
||||
} else {
|
||||
const tokenMaxCount = this.configService.get<number>(
|
||||
'MAX_RICES_BY_TOKEN',
|
||||
5,
|
||||
);
|
||||
const tokenCount = await this.supabaseService.countRicesByToken(token);
|
||||
if (tokenCount >= tokenMaxCount) {
|
||||
throw new ConflictException(
|
||||
`The token '${token}' is already associated with 5 or more rices.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const metadata = {
|
||||
id: uuidv4(),
|
||||
token,
|
||||
|
|
|
@ -132,4 +132,18 @@ export class SupabaseService {
|
|||
throw new Error(`Failed to update rice level: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async countRicesByToken(token: string): Promise<number> {
|
||||
const { data, error, count } = await this.supabase
|
||||
.from('rices') // Nombre de tu tabla en Supabase
|
||||
.select('*', { count: 'exact' })
|
||||
.eq('token', token);
|
||||
|
||||
if (error) {
|
||||
console.error('Error counting rices by token:', error);
|
||||
throw new Error('Failed to count rices by token');
|
||||
}
|
||||
|
||||
return count || 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
POST {{baseUrl}}/rices
|
||||
Content-Type: application/json
|
||||
X-Zen-Rice-Name: cool-zenrice-test-base64211
|
||||
X-Zen-Rice-Name: cool-zenrice-test-base
|
||||
X-Zen-Rice-Author: jhon@doe.com
|
||||
User-Agent: ZenBrowser/1.2b.0 (EndeavourOS x86_64)
|
||||
|
||||
|
|
77
test/restclient/01b_create_rice_same_token.http
Normal file
77
test/restclient/01b_create_rice_same_token.http
Normal file
|
@ -0,0 +1,77 @@
|
|||
@baseUrl = http://localhost:3000
|
||||
|
||||
@previous_token = 32af2ec5-b7f0-4c61-8c9a-e67edb3faad4
|
||||
|
||||
POST {{baseUrl}}/rices
|
||||
Content-Type: application/json
|
||||
X-Zen-Rice-Name: cool-zenrice-test-base5
|
||||
X-Zen-Rice-Author: jhon@doe.com
|
||||
x-zen-rices-token: {{previous_token}}
|
||||
User-Agent: ZenBrowser/1.2b.0 (EndeavourOS x86_64)
|
||||
|
||||
{
|
||||
"userChrome": "",
|
||||
"userContent": null,
|
||||
"enabledMods": [
|
||||
"5bb07b6e-c89f-4f4a-a0ed-e483cc535594"
|
||||
],
|
||||
"preferences": {
|
||||
"theme.custom_menubutton.default": "Firefox",
|
||||
"theme.custom_menubutton.custom": "url(chrome://branding/content/icon32.png)",
|
||||
"zen.view.use-single-toolbar": true,
|
||||
"zen.view.sidebar-expanded": true,
|
||||
"zen.tabs.vertical.right-side": false,
|
||||
"zen.view.experimental-no-window-controls": false,
|
||||
"zen.view.hide-window-controls": true,
|
||||
"browser.uiCustomization.state": "{\"placements\":{\"widget-overflow-fixed-list\":[],\"unified-extensions-area\":[\"ublock0_raymondhill_net-browser-action\",\"addon_darkreader_org-browser-action\",\"_7a7a4a92-a2a0-41d1-9fd7-1e92480d612d_-browser-action\",\"cookieautodelete_kennydo_com-browser-action\",\"tab-unloader-we_afnankhan-browser-action\"],\"nav-bar\":[\"back-button\",\"forward-button\",\"stop-reload-button\",\"customizableui-special-spring1\",\"urlbar-container\",\"customizableui-special-spring2\",\"wrapper-sidebar-button\",\"unified-extensions-button\"],\"toolbar-menubar\":[\"menubar-items\"],\"TabsToolbar\":[\"tabbrowser-tabs\"],\"vertical-tabs\":[],\"PersonalToolbar\":[\"personal-bookmarks\"],\"zen-sidebar-top-buttons\":[\"zen-sidepanel-button\"],\"zen-sidebar-icons-wrapper\":[\"zen-profile-button\",\"zen-workspaces-button\",\"downloads-button\"]},\"seen\":[\"_7a7a4a92-a2a0-41d1-9fd7-1e92480d612d_-browser-action\",\"developer-button\",\"cookieautodelete_kennydo_com-browser-action\",\"tab-unloader-we_afnankhan-browser-action\",\"addon_darkreader_org-browser-action\",\"ublock0_raymondhill_net-browser-action\"],\"dirtyAreaCache\":[\"unified-extensions-area\",\"nav-bar\",\"toolbar-menubar\",\"TabsToolbar\",\"vertical-tabs\",\"PersonalToolbar\",\"zen-sidebar-top-buttons\",\"zen-sidebar-icons-wrapper\"],\"currentVersion\":20,\"newElementCount\":2}"
|
||||
},
|
||||
"workspaceThemes": [
|
||||
{
|
||||
"type": "gradient",
|
||||
"gradientColors": [
|
||||
{
|
||||
"c": [
|
||||
124,
|
||||
133,
|
||||
255
|
||||
],
|
||||
"isCustom": false
|
||||
},
|
||||
{
|
||||
"c": [
|
||||
69,
|
||||
255,
|
||||
86
|
||||
],
|
||||
"isCustom": false
|
||||
}
|
||||
],
|
||||
"opacity": 0.5,
|
||||
"rotation": 45,
|
||||
"texture": 0
|
||||
},
|
||||
{
|
||||
"type": "gradient",
|
||||
"gradientColors": [
|
||||
{
|
||||
"c": [
|
||||
255,
|
||||
133,
|
||||
65
|
||||
],
|
||||
"isCustom": false
|
||||
}
|
||||
],
|
||||
"opacity": 0.6,
|
||||
"rotation": 45,
|
||||
"texture": null
|
||||
},
|
||||
{
|
||||
"type": "gradient",
|
||||
"gradientColors": [],
|
||||
"opacity": 0.5,
|
||||
"rotation": 45,
|
||||
"texture": null
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue