hub features
This commit is contained in:
@@ -19,11 +19,19 @@ export const properties = pgTable(
|
||||
.references(() => users.id, { onDelete: 'set null' }),
|
||||
detailsJson: t.jsonb('details_json'),
|
||||
metadata: t.jsonb('metadata'),
|
||||
// Community features
|
||||
isPrivate: t.boolean('is_private').notNull().default(true),
|
||||
views: t.integer('views').notNull().default(0),
|
||||
likes: t.integer('likes').notNull().default(0),
|
||||
thumbnailUrl: t.text('thumbnail_url'),
|
||||
...timestampsColumns,
|
||||
}),
|
||||
(t) => [
|
||||
index('property_address_idx').on(t.addressId),
|
||||
index('property_owner_idx').on(t.ownerId),
|
||||
index('property_is_private_idx').on(t.isPrivate),
|
||||
index('property_views_idx').on(t.views),
|
||||
index('property_likes_idx').on(t.likes),
|
||||
],
|
||||
).enableRLS()
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
-- Add community features to properties table
|
||||
ALTER TABLE properties ADD COLUMN IF NOT EXISTS is_private BOOLEAN NOT NULL DEFAULT true;
|
||||
ALTER TABLE properties ADD COLUMN IF NOT EXISTS views INTEGER NOT NULL DEFAULT 0;
|
||||
ALTER TABLE properties ADD COLUMN IF NOT EXISTS likes INTEGER NOT NULL DEFAULT 0;
|
||||
ALTER TABLE properties ADD COLUMN IF NOT EXISTS thumbnail_url TEXT;
|
||||
|
||||
-- Create indexes for community queries
|
||||
CREATE INDEX IF NOT EXISTS idx_properties_is_private ON properties(is_private) WHERE is_private = false;
|
||||
CREATE INDEX IF NOT EXISTS idx_properties_views ON properties(views DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_properties_likes ON properties(likes DESC);
|
||||
|
||||
-- Set existing properties to private (user opt-in to share)
|
||||
UPDATE properties SET is_private = true WHERE is_private IS NULL;
|
||||
@@ -0,0 +1,78 @@
|
||||
-- Drop existing RLS policies for properties
|
||||
DROP POLICY IF EXISTS "Users can view their own properties" ON properties;
|
||||
DROP POLICY IF EXISTS "Users can insert their own properties" ON properties;
|
||||
DROP POLICY IF EXISTS "Users can update their own properties" ON properties;
|
||||
DROP POLICY IF EXISTS "Users can delete their own properties" ON properties;
|
||||
|
||||
-- New RLS policy: Users can view their own properties OR public properties
|
||||
CREATE POLICY "Users can view own or public properties"
|
||||
ON properties FOR SELECT
|
||||
USING (
|
||||
owner_id = current_setting('app.user_id', true)::TEXT
|
||||
OR is_private = false
|
||||
OR owner_id IS NULL
|
||||
);
|
||||
|
||||
-- Keep other policies the same (insert/update/delete still require ownership)
|
||||
CREATE POLICY "Users can insert their own properties"
|
||||
ON properties FOR INSERT
|
||||
WITH CHECK (owner_id = current_setting('app.user_id', true)::TEXT OR owner_id IS NULL);
|
||||
|
||||
CREATE POLICY "Users can update their own properties"
|
||||
ON properties FOR UPDATE
|
||||
USING (owner_id = current_setting('app.user_id', true)::TEXT OR owner_id IS NULL);
|
||||
|
||||
CREATE POLICY "Users can delete their own properties"
|
||||
ON properties FOR DELETE
|
||||
USING (owner_id = current_setting('app.user_id', true)::TEXT OR owner_id IS NULL);
|
||||
|
||||
-- Drop existing RLS policies for models
|
||||
DROP POLICY IF EXISTS "Users can view models of their own properties" ON properties_models;
|
||||
DROP POLICY IF EXISTS "Users can insert models for their own properties" ON properties_models;
|
||||
DROP POLICY IF EXISTS "Users can update models of their own properties" ON properties_models;
|
||||
DROP POLICY IF EXISTS "Users can delete models of their own properties" ON properties_models;
|
||||
|
||||
-- Update models policy: Users can view models of their own properties OR public properties
|
||||
CREATE POLICY "Users can view models of own or public properties"
|
||||
ON properties_models FOR SELECT
|
||||
USING (
|
||||
EXISTS (
|
||||
SELECT 1 FROM properties
|
||||
WHERE properties.id = properties_models.property_id
|
||||
AND (
|
||||
properties.owner_id = current_setting('app.user_id', true)::TEXT
|
||||
OR properties.is_private = false
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
-- Keep other model policies the same
|
||||
CREATE POLICY "Users can insert models for their own properties"
|
||||
ON properties_models FOR INSERT
|
||||
WITH CHECK (
|
||||
EXISTS (
|
||||
SELECT 1 FROM properties
|
||||
WHERE properties.id = properties_models.property_id
|
||||
AND properties.owner_id = current_setting('app.user_id', true)::TEXT
|
||||
)
|
||||
);
|
||||
|
||||
CREATE POLICY "Users can update models of their own properties"
|
||||
ON properties_models FOR UPDATE
|
||||
USING (
|
||||
EXISTS (
|
||||
SELECT 1 FROM properties
|
||||
WHERE properties.id = properties_models.property_id
|
||||
AND properties.owner_id = current_setting('app.user_id', true)::TEXT
|
||||
)
|
||||
);
|
||||
|
||||
CREATE POLICY "Users can delete models of their own properties"
|
||||
ON properties_models FOR DELETE
|
||||
USING (
|
||||
EXISTS (
|
||||
SELECT 1 FROM properties
|
||||
WHERE properties.id = properties_models.property_id
|
||||
AND properties.owner_id = current_setting('app.user_id', true)::TEXT
|
||||
)
|
||||
);
|
||||
@@ -0,0 +1,9 @@
|
||||
-- Function to atomically increment view count
|
||||
CREATE OR REPLACE FUNCTION increment_property_views(property_id TEXT)
|
||||
RETURNS void AS $$
|
||||
BEGIN
|
||||
UPDATE properties
|
||||
SET views = views + 1
|
||||
WHERE id = property_id;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
@@ -0,0 +1,41 @@
|
||||
-- Create property_likes table to track user likes
|
||||
CREATE TABLE IF NOT EXISTS property_likes (
|
||||
id TEXT PRIMARY KEY,
|
||||
property_id TEXT NOT NULL REFERENCES properties(id) ON DELETE CASCADE,
|
||||
user_id TEXT NOT NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
|
||||
-- Ensure a user can only like a property once
|
||||
UNIQUE(property_id, user_id)
|
||||
);
|
||||
|
||||
-- Enable RLS
|
||||
ALTER TABLE property_likes ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- RLS Policies
|
||||
-- Users can view all likes (to see like counts)
|
||||
CREATE POLICY "Anyone can view likes"
|
||||
ON property_likes FOR SELECT
|
||||
USING (true);
|
||||
|
||||
-- Users can insert their own likes
|
||||
CREATE POLICY "Users can create their own likes"
|
||||
ON property_likes FOR INSERT
|
||||
WITH CHECK (user_id = current_setting('app.user_id', true)::TEXT);
|
||||
|
||||
-- Users can delete their own likes
|
||||
CREATE POLICY "Users can delete their own likes"
|
||||
ON property_likes FOR DELETE
|
||||
USING (user_id = current_setting('app.user_id', true)::TEXT);
|
||||
|
||||
-- Create index for efficient querying
|
||||
CREATE INDEX IF NOT EXISTS idx_property_likes_property_id ON property_likes(property_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_property_likes_user_id ON property_likes(user_id);
|
||||
|
||||
-- Function to get like count for a property
|
||||
CREATE OR REPLACE FUNCTION get_property_like_count(property_id TEXT)
|
||||
RETURNS INTEGER AS $$
|
||||
BEGIN
|
||||
RETURN (SELECT COUNT(*)::INTEGER FROM property_likes WHERE property_likes.property_id = $1);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER STABLE;
|
||||
Reference in New Issue
Block a user