mirror of
https://github.com/jordienr/zenblog.git
synced 2026-09-28 01:56:07 -04:00
wip
This commit is contained in:
@@ -20,11 +20,11 @@ export const CodeBlock = ({
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="rounded-lg bg-slate-900 font-mono text-white">
|
||||
<div className="flex items-center justify-between px-2">
|
||||
<h2 className="text-xs text-slate-300">{title || language}</h2>
|
||||
<button onClick={copy} className="p-2 text-slate-300">
|
||||
{isCopied ? <Check size="18" /> : <Clipboard size="18" />}
|
||||
<div className="rounded-lg bg-zinc-900 font-mono text-white">
|
||||
<div className="flex items-center justify-between pl-2">
|
||||
<h2 className="text-xs text-zinc-300">{title || language}</h2>
|
||||
<button onClick={copy} className="p-2 text-zinc-400">
|
||||
{isCopied ? <Check size="15" /> : <Clipboard size="15" />}
|
||||
</button>
|
||||
</div>
|
||||
<SyntaxHighlighter
|
||||
|
||||
@@ -5,11 +5,10 @@ import Spinner from "@/components/Spinner";
|
||||
import { ZendoEditor } from "@/components/Editor/ZendoEditor";
|
||||
import { toast } from "sonner";
|
||||
import { useBlogTags } from "@/components/Editor/Editor.queries";
|
||||
import { usePostQuery, useUpdatePostTagsMutation } from "@/queries/posts";
|
||||
import { usePostQuery } from "@/queries/posts";
|
||||
import { getSupabaseBrowserClient } from "@/lib/supabase";
|
||||
|
||||
export default function Post() {
|
||||
const api = createAPIClient();
|
||||
const router = useRouter();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
@@ -18,11 +17,11 @@ export default function Post() {
|
||||
|
||||
const sb = getSupabaseBrowserClient();
|
||||
|
||||
const { data: post, isLoading } = usePostQuery(postSlug);
|
||||
const { data: post, isLoading, isRefetching } = usePostQuery(postSlug);
|
||||
|
||||
const tags = useBlogTags({ blogId });
|
||||
|
||||
if (isLoading || tags.isLoading) {
|
||||
if (isLoading || tags.isLoading || isRefetching) {
|
||||
return (
|
||||
<div className="flex-center p-12">
|
||||
<Spinner />
|
||||
@@ -63,7 +62,9 @@ export default function Post() {
|
||||
}));
|
||||
|
||||
if (newTags) {
|
||||
await sb.from("post_tags").upsert(newTags);
|
||||
await sb.from("post_tags").upsert(newTags, {
|
||||
onConflict: "tag_id, post_id, blog_id",
|
||||
});
|
||||
}
|
||||
|
||||
queryClient.invalidateQueries([
|
||||
@@ -74,6 +75,8 @@ export default function Post() {
|
||||
"tags",
|
||||
]);
|
||||
|
||||
queryClient.refetchQueries(["posts", "post", blogId, postSlug]);
|
||||
|
||||
toast.success("Post saved!");
|
||||
} catch (error: any) {
|
||||
console.error(error);
|
||||
|
||||
@@ -1,511 +0,0 @@
|
||||
drop policy "delete_categories_policy" on "public"."categories";
|
||||
|
||||
drop policy "insert_categories_policy" on "public"."categories";
|
||||
|
||||
drop policy "select_categories_policy" on "public"."categories";
|
||||
|
||||
drop policy "update_categories_policy" on "public"."categories";
|
||||
|
||||
drop policy "Allow AUTHED users to query ALL their POSTS" on "public"."posts";
|
||||
|
||||
drop policy "Enable delete for users based on user_id" on "public"."posts";
|
||||
|
||||
drop policy "Enable insert for authenticated users only" on "public"."posts";
|
||||
|
||||
drop policy "Enable read access for all users if published" on "public"."posts";
|
||||
|
||||
drop policy "Enable update for users based on user_id" on "public"."posts";
|
||||
|
||||
revoke delete on table "public"."admin_users" from "anon";
|
||||
|
||||
revoke insert on table "public"."admin_users" from "anon";
|
||||
|
||||
revoke references on table "public"."admin_users" from "anon";
|
||||
|
||||
revoke select on table "public"."admin_users" from "anon";
|
||||
|
||||
revoke trigger on table "public"."admin_users" from "anon";
|
||||
|
||||
revoke truncate on table "public"."admin_users" from "anon";
|
||||
|
||||
revoke update on table "public"."admin_users" from "anon";
|
||||
|
||||
revoke delete on table "public"."admin_users" from "authenticated";
|
||||
|
||||
revoke insert on table "public"."admin_users" from "authenticated";
|
||||
|
||||
revoke references on table "public"."admin_users" from "authenticated";
|
||||
|
||||
revoke select on table "public"."admin_users" from "authenticated";
|
||||
|
||||
revoke trigger on table "public"."admin_users" from "authenticated";
|
||||
|
||||
revoke truncate on table "public"."admin_users" from "authenticated";
|
||||
|
||||
revoke update on table "public"."admin_users" from "authenticated";
|
||||
|
||||
revoke delete on table "public"."admin_users" from "service_role";
|
||||
|
||||
revoke insert on table "public"."admin_users" from "service_role";
|
||||
|
||||
revoke references on table "public"."admin_users" from "service_role";
|
||||
|
||||
revoke select on table "public"."admin_users" from "service_role";
|
||||
|
||||
revoke trigger on table "public"."admin_users" from "service_role";
|
||||
|
||||
revoke truncate on table "public"."admin_users" from "service_role";
|
||||
|
||||
revoke update on table "public"."admin_users" from "service_role";
|
||||
|
||||
revoke delete on table "public"."categories" from "anon";
|
||||
|
||||
revoke insert on table "public"."categories" from "anon";
|
||||
|
||||
revoke references on table "public"."categories" from "anon";
|
||||
|
||||
revoke select on table "public"."categories" from "anon";
|
||||
|
||||
revoke trigger on table "public"."categories" from "anon";
|
||||
|
||||
revoke truncate on table "public"."categories" from "anon";
|
||||
|
||||
revoke update on table "public"."categories" from "anon";
|
||||
|
||||
revoke delete on table "public"."categories" from "authenticated";
|
||||
|
||||
revoke insert on table "public"."categories" from "authenticated";
|
||||
|
||||
revoke references on table "public"."categories" from "authenticated";
|
||||
|
||||
revoke select on table "public"."categories" from "authenticated";
|
||||
|
||||
revoke trigger on table "public"."categories" from "authenticated";
|
||||
|
||||
revoke truncate on table "public"."categories" from "authenticated";
|
||||
|
||||
revoke update on table "public"."categories" from "authenticated";
|
||||
|
||||
revoke delete on table "public"."categories" from "service_role";
|
||||
|
||||
revoke insert on table "public"."categories" from "service_role";
|
||||
|
||||
revoke references on table "public"."categories" from "service_role";
|
||||
|
||||
revoke select on table "public"."categories" from "service_role";
|
||||
|
||||
revoke trigger on table "public"."categories" from "service_role";
|
||||
|
||||
revoke truncate on table "public"."categories" from "service_role";
|
||||
|
||||
revoke update on table "public"."categories" from "service_role";
|
||||
|
||||
alter table "public"."admin_users" drop constraint "admin_users_user_id_fkey";
|
||||
|
||||
alter table "public"."categories" drop constraint "categories_blog_id_fkey";
|
||||
|
||||
alter table "public"."categories" drop constraint "categories_blog_id_slug_key";
|
||||
|
||||
alter table "public"."posts" drop constraint "unique_slug_per_user_post_constraint";
|
||||
|
||||
alter table "public"."admin_users" drop constraint "admin_users_pkey";
|
||||
|
||||
alter table "public"."categories" drop constraint "categories_pkey";
|
||||
|
||||
alter table "public"."products" drop constraint "products_pkey";
|
||||
|
||||
alter table "public"."subscriptions" drop constraint "subscriptions_pkey";
|
||||
|
||||
drop index if exists "public"."admin_users_pkey";
|
||||
|
||||
drop index if exists "public"."categories_blog_id_slug_key";
|
||||
|
||||
drop index if exists "public"."categories_pkey";
|
||||
|
||||
drop index if exists "public"."products_pkey";
|
||||
|
||||
drop index if exists "public"."subscriptions_pkey";
|
||||
|
||||
drop index if exists "public"."unique_slug_per_user_post_constraint";
|
||||
|
||||
drop table "public"."admin_users";
|
||||
|
||||
drop table "public"."categories";
|
||||
|
||||
create table "public"."blog_tags" (
|
||||
"id" uuid not null default gen_random_uuid(),
|
||||
"blog_id" uuid not null,
|
||||
"name" text not null,
|
||||
"slug" text not null,
|
||||
"created_at" timestamp with time zone not null default now(),
|
||||
"updated_at" timestamp with time zone not null default now(),
|
||||
"description" text
|
||||
);
|
||||
|
||||
|
||||
alter table "public"."blog_tags" enable row level security;
|
||||
|
||||
create table "public"."post_tags" (
|
||||
"id" bigint generated by default as identity not null,
|
||||
"created_at" timestamp with time zone not null default now(),
|
||||
"post_id" uuid not null,
|
||||
"tag_id" uuid not null,
|
||||
"blog_id" uuid not null
|
||||
);
|
||||
|
||||
|
||||
alter table "public"."post_tags" enable row level security;
|
||||
|
||||
create table "public"."prices" (
|
||||
"id" bigint generated by default as identity not null,
|
||||
"created_at" timestamp with time zone not null default now(),
|
||||
"price" jsonb not null,
|
||||
"stripe_price_id" text not null
|
||||
);
|
||||
|
||||
|
||||
alter table "public"."prices" enable row level security;
|
||||
|
||||
alter table "public"."posts" add column "deleted" boolean not null default false;
|
||||
|
||||
alter table "public"."posts" add column "deprecated_user_id" text default 'default'::text;
|
||||
|
||||
alter table "public"."posts" alter column "user_id" set default auth.uid();
|
||||
|
||||
alter table "public"."posts" alter column "user_id" set data type uuid using "user_id"::uuid;
|
||||
|
||||
alter table "public"."products" alter column "stripe_product_id" set not null;
|
||||
|
||||
alter table "public"."subscriptions" add column "stripe_subscription_id" text not null;
|
||||
|
||||
alter table "public"."subscriptions" add column "subscription" jsonb not null;
|
||||
|
||||
CREATE UNIQUE INDEX post_categories_pkey ON public.post_tags USING btree (id);
|
||||
|
||||
CREATE UNIQUE INDEX prices_pkey ON public.prices USING btree (id, stripe_price_id);
|
||||
|
||||
CREATE UNIQUE INDEX prices_stripe_price_id_key ON public.prices USING btree (stripe_price_id);
|
||||
|
||||
CREATE UNIQUE INDEX products_stripe_product_id_key ON public.products USING btree (stripe_product_id);
|
||||
|
||||
CREATE UNIQUE INDEX subscriptions_stripe_subscription_id_key ON public.subscriptions USING btree (stripe_subscription_id);
|
||||
|
||||
CREATE UNIQUE INDEX unique_post_tag_blog_combination ON public.post_tags USING btree (post_id, tag_id, blog_id);
|
||||
|
||||
CREATE UNIQUE INDEX categories_blog_id_slug_key ON public.blog_tags USING btree (blog_id, slug);
|
||||
|
||||
CREATE UNIQUE INDEX categories_pkey ON public.blog_tags USING btree (id);
|
||||
|
||||
CREATE UNIQUE INDEX products_pkey ON public.products USING btree (id, stripe_product_id);
|
||||
|
||||
CREATE UNIQUE INDEX subscriptions_pkey ON public.subscriptions USING btree (stripe_subscription_id);
|
||||
|
||||
CREATE UNIQUE INDEX unique_slug_per_user_post_constraint ON public.posts USING btree (slug, deprecated_user_id, blog_id);
|
||||
|
||||
alter table "public"."blog_tags" add constraint "categories_pkey" PRIMARY KEY using index "categories_pkey";
|
||||
|
||||
alter table "public"."post_tags" add constraint "post_categories_pkey" PRIMARY KEY using index "post_categories_pkey";
|
||||
|
||||
alter table "public"."prices" add constraint "prices_pkey" PRIMARY KEY using index "prices_pkey";
|
||||
|
||||
alter table "public"."products" add constraint "products_pkey" PRIMARY KEY using index "products_pkey";
|
||||
|
||||
alter table "public"."subscriptions" add constraint "subscriptions_pkey" PRIMARY KEY using index "subscriptions_pkey";
|
||||
|
||||
alter table "public"."blog_tags" add constraint "blog_tags_blog_id_fkey" FOREIGN KEY (blog_id) REFERENCES blogs(id) ON DELETE CASCADE not valid;
|
||||
|
||||
alter table "public"."blog_tags" validate constraint "blog_tags_blog_id_fkey";
|
||||
|
||||
alter table "public"."blog_tags" add constraint "categories_blog_id_slug_key" UNIQUE using index "categories_blog_id_slug_key";
|
||||
|
||||
alter table "public"."post_tags" add constraint "post_tags_blog_id_fkey" FOREIGN KEY (blog_id) REFERENCES blogs(id) not valid;
|
||||
|
||||
alter table "public"."post_tags" validate constraint "post_tags_blog_id_fkey";
|
||||
|
||||
alter table "public"."post_tags" add constraint "post_tags_post_id_fkey" FOREIGN KEY (post_id) REFERENCES posts(id) not valid;
|
||||
|
||||
alter table "public"."post_tags" validate constraint "post_tags_post_id_fkey";
|
||||
|
||||
alter table "public"."post_tags" add constraint "post_tags_tag_id_fkey" FOREIGN KEY (tag_id) REFERENCES blog_tags(id) not valid;
|
||||
|
||||
alter table "public"."post_tags" validate constraint "post_tags_tag_id_fkey";
|
||||
|
||||
alter table "public"."post_tags" add constraint "unique_post_tag_blog_combination" UNIQUE using index "unique_post_tag_blog_combination";
|
||||
|
||||
alter table "public"."prices" add constraint "prices_stripe_price_id_key" UNIQUE using index "prices_stripe_price_id_key";
|
||||
|
||||
alter table "public"."products" add constraint "products_stripe_product_id_key" UNIQUE using index "products_stripe_product_id_key";
|
||||
|
||||
alter table "public"."subscriptions" add constraint "subscriptions_stripe_subscription_id_key" UNIQUE using index "subscriptions_stripe_subscription_id_key";
|
||||
|
||||
alter table "public"."posts" add constraint "unique_slug_per_user_post_constraint" UNIQUE using index "unique_slug_per_user_post_constraint";
|
||||
|
||||
create or replace view "public"."posts_with_tags" as SELECT p.created_at,
|
||||
p.deprecated_user_id,
|
||||
p.blog_id,
|
||||
p.title,
|
||||
p.published,
|
||||
p.content,
|
||||
p.updated_at,
|
||||
p.slug,
|
||||
p.id AS post_id,
|
||||
p.cover_image,
|
||||
p.metadata,
|
||||
p.deleted,
|
||||
p.user_id,
|
||||
COALESCE(array_agg(bt.name) FILTER (WHERE (bt.id IS NOT NULL)), '{}'::text[]) AS tags
|
||||
FROM ((posts p
|
||||
LEFT JOIN post_tags pt ON ((p.id = pt.post_id)))
|
||||
LEFT JOIN blog_tags bt ON ((pt.tag_id = bt.id)))
|
||||
GROUP BY p.created_at, p.deprecated_user_id, p.blog_id, p.title, p.published, p.content, p.updated_at, p.slug, p.id, p.cover_image, p.metadata, p.deleted, p.user_id
|
||||
ORDER BY p.created_at DESC;
|
||||
|
||||
|
||||
grant delete on table "public"."blog_tags" to "anon";
|
||||
|
||||
grant insert on table "public"."blog_tags" to "anon";
|
||||
|
||||
grant references on table "public"."blog_tags" to "anon";
|
||||
|
||||
grant select on table "public"."blog_tags" to "anon";
|
||||
|
||||
grant trigger on table "public"."blog_tags" to "anon";
|
||||
|
||||
grant truncate on table "public"."blog_tags" to "anon";
|
||||
|
||||
grant update on table "public"."blog_tags" to "anon";
|
||||
|
||||
grant delete on table "public"."blog_tags" to "authenticated";
|
||||
|
||||
grant insert on table "public"."blog_tags" to "authenticated";
|
||||
|
||||
grant references on table "public"."blog_tags" to "authenticated";
|
||||
|
||||
grant select on table "public"."blog_tags" to "authenticated";
|
||||
|
||||
grant trigger on table "public"."blog_tags" to "authenticated";
|
||||
|
||||
grant truncate on table "public"."blog_tags" to "authenticated";
|
||||
|
||||
grant update on table "public"."blog_tags" to "authenticated";
|
||||
|
||||
grant delete on table "public"."blog_tags" to "service_role";
|
||||
|
||||
grant insert on table "public"."blog_tags" to "service_role";
|
||||
|
||||
grant references on table "public"."blog_tags" to "service_role";
|
||||
|
||||
grant select on table "public"."blog_tags" to "service_role";
|
||||
|
||||
grant trigger on table "public"."blog_tags" to "service_role";
|
||||
|
||||
grant truncate on table "public"."blog_tags" to "service_role";
|
||||
|
||||
grant update on table "public"."blog_tags" to "service_role";
|
||||
|
||||
grant delete on table "public"."post_tags" to "anon";
|
||||
|
||||
grant insert on table "public"."post_tags" to "anon";
|
||||
|
||||
grant references on table "public"."post_tags" to "anon";
|
||||
|
||||
grant select on table "public"."post_tags" to "anon";
|
||||
|
||||
grant trigger on table "public"."post_tags" to "anon";
|
||||
|
||||
grant truncate on table "public"."post_tags" to "anon";
|
||||
|
||||
grant update on table "public"."post_tags" to "anon";
|
||||
|
||||
grant delete on table "public"."post_tags" to "authenticated";
|
||||
|
||||
grant insert on table "public"."post_tags" to "authenticated";
|
||||
|
||||
grant references on table "public"."post_tags" to "authenticated";
|
||||
|
||||
grant select on table "public"."post_tags" to "authenticated";
|
||||
|
||||
grant trigger on table "public"."post_tags" to "authenticated";
|
||||
|
||||
grant truncate on table "public"."post_tags" to "authenticated";
|
||||
|
||||
grant update on table "public"."post_tags" to "authenticated";
|
||||
|
||||
grant delete on table "public"."post_tags" to "service_role";
|
||||
|
||||
grant insert on table "public"."post_tags" to "service_role";
|
||||
|
||||
grant references on table "public"."post_tags" to "service_role";
|
||||
|
||||
grant select on table "public"."post_tags" to "service_role";
|
||||
|
||||
grant trigger on table "public"."post_tags" to "service_role";
|
||||
|
||||
grant truncate on table "public"."post_tags" to "service_role";
|
||||
|
||||
grant update on table "public"."post_tags" to "service_role";
|
||||
|
||||
grant delete on table "public"."prices" to "anon";
|
||||
|
||||
grant insert on table "public"."prices" to "anon";
|
||||
|
||||
grant references on table "public"."prices" to "anon";
|
||||
|
||||
grant select on table "public"."prices" to "anon";
|
||||
|
||||
grant trigger on table "public"."prices" to "anon";
|
||||
|
||||
grant truncate on table "public"."prices" to "anon";
|
||||
|
||||
grant update on table "public"."prices" to "anon";
|
||||
|
||||
grant delete on table "public"."prices" to "authenticated";
|
||||
|
||||
grant insert on table "public"."prices" to "authenticated";
|
||||
|
||||
grant references on table "public"."prices" to "authenticated";
|
||||
|
||||
grant select on table "public"."prices" to "authenticated";
|
||||
|
||||
grant trigger on table "public"."prices" to "authenticated";
|
||||
|
||||
grant truncate on table "public"."prices" to "authenticated";
|
||||
|
||||
grant update on table "public"."prices" to "authenticated";
|
||||
|
||||
grant delete on table "public"."prices" to "service_role";
|
||||
|
||||
grant insert on table "public"."prices" to "service_role";
|
||||
|
||||
grant references on table "public"."prices" to "service_role";
|
||||
|
||||
grant select on table "public"."prices" to "service_role";
|
||||
|
||||
grant trigger on table "public"."prices" to "service_role";
|
||||
|
||||
grant truncate on table "public"."prices" to "service_role";
|
||||
|
||||
grant update on table "public"."prices" to "service_role";
|
||||
|
||||
create policy "delete_categories_policy"
|
||||
on "public"."blog_tags"
|
||||
as permissive
|
||||
for delete
|
||||
to public
|
||||
using ((EXISTS ( SELECT 1
|
||||
FROM blogs
|
||||
WHERE ((blogs.id = blog_tags.blog_id) AND (blogs.user_id = CURRENT_USER)))));
|
||||
|
||||
|
||||
create policy "insert_categories_policy"
|
||||
on "public"."blog_tags"
|
||||
as permissive
|
||||
for insert
|
||||
to public
|
||||
with check ((EXISTS ( SELECT 1
|
||||
FROM blogs
|
||||
WHERE ((blogs.id = blog_tags.blog_id) AND (blogs.user_id = (auth.uid())::text)))));
|
||||
|
||||
|
||||
create policy "select_categories_policy"
|
||||
on "public"."blog_tags"
|
||||
as permissive
|
||||
for select
|
||||
to public
|
||||
using (true);
|
||||
|
||||
|
||||
create policy "update_categories_policy"
|
||||
on "public"."blog_tags"
|
||||
as permissive
|
||||
for update
|
||||
to public
|
||||
using ((EXISTS ( SELECT 1
|
||||
FROM blogs
|
||||
WHERE ((blogs.id = blog_tags.blog_id) AND (blogs.user_id = CURRENT_USER)))));
|
||||
|
||||
|
||||
create policy "Enable insert for authenticated users only"
|
||||
on "public"."post_tags"
|
||||
as permissive
|
||||
for insert
|
||||
to authenticated
|
||||
with check ((EXISTS ( SELECT 1
|
||||
FROM blogs
|
||||
WHERE ((blogs.id = post_tags.blog_id) AND (blogs.user_id = (auth.uid())::text)))));
|
||||
|
||||
|
||||
create policy "Enable read access for all users"
|
||||
on "public"."post_tags"
|
||||
as permissive
|
||||
for select
|
||||
to public
|
||||
using (true);
|
||||
|
||||
|
||||
create policy "delete_policy"
|
||||
on "public"."post_tags"
|
||||
as permissive
|
||||
for delete
|
||||
to authenticated
|
||||
using ((EXISTS ( SELECT 1
|
||||
FROM blogs
|
||||
WHERE ((blogs.id = post_tags.blog_id) AND (blogs.user_id = (auth.uid())::text)))));
|
||||
|
||||
|
||||
create policy "update_post_tags"
|
||||
on "public"."post_tags"
|
||||
as permissive
|
||||
for update
|
||||
to authenticated
|
||||
using ((EXISTS ( SELECT 1
|
||||
FROM blogs
|
||||
WHERE ((blogs.id = post_tags.blog_id) AND (blogs.user_id = (auth.uid())::text)))))
|
||||
with check (true);
|
||||
|
||||
|
||||
create policy "insert_posts"
|
||||
on "public"."posts"
|
||||
as permissive
|
||||
for insert
|
||||
to authenticated
|
||||
with check ((EXISTS ( SELECT 1
|
||||
FROM blogs
|
||||
WHERE ((blogs.id = posts.blog_id) AND (blogs.user_id = (auth.uid())::text)))));
|
||||
|
||||
|
||||
create policy "read_posts"
|
||||
on "public"."posts"
|
||||
as permissive
|
||||
for select
|
||||
to anon
|
||||
using (((published = true) AND (deleted = false)));
|
||||
|
||||
|
||||
create policy "update_posts"
|
||||
on "public"."posts"
|
||||
as permissive
|
||||
for update
|
||||
to authenticated
|
||||
using ((EXISTS ( SELECT 1
|
||||
FROM blogs
|
||||
WHERE ((blogs.id = posts.blog_id) AND (blogs.user_id = (auth.uid())::text)))));
|
||||
|
||||
|
||||
create policy "Enable read access for all users"
|
||||
on "public"."prices"
|
||||
as permissive
|
||||
for select
|
||||
to public
|
||||
using (true);
|
||||
|
||||
|
||||
create policy "Enable read access for all users"
|
||||
on "public"."products"
|
||||
as permissive
|
||||
for select
|
||||
to public
|
||||
using (true);
|
||||
|
||||
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
drop policy "insert_posts" on "public"."posts";
|
||||
|
||||
set check_function_bodies = off;
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.is_blog_owner(blog_id uuid, given_user_id uuid)
|
||||
RETURNS boolean
|
||||
LANGUAGE plpgsql
|
||||
AS $function$
|
||||
BEGIN
|
||||
RETURN EXISTS (
|
||||
SELECT 1
|
||||
FROM public.blogs
|
||||
WHERE id = blog_id AND user_id = given_user_id::text
|
||||
);
|
||||
END;
|
||||
$function$
|
||||
;
|
||||
|
||||
create policy "authed_read_posts"
|
||||
on "public"."posts"
|
||||
as permissive
|
||||
for select
|
||||
to authenticated
|
||||
using (is_blog_owner(blog_id, auth.uid()));
|
||||
|
||||
|
||||
create policy "insert_posts"
|
||||
on "public"."posts"
|
||||
as permissive
|
||||
for insert
|
||||
to authenticated
|
||||
with check (is_blog_owner(blog_id, auth.uid()));
|
||||
|
||||
|
||||
|
||||
@@ -1,205 +0,0 @@
|
||||
drop policy "delete_categories_policy" on "public"."blog_tags";
|
||||
|
||||
drop policy "insert_categories_policy" on "public"."blog_tags";
|
||||
|
||||
drop policy "update_categories_policy" on "public"."blog_tags";
|
||||
|
||||
drop policy "owners of a blog can create invitations" on "public"."invitations";
|
||||
|
||||
drop policy "owners of a blog can delete invitations" on "public"."invitations";
|
||||
|
||||
drop policy "owners of the blog can see invitations" on "public"."invitations";
|
||||
|
||||
drop policy "Enable insert for authenticated users only" on "public"."post_tags";
|
||||
|
||||
drop policy "Enable read access for all users" on "public"."post_tags";
|
||||
|
||||
drop policy "delete_policy" on "public"."post_tags";
|
||||
|
||||
drop policy "users can crud their blogs" on "public"."blogs";
|
||||
|
||||
drop policy "update_post_tags" on "public"."post_tags";
|
||||
|
||||
drop policy "update_posts" on "public"."posts";
|
||||
|
||||
revoke delete on table "public"."invitations" from "anon";
|
||||
|
||||
revoke insert on table "public"."invitations" from "anon";
|
||||
|
||||
revoke references on table "public"."invitations" from "anon";
|
||||
|
||||
revoke select on table "public"."invitations" from "anon";
|
||||
|
||||
revoke trigger on table "public"."invitations" from "anon";
|
||||
|
||||
revoke truncate on table "public"."invitations" from "anon";
|
||||
|
||||
revoke update on table "public"."invitations" from "anon";
|
||||
|
||||
revoke delete on table "public"."invitations" from "authenticated";
|
||||
|
||||
revoke insert on table "public"."invitations" from "authenticated";
|
||||
|
||||
revoke references on table "public"."invitations" from "authenticated";
|
||||
|
||||
revoke select on table "public"."invitations" from "authenticated";
|
||||
|
||||
revoke trigger on table "public"."invitations" from "authenticated";
|
||||
|
||||
revoke truncate on table "public"."invitations" from "authenticated";
|
||||
|
||||
revoke update on table "public"."invitations" from "authenticated";
|
||||
|
||||
revoke delete on table "public"."invitations" from "service_role";
|
||||
|
||||
revoke insert on table "public"."invitations" from "service_role";
|
||||
|
||||
revoke references on table "public"."invitations" from "service_role";
|
||||
|
||||
revoke select on table "public"."invitations" from "service_role";
|
||||
|
||||
revoke trigger on table "public"."invitations" from "service_role";
|
||||
|
||||
revoke truncate on table "public"."invitations" from "service_role";
|
||||
|
||||
revoke update on table "public"."invitations" from "service_role";
|
||||
|
||||
alter table "public"."invitations" drop constraint "invitations_blog_id_fkey";
|
||||
|
||||
alter table "public"."posts" drop constraint "unique_slug_per_user_post_constraint";
|
||||
|
||||
drop view if exists "public"."posts_with_tags";
|
||||
|
||||
alter table "public"."invitations" drop constraint "invitations_pkey";
|
||||
|
||||
drop index if exists "public"."invitations_pkey";
|
||||
|
||||
drop index if exists "public"."unique_slug_per_user_post_constraint";
|
||||
|
||||
drop table "public"."invitations";
|
||||
|
||||
alter table "public"."blogs" alter column "user_id" drop default;
|
||||
|
||||
alter table "public"."blogs" alter column "user_id" set data type uuid using "user_id"::uuid;
|
||||
|
||||
alter table "public"."posts" drop column "deprecated_user_id";
|
||||
|
||||
CREATE UNIQUE INDEX unique_slug_per_user_blog_constraint ON public.posts USING btree (slug, user_id, blog_id);
|
||||
|
||||
alter table "public"."blogs" add constraint "fk_blogs_users" FOREIGN KEY (user_id) REFERENCES auth.users(id) not valid;
|
||||
|
||||
alter table "public"."blogs" validate constraint "fk_blogs_users";
|
||||
|
||||
alter table "public"."posts" add constraint "public_posts_user_id_fkey" FOREIGN KEY (user_id) REFERENCES auth.users(id) not valid;
|
||||
|
||||
alter table "public"."posts" validate constraint "public_posts_user_id_fkey";
|
||||
|
||||
set check_function_bodies = off;
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.is_blog_owner(blog_id uuid, given_user_id uuid)
|
||||
RETURNS boolean
|
||||
LANGUAGE plpgsql
|
||||
AS $function$
|
||||
BEGIN
|
||||
RETURN EXISTS (
|
||||
SELECT 1
|
||||
FROM public.blogs
|
||||
WHERE id = blog_id AND user_id = given_user_id
|
||||
);
|
||||
END;
|
||||
$function$
|
||||
;
|
||||
|
||||
create or replace view "public"."posts_with_tags" as SELECT p.created_at,
|
||||
p.blog_id,
|
||||
p.title,
|
||||
p.published,
|
||||
p.content,
|
||||
p.updated_at,
|
||||
p.slug,
|
||||
p.id AS post_id,
|
||||
p.cover_image,
|
||||
p.metadata,
|
||||
p.deleted,
|
||||
COALESCE(array_agg(bt.name) FILTER (WHERE (bt.id IS NOT NULL)), '{}'::text[]) AS tags
|
||||
FROM ((posts p
|
||||
LEFT JOIN post_tags pt ON ((p.id = pt.post_id)))
|
||||
LEFT JOIN blog_tags bt ON ((pt.tag_id = bt.id)))
|
||||
GROUP BY p.created_at, p.blog_id, p.title, p.published, p.content, p.updated_at, p.slug, p.id, p.cover_image, p.metadata, p.deleted, p.user_id
|
||||
ORDER BY p.created_at DESC;
|
||||
|
||||
|
||||
create policy "delete_tags"
|
||||
on "public"."blog_tags"
|
||||
as permissive
|
||||
for delete
|
||||
to public
|
||||
using (is_blog_owner(blog_id, auth.uid()));
|
||||
|
||||
|
||||
create policy "insert_tags"
|
||||
on "public"."blog_tags"
|
||||
as permissive
|
||||
for insert
|
||||
to public
|
||||
with check (is_blog_owner(blog_id, auth.uid()));
|
||||
|
||||
|
||||
create policy "update_tags"
|
||||
on "public"."blog_tags"
|
||||
as permissive
|
||||
for update
|
||||
to public
|
||||
using (is_blog_owner(blog_id, auth.uid()));
|
||||
|
||||
|
||||
create policy "delete_post_tag"
|
||||
on "public"."post_tags"
|
||||
as permissive
|
||||
for delete
|
||||
to authenticated
|
||||
using (is_blog_owner(blog_id, auth.uid()));
|
||||
|
||||
|
||||
create policy "insert_post_tag"
|
||||
on "public"."post_tags"
|
||||
as permissive
|
||||
for insert
|
||||
to authenticated
|
||||
with check (is_blog_owner(blog_id, auth.uid()));
|
||||
|
||||
|
||||
create policy "read_post_tags"
|
||||
on "public"."post_tags"
|
||||
as permissive
|
||||
for select
|
||||
to public
|
||||
using (true);
|
||||
|
||||
|
||||
create policy "users can crud their blogs"
|
||||
on "public"."blogs"
|
||||
as permissive
|
||||
for all
|
||||
to authenticated
|
||||
using ((auth.uid() = user_id));
|
||||
|
||||
|
||||
create policy "update_post_tags"
|
||||
on "public"."post_tags"
|
||||
as permissive
|
||||
for update
|
||||
to authenticated
|
||||
using (is_blog_owner(blog_id, auth.uid()))
|
||||
with check (true);
|
||||
|
||||
|
||||
create policy "update_posts"
|
||||
on "public"."posts"
|
||||
as permissive
|
||||
for update
|
||||
to authenticated
|
||||
using (is_blog_owner(blog_id, auth.uid()));
|
||||
|
||||
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
create or replace view "public"."posts_with_blog_and_subscription_status" as SELECT p.created_at,
|
||||
p.blog_id,
|
||||
p.title,
|
||||
p.published,
|
||||
p.content,
|
||||
p.updated_at,
|
||||
p.slug,
|
||||
p.id AS post_id,
|
||||
p.cover_image,
|
||||
p.metadata,
|
||||
p.deleted,
|
||||
COALESCE(array_agg(bt.name) FILTER (WHERE (bt.id IS NOT NULL)), '{}'::text[]) AS tags,
|
||||
t.owner_id,
|
||||
s.status AS subscription_status
|
||||
FROM (((((posts p
|
||||
LEFT JOIN blogs b ON ((p.blog_id = b.id)))
|
||||
LEFT JOIN teams t ON ((b.user_id = t.owner_id)))
|
||||
LEFT JOIN subscriptions s ON ((t.owner_id = s.user_id)))
|
||||
LEFT JOIN post_tags pt ON ((p.id = pt.post_id)))
|
||||
LEFT JOIN blog_tags bt ON ((pt.tag_id = bt.id)))
|
||||
GROUP BY p.created_at, p.blog_id, p.title, p.published, p.content, p.updated_at, p.slug, p.id, p.cover_image, p.metadata, p.deleted, p.user_id, t.owner_id, s.status
|
||||
ORDER BY p.created_at DESC;
|
||||
|
||||
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
alter table "public"."blogs" drop constraint "fk_blogs_users";
|
||||
|
||||
drop view if exists "public"."posts_with_blog_and_subscription_status";
|
||||
|
||||
alter table "public"."blogs" alter column "user_id" set default auth.uid();
|
||||
|
||||
alter table "public"."blogs" add constraint "blogs_user_id_fkey" FOREIGN KEY (user_id) REFERENCES auth.users(id) not valid;
|
||||
|
||||
alter table "public"."blogs" validate constraint "blogs_user_id_fkey";
|
||||
|
||||
create or replace view "public"."posts_with_blog_and_subscription_status" as SELECT p.created_at,
|
||||
p.blog_id,
|
||||
p.title,
|
||||
p.published,
|
||||
p.content,
|
||||
p.updated_at,
|
||||
p.slug,
|
||||
p.id AS post_id,
|
||||
p.cover_image,
|
||||
p.metadata,
|
||||
p.deleted,
|
||||
COALESCE(array_agg(bt.name) FILTER (WHERE (bt.id IS NOT NULL)), '{}'::text[]) AS tags,
|
||||
s.status AS subscription_status
|
||||
FROM ((((posts p
|
||||
LEFT JOIN blogs b ON ((p.blog_id = b.id)))
|
||||
LEFT JOIN subscriptions s ON ((b.user_id = s.user_id)))
|
||||
LEFT JOIN post_tags pt ON ((p.id = pt.post_id)))
|
||||
LEFT JOIN blog_tags bt ON ((pt.tag_id = bt.id)))
|
||||
GROUP BY p.created_at, p.blog_id, p.title, p.published, p.content, p.updated_at, p.slug, p.id, p.cover_image, p.metadata, p.deleted, p.user_id, s.status
|
||||
ORDER BY p.created_at DESC;
|
||||
|
||||
|
||||
|
||||
+214
-134
@@ -10,28 +10,14 @@ SET xmloption = content;
|
||||
SET client_min_messages = warning;
|
||||
SET row_security = off;
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS "timescaledb" WITH SCHEMA "extensions";
|
||||
CREATE SCHEMA IF NOT EXISTS "public";
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS "pg_net" WITH SCHEMA "extensions";
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS "pgsodium" WITH SCHEMA "pgsodium";
|
||||
ALTER SCHEMA "public" OWNER TO "pg_database_owner";
|
||||
|
||||
CREATE SCHEMA IF NOT EXISTS "stripe";
|
||||
|
||||
ALTER SCHEMA "stripe" OWNER TO "postgres";
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS "pg_graphql" WITH SCHEMA "graphql";
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS "pg_stat_statements" WITH SCHEMA "extensions";
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS "pgcrypto" WITH SCHEMA "extensions";
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS "pgjwt" WITH SCHEMA "extensions";
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS "supabase_vault" WITH SCHEMA "vault";
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp" WITH SCHEMA "extensions";
|
||||
|
||||
CREATE OR REPLACE FUNCTION "public"."generate_random_string"("length" integer) RETURNS "text"
|
||||
LANGUAGE "plpgsql"
|
||||
AS $$
|
||||
@@ -73,6 +59,20 @@ $$;
|
||||
|
||||
ALTER FUNCTION "public"."generate_slug"("title" "text") OWNER TO "postgres";
|
||||
|
||||
CREATE OR REPLACE FUNCTION "public"."is_blog_owner"("blog_id" "uuid", "given_user_id" "uuid") RETURNS boolean
|
||||
LANGUAGE "plpgsql"
|
||||
AS $$
|
||||
BEGIN
|
||||
RETURN EXISTS (
|
||||
SELECT 1
|
||||
FROM public.blogs
|
||||
WHERE id = blog_id AND user_id = given_user_id
|
||||
);
|
||||
END;
|
||||
$$;
|
||||
|
||||
ALTER FUNCTION "public"."is_blog_owner"("blog_id" "uuid", "given_user_id" "uuid") OWNER TO "postgres";
|
||||
|
||||
CREATE OR REPLACE FUNCTION "public"."requesting_user_id"() RETURNS "text"
|
||||
LANGUAGE "sql" STABLE
|
||||
AS $$
|
||||
@@ -85,46 +85,30 @@ SET default_tablespace = '';
|
||||
|
||||
SET default_table_access_method = "heap";
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "public"."admin_users" (
|
||||
"id" bigint NOT NULL,
|
||||
CREATE TABLE IF NOT EXISTS "public"."blog_tags" (
|
||||
"id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL,
|
||||
"blog_id" "uuid" NOT NULL,
|
||||
"name" "text" NOT NULL,
|
||||
"slug" "text" NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT "now"() NOT NULL,
|
||||
"user_id" "uuid"
|
||||
"updated_at" timestamp with time zone DEFAULT "now"() NOT NULL,
|
||||
"description" "text"
|
||||
);
|
||||
|
||||
ALTER TABLE "public"."admin_users" OWNER TO "postgres";
|
||||
|
||||
ALTER TABLE "public"."admin_users" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY (
|
||||
SEQUENCE NAME "public"."admin_users_id_seq"
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1
|
||||
);
|
||||
ALTER TABLE "public"."blog_tags" OWNER TO "postgres";
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "public"."blogs" (
|
||||
"id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT "now"() NOT NULL,
|
||||
"title" "text" NOT NULL,
|
||||
"emoji" "text" NOT NULL,
|
||||
"user_id" "text" DEFAULT "public"."requesting_user_id"() NOT NULL,
|
||||
"user_id" "uuid" DEFAULT "auth"."uid"() NOT NULL,
|
||||
"description" "text",
|
||||
"public_id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL
|
||||
);
|
||||
|
||||
ALTER TABLE "public"."blogs" OWNER TO "postgres";
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "public"."categories" (
|
||||
"id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL,
|
||||
"blog_id" "uuid" NOT NULL,
|
||||
"name" "text" NOT NULL,
|
||||
"slug" "text" NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT "now"() NOT NULL,
|
||||
"updated_at" timestamp with time zone DEFAULT "now"() NOT NULL
|
||||
);
|
||||
|
||||
ALTER TABLE "public"."categories" OWNER TO "postgres";
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "public"."feedback" (
|
||||
"id" bigint NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT "now"() NOT NULL,
|
||||
@@ -161,19 +145,28 @@ ALTER TABLE "public"."homepage_signup" ALTER COLUMN "id" ADD GENERATED BY DEFAUL
|
||||
CACHE 1
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "public"."invitations" (
|
||||
CREATE TABLE IF NOT EXISTS "public"."post_tags" (
|
||||
"id" bigint NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT "now"() NOT NULL,
|
||||
"blog_id" "uuid" NOT NULL,
|
||||
"email" "text" NOT NULL,
|
||||
"name" "text" NOT NULL,
|
||||
"id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL
|
||||
"post_id" "uuid" NOT NULL,
|
||||
"tag_id" "uuid" NOT NULL,
|
||||
"blog_id" "uuid" NOT NULL
|
||||
);
|
||||
|
||||
ALTER TABLE "public"."invitations" OWNER TO "postgres";
|
||||
ALTER TABLE "public"."post_tags" OWNER TO "postgres";
|
||||
|
||||
ALTER TABLE "public"."post_tags" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY (
|
||||
SEQUENCE NAME "public"."post_tags_id_seq"
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "public"."posts" (
|
||||
"created_at" timestamp with time zone DEFAULT "now"() NOT NULL,
|
||||
"user_id" "text" DEFAULT "public"."requesting_user_id"() NOT NULL,
|
||||
"user_id" "uuid" DEFAULT "auth"."uid"() NOT NULL,
|
||||
"blog_id" "uuid" NOT NULL,
|
||||
"title" "text" NOT NULL,
|
||||
"published" boolean DEFAULT false NOT NULL,
|
||||
@@ -182,16 +175,91 @@ CREATE TABLE IF NOT EXISTS "public"."posts" (
|
||||
"slug" "text" NOT NULL,
|
||||
"id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL,
|
||||
"cover_image" "text",
|
||||
"metadata" "jsonb"[]
|
||||
"metadata" "jsonb"[],
|
||||
"deleted" boolean DEFAULT false NOT NULL,
|
||||
"published_at" timestamp with time zone DEFAULT "now"()
|
||||
);
|
||||
|
||||
ALTER TABLE "public"."posts" OWNER TO "postgres";
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "public"."subscriptions" (
|
||||
"created_at" timestamp with time zone DEFAULT "now"() NOT NULL,
|
||||
"user_id" "uuid" NOT NULL,
|
||||
"status" "text" NOT NULL,
|
||||
"stripe_subscription_id" "text" NOT NULL,
|
||||
"subscription" "jsonb" NOT NULL
|
||||
);
|
||||
|
||||
ALTER TABLE "public"."subscriptions" OWNER TO "postgres";
|
||||
|
||||
CREATE OR REPLACE VIEW "public"."posts_with_blog_and_subscription_status" AS
|
||||
SELECT "p"."created_at",
|
||||
"p"."blog_id",
|
||||
"p"."title",
|
||||
"p"."published",
|
||||
"p"."content",
|
||||
"p"."updated_at",
|
||||
"p"."slug",
|
||||
"p"."id" AS "post_id",
|
||||
"p"."cover_image",
|
||||
"p"."metadata",
|
||||
"p"."deleted",
|
||||
COALESCE("array_agg"("bt"."name") FILTER (WHERE ("bt"."id" IS NOT NULL)), '{}'::"text"[]) AS "tags",
|
||||
"s"."status" AS "subscription_status"
|
||||
FROM (((("public"."posts" "p"
|
||||
LEFT JOIN "public"."blogs" "b" ON (("p"."blog_id" = "b"."id")))
|
||||
LEFT JOIN "public"."subscriptions" "s" ON (("b"."user_id" = "s"."user_id")))
|
||||
LEFT JOIN "public"."post_tags" "pt" ON (("p"."id" = "pt"."post_id")))
|
||||
LEFT JOIN "public"."blog_tags" "bt" ON (("pt"."tag_id" = "bt"."id")))
|
||||
GROUP BY "p"."created_at", "p"."blog_id", "p"."title", "p"."published", "p"."content", "p"."updated_at", "p"."slug", "p"."id", "p"."cover_image", "p"."metadata", "p"."deleted", "p"."user_id", "s"."status"
|
||||
ORDER BY "p"."created_at" DESC;
|
||||
|
||||
ALTER TABLE "public"."posts_with_blog_and_subscription_status" OWNER TO "postgres";
|
||||
|
||||
CREATE OR REPLACE VIEW "public"."posts_with_tags" AS
|
||||
SELECT "p"."created_at",
|
||||
"p"."blog_id",
|
||||
"p"."title",
|
||||
"p"."published",
|
||||
"p"."content",
|
||||
"p"."updated_at",
|
||||
"p"."slug",
|
||||
"p"."id" AS "post_id",
|
||||
"p"."cover_image",
|
||||
"p"."metadata",
|
||||
"p"."deleted",
|
||||
COALESCE("array_agg"("bt"."name") FILTER (WHERE ("bt"."id" IS NOT NULL)), '{}'::"text"[]) AS "tags"
|
||||
FROM (("public"."posts" "p"
|
||||
LEFT JOIN "public"."post_tags" "pt" ON (("p"."id" = "pt"."post_id")))
|
||||
LEFT JOIN "public"."blog_tags" "bt" ON (("pt"."tag_id" = "bt"."id")))
|
||||
GROUP BY "p"."created_at", "p"."blog_id", "p"."title", "p"."published", "p"."content", "p"."updated_at", "p"."slug", "p"."id", "p"."cover_image", "p"."metadata", "p"."deleted", "p"."user_id"
|
||||
ORDER BY "p"."created_at" DESC;
|
||||
|
||||
ALTER TABLE "public"."posts_with_tags" OWNER TO "postgres";
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "public"."prices" (
|
||||
"id" bigint NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT "now"() NOT NULL,
|
||||
"price" "jsonb" NOT NULL,
|
||||
"stripe_price_id" "text" NOT NULL
|
||||
);
|
||||
|
||||
ALTER TABLE "public"."prices" OWNER TO "postgres";
|
||||
|
||||
ALTER TABLE "public"."prices" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY (
|
||||
SEQUENCE NAME "public"."prices_id_seq"
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "public"."products" (
|
||||
"id" bigint NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT "now"() NOT NULL,
|
||||
"product" "jsonb" NOT NULL,
|
||||
"stripe_product_id" "text"
|
||||
"stripe_product_id" "text" NOT NULL
|
||||
);
|
||||
|
||||
ALTER TABLE "public"."products" OWNER TO "postgres";
|
||||
@@ -205,14 +273,6 @@ ALTER TABLE "public"."products" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS ID
|
||||
CACHE 1
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "public"."subscriptions" (
|
||||
"created_at" timestamp with time zone DEFAULT "now"() NOT NULL,
|
||||
"user_id" "uuid" NOT NULL,
|
||||
"status" "text" NOT NULL
|
||||
);
|
||||
|
||||
ALTER TABLE "public"."subscriptions" OWNER TO "postgres";
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "public"."teams" (
|
||||
"created_at" timestamp with time zone DEFAULT "now"() NOT NULL,
|
||||
"owner_id" "uuid",
|
||||
@@ -271,16 +331,13 @@ CREATE OR REPLACE VIEW "public"."users" AS
|
||||
|
||||
ALTER TABLE "public"."users" OWNER TO "postgres";
|
||||
|
||||
ALTER TABLE ONLY "public"."admin_users"
|
||||
ADD CONSTRAINT "admin_users_pkey" PRIMARY KEY ("id");
|
||||
|
||||
ALTER TABLE ONLY "public"."blogs"
|
||||
ADD CONSTRAINT "blogs_pkey" PRIMARY KEY ("id");
|
||||
|
||||
ALTER TABLE ONLY "public"."categories"
|
||||
ALTER TABLE ONLY "public"."blog_tags"
|
||||
ADD CONSTRAINT "categories_blog_id_slug_key" UNIQUE ("blog_id", "slug");
|
||||
|
||||
ALTER TABLE ONLY "public"."categories"
|
||||
ALTER TABLE ONLY "public"."blog_tags"
|
||||
ADD CONSTRAINT "categories_pkey" PRIMARY KEY ("id");
|
||||
|
||||
ALTER TABLE ONLY "public"."feedback"
|
||||
@@ -289,17 +346,29 @@ ALTER TABLE ONLY "public"."feedback"
|
||||
ALTER TABLE ONLY "public"."homepage_signup"
|
||||
ADD CONSTRAINT "homepage_signup_pkey" PRIMARY KEY ("id");
|
||||
|
||||
ALTER TABLE ONLY "public"."invitations"
|
||||
ADD CONSTRAINT "invitations_pkey" PRIMARY KEY ("id");
|
||||
ALTER TABLE ONLY "public"."post_tags"
|
||||
ADD CONSTRAINT "post_categories_pkey" PRIMARY KEY ("id");
|
||||
|
||||
ALTER TABLE ONLY "public"."posts"
|
||||
ADD CONSTRAINT "posts_pkey" PRIMARY KEY ("id");
|
||||
|
||||
ALTER TABLE ONLY "public"."prices"
|
||||
ADD CONSTRAINT "prices_pkey" PRIMARY KEY ("id", "stripe_price_id");
|
||||
|
||||
ALTER TABLE ONLY "public"."prices"
|
||||
ADD CONSTRAINT "prices_stripe_price_id_key" UNIQUE ("stripe_price_id");
|
||||
|
||||
ALTER TABLE ONLY "public"."products"
|
||||
ADD CONSTRAINT "products_pkey" PRIMARY KEY ("id");
|
||||
ADD CONSTRAINT "products_pkey" PRIMARY KEY ("id", "stripe_product_id");
|
||||
|
||||
ALTER TABLE ONLY "public"."products"
|
||||
ADD CONSTRAINT "products_stripe_product_id_key" UNIQUE ("stripe_product_id");
|
||||
|
||||
ALTER TABLE ONLY "public"."subscriptions"
|
||||
ADD CONSTRAINT "subscriptions_pkey" PRIMARY KEY ("user_id");
|
||||
ADD CONSTRAINT "subscriptions_pkey" PRIMARY KEY ("stripe_subscription_id");
|
||||
|
||||
ALTER TABLE ONLY "public"."subscriptions"
|
||||
ADD CONSTRAINT "subscriptions_stripe_subscription_id_key" UNIQUE ("stripe_subscription_id");
|
||||
|
||||
ALTER TABLE ONLY "public"."subscriptions"
|
||||
ADD CONSTRAINT "subscriptions_user_id_key" UNIQUE ("user_id");
|
||||
@@ -313,106 +382,101 @@ ALTER TABLE ONLY "public"."teams"
|
||||
ALTER TABLE ONLY "public"."teams"
|
||||
ADD CONSTRAINT "teams_ref_key" UNIQUE ("ref");
|
||||
|
||||
ALTER TABLE ONLY "public"."posts"
|
||||
ADD CONSTRAINT "unique_slug_per_user_post_constraint" UNIQUE ("slug", "user_id", "blog_id");
|
||||
ALTER TABLE ONLY "public"."post_tags"
|
||||
ADD CONSTRAINT "unique_post_tag_blog_combination" UNIQUE ("post_id", "tag_id", "blog_id");
|
||||
|
||||
CREATE INDEX "posts_slug_blog_id_idx" ON "public"."posts" USING "btree" ("slug", "blog_id");
|
||||
|
||||
CREATE INDEX "posts_slug_idx" ON "public"."posts" USING "btree" ("slug");
|
||||
|
||||
ALTER TABLE ONLY "public"."admin_users"
|
||||
ADD CONSTRAINT "admin_users_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "auth"."users"("id");
|
||||
CREATE UNIQUE INDEX "unique_slug_per_user_blog_constraint" ON "public"."posts" USING "btree" ("slug", "user_id", "blog_id");
|
||||
|
||||
ALTER TABLE ONLY "public"."categories"
|
||||
ADD CONSTRAINT "categories_blog_id_fkey" FOREIGN KEY ("blog_id") REFERENCES "public"."blogs"("id") ON DELETE CASCADE;
|
||||
ALTER TABLE ONLY "public"."blog_tags"
|
||||
ADD CONSTRAINT "blog_tags_blog_id_fkey" FOREIGN KEY ("blog_id") REFERENCES "public"."blogs"("id") ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY "public"."invitations"
|
||||
ADD CONSTRAINT "invitations_blog_id_fkey" FOREIGN KEY ("blog_id") REFERENCES "public"."blogs"("id");
|
||||
ALTER TABLE ONLY "public"."blogs"
|
||||
ADD CONSTRAINT "blogs_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "auth"."users"("id");
|
||||
|
||||
ALTER TABLE ONLY "public"."post_tags"
|
||||
ADD CONSTRAINT "post_tags_blog_id_fkey" FOREIGN KEY ("blog_id") REFERENCES "public"."blogs"("id");
|
||||
|
||||
ALTER TABLE ONLY "public"."post_tags"
|
||||
ADD CONSTRAINT "post_tags_post_id_fkey" FOREIGN KEY ("post_id") REFERENCES "public"."posts"("id");
|
||||
|
||||
ALTER TABLE ONLY "public"."post_tags"
|
||||
ADD CONSTRAINT "post_tags_tag_id_fkey" FOREIGN KEY ("tag_id") REFERENCES "public"."blog_tags"("id");
|
||||
|
||||
ALTER TABLE ONLY "public"."posts"
|
||||
ADD CONSTRAINT "posts_blog_id_fkey" FOREIGN KEY ("blog_id") REFERENCES "public"."blogs"("id") ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY "public"."posts"
|
||||
ADD CONSTRAINT "public_posts_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "auth"."users"("id");
|
||||
|
||||
ALTER TABLE ONLY "public"."teams"
|
||||
ADD CONSTRAINT "public_teams_owner_id_fkey" FOREIGN KEY ("owner_id") REFERENCES "auth"."users"("id");
|
||||
|
||||
ALTER TABLE ONLY "public"."subscriptions"
|
||||
ADD CONSTRAINT "subscriptions_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "auth"."users"("id");
|
||||
|
||||
CREATE POLICY "Allow AUTHED users to query ALL their POSTS" ON "public"."posts" FOR SELECT TO "authenticated" USING ((("auth"."uid"())::"text" = "user_id"));
|
||||
|
||||
CREATE POLICY "Enable INSERT access for all users" ON "public"."homepage_signup" FOR INSERT TO "anon" WITH CHECK (true);
|
||||
|
||||
CREATE POLICY "Enable delete for users based on user_id" ON "public"."posts" FOR DELETE USING ((("auth"."uid"())::"text" = "user_id"));
|
||||
|
||||
CREATE POLICY "Enable insert for authenticated users only" ON "public"."feedback" FOR INSERT TO "authenticated" WITH CHECK (true);
|
||||
|
||||
CREATE POLICY "Enable insert for authenticated users only" ON "public"."posts" FOR INSERT TO "authenticated" WITH CHECK ((("auth"."uid"())::"text" = "user_id"));
|
||||
|
||||
CREATE POLICY "Enable insert for owners" ON "public"."teams" FOR INSERT TO "authenticated" WITH CHECK (("auth"."uid"() = "owner_id"));
|
||||
|
||||
CREATE POLICY "Enable read access for all users" ON "public"."prices" FOR SELECT USING (true);
|
||||
|
||||
CREATE POLICY "Enable read access for all users" ON "public"."products" FOR SELECT USING (true);
|
||||
|
||||
CREATE POLICY "Enable read access for all users" ON "public"."teams" FOR SELECT USING (true);
|
||||
|
||||
CREATE POLICY "Enable read access for all users if published" ON "public"."posts" FOR SELECT TO "anon" USING (("published" = true));
|
||||
CREATE POLICY "authed_read_posts" ON "public"."posts" FOR SELECT TO "authenticated" USING ("public"."is_blog_owner"("blog_id", "auth"."uid"()));
|
||||
|
||||
CREATE POLICY "Enable update for users based on user_id" ON "public"."posts" FOR UPDATE USING ((("auth"."uid"())::"text" = "user_id"));
|
||||
|
||||
ALTER TABLE "public"."admin_users" ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE "public"."blog_tags" ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
ALTER TABLE "public"."blogs" ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
ALTER TABLE "public"."categories" ENABLE ROW LEVEL SECURITY;
|
||||
CREATE POLICY "delete_post_tag" ON "public"."post_tags" FOR DELETE TO "authenticated" USING ("public"."is_blog_owner"("blog_id", "auth"."uid"()));
|
||||
|
||||
CREATE POLICY "delete_categories_policy" ON "public"."categories" FOR DELETE USING ((EXISTS ( SELECT 1
|
||||
FROM "public"."blogs"
|
||||
WHERE (("blogs"."id" = "categories"."blog_id") AND ("blogs"."user_id" = CURRENT_USER)))));
|
||||
CREATE POLICY "delete_tags" ON "public"."blog_tags" FOR DELETE USING ("public"."is_blog_owner"("blog_id", "auth"."uid"()));
|
||||
|
||||
ALTER TABLE "public"."feedback" ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
ALTER TABLE "public"."homepage_signup" ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
CREATE POLICY "insert_categories_policy" ON "public"."categories" FOR INSERT WITH CHECK ((EXISTS ( SELECT 1
|
||||
FROM "public"."blogs"
|
||||
WHERE (("blogs"."id" = "categories"."blog_id") AND ("blogs"."user_id" = CURRENT_USER)))));
|
||||
CREATE POLICY "insert_post_tag" ON "public"."post_tags" FOR INSERT TO "authenticated" WITH CHECK ("public"."is_blog_owner"("blog_id", "auth"."uid"()));
|
||||
|
||||
ALTER TABLE "public"."invitations" ENABLE ROW LEVEL SECURITY;
|
||||
CREATE POLICY "insert_posts" ON "public"."posts" FOR INSERT TO "authenticated" WITH CHECK ("public"."is_blog_owner"("blog_id", "auth"."uid"()));
|
||||
|
||||
CREATE POLICY "owners of a blog can create invitations" ON "public"."invitations" FOR INSERT TO "authenticated" WITH CHECK ((EXISTS ( SELECT 1
|
||||
FROM "public"."blogs"
|
||||
WHERE (("blogs"."id" = "invitations"."blog_id") AND ("blogs"."user_id" = "public"."requesting_user_id"())))));
|
||||
CREATE POLICY "insert_tags" ON "public"."blog_tags" FOR INSERT WITH CHECK ("public"."is_blog_owner"("blog_id", "auth"."uid"()));
|
||||
|
||||
CREATE POLICY "owners of a blog can delete invitations" ON "public"."invitations" FOR DELETE TO "authenticated" USING ((EXISTS ( SELECT 1
|
||||
FROM "public"."blogs"
|
||||
WHERE (("blogs"."id" = "invitations"."blog_id") AND ("blogs"."user_id" = "public"."requesting_user_id"())))));
|
||||
|
||||
CREATE POLICY "owners of the blog can see invitations" ON "public"."invitations" FOR SELECT TO "authenticated" USING ((EXISTS ( SELECT "blogs"."id",
|
||||
"blogs"."created_at",
|
||||
"blogs"."title",
|
||||
"blogs"."emoji",
|
||||
"blogs"."user_id",
|
||||
"blogs"."description",
|
||||
"blogs"."public_id"
|
||||
FROM "public"."blogs"
|
||||
WHERE (("blogs"."id" = "invitations"."blog_id") AND ("blogs"."user_id" = "public"."requesting_user_id"())))));
|
||||
ALTER TABLE "public"."post_tags" ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
ALTER TABLE "public"."posts" ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
ALTER TABLE "public"."prices" ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
ALTER TABLE "public"."products" ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
CREATE POLICY "read_post_tags" ON "public"."post_tags" FOR SELECT USING (true);
|
||||
|
||||
CREATE POLICY "read_posts" ON "public"."posts" FOR SELECT TO "anon" USING ((("published" = true) AND ("deleted" = false)));
|
||||
|
||||
CREATE POLICY "select subscription" ON "public"."subscriptions" FOR SELECT TO "authenticated" USING (("auth"."uid"() = "user_id"));
|
||||
|
||||
CREATE POLICY "select_categories_policy" ON "public"."categories" FOR SELECT USING ((EXISTS ( SELECT 1
|
||||
FROM "public"."blogs"
|
||||
WHERE (("blogs"."id" = "categories"."blog_id") AND ("blogs"."user_id" = CURRENT_USER)))));
|
||||
CREATE POLICY "select_categories_policy" ON "public"."blog_tags" FOR SELECT USING (true);
|
||||
|
||||
ALTER TABLE "public"."subscriptions" ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
ALTER TABLE "public"."teams" ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
CREATE POLICY "update_categories_policy" ON "public"."categories" FOR UPDATE USING ((EXISTS ( SELECT 1
|
||||
FROM "public"."blogs"
|
||||
WHERE (("blogs"."id" = "categories"."blog_id") AND ("blogs"."user_id" = CURRENT_USER)))));
|
||||
CREATE POLICY "update_post_tags" ON "public"."post_tags" FOR UPDATE TO "authenticated" USING ("public"."is_blog_owner"("blog_id", "auth"."uid"())) WITH CHECK (true);
|
||||
|
||||
CREATE POLICY "users can crud their blogs" ON "public"."blogs" TO "authenticated" USING ((("auth"."uid"())::"text" = "user_id"));
|
||||
CREATE POLICY "update_posts" ON "public"."posts" FOR UPDATE TO "authenticated" USING ("public"."is_blog_owner"("blog_id", "auth"."uid"()));
|
||||
|
||||
CREATE POLICY "update_tags" ON "public"."blog_tags" FOR UPDATE USING ("public"."is_blog_owner"("blog_id", "auth"."uid"()));
|
||||
|
||||
CREATE POLICY "users can crud their blogs" ON "public"."blogs" TO "authenticated" USING (("auth"."uid"() = "user_id"));
|
||||
|
||||
REVOKE USAGE ON SCHEMA "public" FROM PUBLIC;
|
||||
GRANT USAGE ON SCHEMA "public" TO "postgres";
|
||||
@@ -428,26 +492,22 @@ GRANT ALL ON FUNCTION "public"."generate_slug"("title" "text") TO "anon";
|
||||
GRANT ALL ON FUNCTION "public"."generate_slug"("title" "text") TO "authenticated";
|
||||
GRANT ALL ON FUNCTION "public"."generate_slug"("title" "text") TO "service_role";
|
||||
|
||||
GRANT ALL ON FUNCTION "public"."is_blog_owner"("blog_id" "uuid", "given_user_id" "uuid") TO "anon";
|
||||
GRANT ALL ON FUNCTION "public"."is_blog_owner"("blog_id" "uuid", "given_user_id" "uuid") TO "authenticated";
|
||||
GRANT ALL ON FUNCTION "public"."is_blog_owner"("blog_id" "uuid", "given_user_id" "uuid") TO "service_role";
|
||||
|
||||
GRANT ALL ON FUNCTION "public"."requesting_user_id"() TO "anon";
|
||||
GRANT ALL ON FUNCTION "public"."requesting_user_id"() TO "authenticated";
|
||||
GRANT ALL ON FUNCTION "public"."requesting_user_id"() TO "service_role";
|
||||
|
||||
GRANT ALL ON TABLE "public"."admin_users" TO "anon";
|
||||
GRANT ALL ON TABLE "public"."admin_users" TO "authenticated";
|
||||
GRANT ALL ON TABLE "public"."admin_users" TO "service_role";
|
||||
|
||||
GRANT ALL ON SEQUENCE "public"."admin_users_id_seq" TO "anon";
|
||||
GRANT ALL ON SEQUENCE "public"."admin_users_id_seq" TO "authenticated";
|
||||
GRANT ALL ON SEQUENCE "public"."admin_users_id_seq" TO "service_role";
|
||||
GRANT ALL ON TABLE "public"."blog_tags" TO "anon";
|
||||
GRANT ALL ON TABLE "public"."blog_tags" TO "authenticated";
|
||||
GRANT ALL ON TABLE "public"."blog_tags" TO "service_role";
|
||||
|
||||
GRANT ALL ON TABLE "public"."blogs" TO "anon";
|
||||
GRANT ALL ON TABLE "public"."blogs" TO "authenticated";
|
||||
GRANT ALL ON TABLE "public"."blogs" TO "service_role";
|
||||
|
||||
GRANT ALL ON TABLE "public"."categories" TO "anon";
|
||||
GRANT ALL ON TABLE "public"."categories" TO "authenticated";
|
||||
GRANT ALL ON TABLE "public"."categories" TO "service_role";
|
||||
|
||||
GRANT ALL ON TABLE "public"."feedback" TO "anon";
|
||||
GRANT ALL ON TABLE "public"."feedback" TO "authenticated";
|
||||
GRANT ALL ON TABLE "public"."feedback" TO "service_role";
|
||||
@@ -464,14 +524,38 @@ GRANT ALL ON SEQUENCE "public"."homepage_signup_id_seq" TO "anon";
|
||||
GRANT ALL ON SEQUENCE "public"."homepage_signup_id_seq" TO "authenticated";
|
||||
GRANT ALL ON SEQUENCE "public"."homepage_signup_id_seq" TO "service_role";
|
||||
|
||||
GRANT ALL ON TABLE "public"."invitations" TO "anon";
|
||||
GRANT ALL ON TABLE "public"."invitations" TO "authenticated";
|
||||
GRANT ALL ON TABLE "public"."invitations" TO "service_role";
|
||||
GRANT ALL ON TABLE "public"."post_tags" TO "anon";
|
||||
GRANT ALL ON TABLE "public"."post_tags" TO "authenticated";
|
||||
GRANT ALL ON TABLE "public"."post_tags" TO "service_role";
|
||||
|
||||
GRANT ALL ON SEQUENCE "public"."post_tags_id_seq" TO "anon";
|
||||
GRANT ALL ON SEQUENCE "public"."post_tags_id_seq" TO "authenticated";
|
||||
GRANT ALL ON SEQUENCE "public"."post_tags_id_seq" TO "service_role";
|
||||
|
||||
GRANT ALL ON TABLE "public"."posts" TO "anon";
|
||||
GRANT ALL ON TABLE "public"."posts" TO "authenticated";
|
||||
GRANT ALL ON TABLE "public"."posts" TO "service_role";
|
||||
|
||||
GRANT ALL ON TABLE "public"."subscriptions" TO "anon";
|
||||
GRANT ALL ON TABLE "public"."subscriptions" TO "authenticated";
|
||||
GRANT ALL ON TABLE "public"."subscriptions" TO "service_role";
|
||||
|
||||
GRANT ALL ON TABLE "public"."posts_with_blog_and_subscription_status" TO "anon";
|
||||
GRANT ALL ON TABLE "public"."posts_with_blog_and_subscription_status" TO "authenticated";
|
||||
GRANT ALL ON TABLE "public"."posts_with_blog_and_subscription_status" TO "service_role";
|
||||
|
||||
GRANT ALL ON TABLE "public"."posts_with_tags" TO "anon";
|
||||
GRANT ALL ON TABLE "public"."posts_with_tags" TO "authenticated";
|
||||
GRANT ALL ON TABLE "public"."posts_with_tags" TO "service_role";
|
||||
|
||||
GRANT ALL ON TABLE "public"."prices" TO "anon";
|
||||
GRANT ALL ON TABLE "public"."prices" TO "authenticated";
|
||||
GRANT ALL ON TABLE "public"."prices" TO "service_role";
|
||||
|
||||
GRANT ALL ON SEQUENCE "public"."prices_id_seq" TO "anon";
|
||||
GRANT ALL ON SEQUENCE "public"."prices_id_seq" TO "authenticated";
|
||||
GRANT ALL ON SEQUENCE "public"."prices_id_seq" TO "service_role";
|
||||
|
||||
GRANT ALL ON TABLE "public"."products" TO "anon";
|
||||
GRANT ALL ON TABLE "public"."products" TO "authenticated";
|
||||
GRANT ALL ON TABLE "public"."products" TO "service_role";
|
||||
@@ -480,10 +564,6 @@ GRANT ALL ON SEQUENCE "public"."products_id_seq" TO "anon";
|
||||
GRANT ALL ON SEQUENCE "public"."products_id_seq" TO "authenticated";
|
||||
GRANT ALL ON SEQUENCE "public"."products_id_seq" TO "service_role";
|
||||
|
||||
GRANT ALL ON TABLE "public"."subscriptions" TO "anon";
|
||||
GRANT ALL ON TABLE "public"."subscriptions" TO "authenticated";
|
||||
GRANT ALL ON TABLE "public"."subscriptions" TO "service_role";
|
||||
|
||||
GRANT ALL ON TABLE "public"."teams" TO "anon";
|
||||
GRANT ALL ON TABLE "public"."teams" TO "authenticated";
|
||||
GRANT ALL ON TABLE "public"."teams" TO "service_role";
|
||||
+3
-1
@@ -2,8 +2,9 @@
|
||||
|
||||
## General
|
||||
|
||||
- [] bug when adding a second tag to a post
|
||||
- [x] License
|
||||
- [] FAQ on homepage
|
||||
- [] FAQ on homepage?
|
||||
- [] Update README
|
||||
- [] Homepage use cases examples: personal blog, docs, careers page, product listing pages, help center, changelogs, directory websites, etc.
|
||||
- [] email provider
|
||||
@@ -45,6 +46,7 @@
|
||||
|
||||
## Posts
|
||||
|
||||
- [] When uploading an image, it would be nice if you could rename it before uploading.
|
||||
- [] See "published at" and "updated at" dates in post list
|
||||
- [] change published date in post settings
|
||||
- [x] View all posts
|
||||
|
||||
Reference in New Issue
Block a user