Skip to content

Commit e27f354

Browse files
Merge pull request #775 from decentraland/feat/tip-changes
feat: add creator_address to place attributes and update related functions
2 parents 3094ef5 + 6203984 commit e27f354

21 files changed

+160
-16
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ See the **[OpenAPI Specification](docs/openapi.yaml)** which can be viewed with
5656

5757
The database schema includes the following main tables:
5858

59-
- `places` - Main table storing scene and world information
59+
- `places` - Main table storing scene and world information (includes creator_address for creator-based queries)
6060
- `users` - Registered users with permissions
6161
- `categories` - Place categories for organization
6262
- `place_categories` - Many-to-many relationship between places and categories

docs/ai-agent-context.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ The Decentraland Places service is a comprehensive API solution for discovering,
6161
- **Hot Scenes**: Places with active users, tracked via Catalyst realm provider with real-time user counts
6262
- **User Visits**: Unique users who visited a place in the last 30 days
6363
- **Highlighted Places**: Featured places with special promotion status
64+
- **Creator Address**: Ethereum address of the scene creator, extracted from scene metadata during deployment processing, indexed for efficient creator-based queries (used by tipping systems)
6465

6566
## API Specification
6667

@@ -73,6 +74,7 @@ The service exposes a REST API under `/api` with comprehensive documentation in
7374
- **Interactions**: `/api/places/:id/likes`, `/api/places/:id/favorites` (authentication required)
7475
- **Reports**: `/api/report` (authentication required, returns S3 signed URL)
7576
- **Social**: `/places/place/`, `/places/world/` (metadata injection for social sharing)
77+
- **Creator Queries**: `/api/places?creator_address=0x...` (lookup places by scene creator for tipping integration)
7678

7779
**Authentication**: Bearer token authentication using Decentraland wallet signatures. Admin endpoints require additional permissions.
7880

@@ -91,7 +93,7 @@ The service exposes a REST API under `/api` with comprehensive documentation in
9193

9294
**Key Tables**:
9395

94-
- `places`: Main table with UUID, title, description, positions[], base_position, owner, content_rating, disabled, user_count, user_visits, like metrics
96+
- `places`: Main table with UUID, title, description, positions[], base_position, owner, creator_address, content_rating, disabled, user_count, user_visits, like metrics
9597
- `users`: Registered users with Ethereum addresses and permissions
9698
- `categories`: Place categories with name, active status, i18n translations
9799
- `place_categories`: Many-to-many relationships between places and categories

docs/database-schemas.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ erDiagram
1212
text description
1313
text image
1414
text owner
15+
text creator_address
1516
varchar_15_array positions
1617
varchar_15 base_position
1718
text contact_name
@@ -119,6 +120,7 @@ Main table containing all places (scenes in Genesis City and Decentraland Worlds
119120
| image | TEXT | YES | NULL | Place thumbnail image URL from navmapThumbnail |
120121
| highlighted_image | TEXT | YES | NULL | Special featured image for highlighted/promoted places |
121122
| owner | TEXT | YES | NULL | Ethereum address of the place owner (0x...) |
123+
| creator_address | TEXT | YES | NULL | Ethereum address of the scene creator (0x...), extracted from metadata |
122124
| positions | VARCHAR(15)[] | NO | {} | Array of parcel coordinates (e.g., ['52,12', '52,13']) |
123125
| base_position | VARCHAR(15) | NO | - | Primary parcel coordinate (spawn point, key for UUID persistence) |
124126
| contact_name | TEXT | YES | NULL | Contact person name |
@@ -152,6 +154,7 @@ Main table containing all places (scenes in Genesis City and Decentraland Worlds
152154
- `(base_position)` WHERE disabled is false and world is false - Fast position lookups for scenes
153155
- `(updated_at)` WHERE disabled is false and world is false - Recently updated places
154156
- `(like_rate)` WHERE disabled is false and world is false - Popular places ranking
157+
- `(creator_address)` - Fast lookups by scene creator for tipping and creator queries
155158

156159
### Constraints
157160

@@ -167,6 +170,7 @@ Main table containing all places (scenes in Genesis City and Decentraland Worlds
167170
- **Full-Text Search**: `textsearch` column is automatically updated via triggers on title, description, and owner changes
168171
- **Categories Denormalization**: The `categories` array is denormalized from `place_categories` for query performance
169172
- **World vs Scene**: `world=true` places use `world_name` for identification, `world=false` places use `positions` and `base_position`
173+
- **Creator Address**: Extracted from scene metadata during deployment processing, used for creator-based queries (e.g., tipping system integration)
170174

171175
---
172176

src/__data__/allPlacesWithAggregatedAttributes.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ export const allPlacesWithAggregatedAttributes: AggregatePlaceAttributes[] = [
105105
world_name: null,
106106
deployed_at: new Date("2022-11-14T17:22:05.307Z"),
107107
textsearch: undefined,
108+
creator_address: null,
108109
},
109110
{
110111
id: "a7ce87fa-df3c-4a2f-bca6-bd2fe794d51a",
@@ -136,5 +137,6 @@ export const allPlacesWithAggregatedAttributes: AggregatePlaceAttributes[] = [
136137
world_name: "test.dcl.eth",
137138
deployed_at: new Date("2022-11-14T17:22:05.307Z"),
138139
textsearch: undefined,
140+
creator_address: null,
139141
},
140142
]

src/__data__/placeGenesisPlaza.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,5 @@ export const placeGenesisPlaza: PlaceAttributes = {
101101
deployed_at: new Date("2022-11-14T17:22:05.307Z"),
102102
textsearch: undefined,
103103
categories: [],
104+
creator_address: null,
104105
}

src/__data__/placeGenesisPlazaWithAggregatedAttributes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,4 +415,5 @@ export const placeGenesisPlazaWithAggregatedAttributes: AggregatePlaceAttributes
415415
world_name: null,
416416
deployed_at: new Date("2022-11-14T17:22:05.307Z"),
417417
textsearch: undefined,
418+
creator_address: null,
418419
}

src/__data__/placeRoad.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,5 @@ export const placeRoad: PlaceAttributes = {
2929
deployed_at: new Date("2022-11-14T17:22:05.307Z"),
3030
textsearch: undefined,
3131
categories: [],
32+
creator_address: null,
3233
}

src/__data__/world.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export const worldPlaceParalax: PlaceAttributes = {
3838
deployed_at: new Date("2023-03-28T13:05:45.437Z"),
3939
textsearch: undefined,
4040
categories: [],
41+
creator_address: null,
4142
}
4243

4344
export const worldPlaceParalaxWithAggregated: AggregatePlaceAttributes = {
@@ -71,6 +72,7 @@ export const worldPlaceParalaxWithAggregated: AggregatePlaceAttributes = {
7172
user_dislike: false,
7273
textsearch: undefined,
7374
categories: [],
75+
creator_address: null,
7476
}
7577

7678
export const worldContentEntitySceneParalax: ContentEntityScene = {
@@ -277,4 +279,5 @@ export const worldPlaceTemplegame: AggregatePlaceAttributes = {
277279
user_count: 3,
278280
textsearch: undefined,
279281
categories: [],
282+
creator_address: null,
280283
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { ContentEntityScene } from "decentraland-gatsby/dist/utils/api/Catalyst.types"
2+
import fetch from "node-fetch"
3+
4+
type SceneJson = {
5+
creator?: string
6+
}
7+
8+
/**
9+
* Extracts the creator address from the scene.json file in the content entity
10+
* @param contentEntityScene - The content entity scene from Catalyst
11+
* @param contentServerUrl - The content server URL
12+
* @returns The creator address or null if not found
13+
*/
14+
export async function extractCreatorAddress(
15+
contentEntityScene: ContentEntityScene,
16+
contentServerUrl: string
17+
): Promise<string | null> {
18+
try {
19+
// Find scene.json in the content files
20+
const sceneJsonContent = contentEntityScene.content.find(
21+
(content) => content.file === "scene.json"
22+
)
23+
24+
if (!sceneJsonContent) {
25+
return null
26+
}
27+
28+
// Construct the URL to fetch the scene.json file
29+
const contentUrl = `${contentServerUrl.replace(/\/+$/, "")}/contents/${
30+
sceneJsonContent.hash
31+
}`
32+
33+
// Fetch the scene.json file
34+
const response = await fetch(contentUrl)
35+
36+
if (!response.ok) {
37+
return null
38+
}
39+
40+
const sceneJson: SceneJson = await response.json()
41+
42+
// Return the creator address if it exists
43+
return sceneJson.creator || null
44+
} catch (error) {
45+
// If there's any error fetching or parsing, return null
46+
return null
47+
}
48+
}

src/entities/CheckScenes/task/processContentEntityScene.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ export function processContentEntityScene(
8585
export function createPlaceFromContentEntityScene(
8686
contentEntityScene: ContentEntityScene,
8787
data: Partial<Omit<PlaceAttributes, "id">> = {},
88-
options: { url?: string } = {}
88+
options: { url?: string; creator?: string | null } = {}
8989
) {
9090
const now = new Date()
9191
const title = contentEntityScene?.metadata?.display?.title || null
@@ -160,6 +160,7 @@ export function createPlaceFromContentEntityScene(
160160
!!data.disabled && !data.disabled_at ? now : data.disabled_at || null,
161161
textsearch: undefined,
162162
categories: [],
163+
creator_address: options.creator || null,
163164
}
164165

165166
placeParsed.textsearch = PlaceModel.textsearch(placeParsed)

0 commit comments

Comments
 (0)