diff --git a/README.md b/README.md index 5abd26fe..aeacc705 100644 --- a/README.md +++ b/README.md @@ -8,18 +8,21 @@ - [Environments and Variables](#environments-and-variables) - [Auth0 (deprecated)](#auth0-deprecated) - [Vercel](#vercel) - - [Vercel Environment Variables](#vercel-environment-variables) - - [API Routes](#api-routes) + - [Vercel Environment Variables](#vercel-environment-variables) + - [API Routes /v3](#api-routes-v3) + - [](#) - [API Authorization](#api-authorization) + - [Supabase](#supabase) + - [Auth0 (deprecated)](#auth0-deprecated-1) - [Tests](#tests) - - [Supabase](#supabase) + - [Supabase](#supabase-1) - [Migrations and Types](#migrations-and-types) - [Deployment](#deployment) - [Radolan Harvester](#radolan-harvester) - - [API Routes](#api-routes-1) + - [API Routes](#api-routes) - [API Authorization](#api-authorization-1) - - [Supabase](#supabase-1) - - [Auth0 (deprecated)](#auth0-deprecated-1) + - [Supabase](#supabase-2) + - [Auth0 (deprecated)](#auth0-deprecated-2) - [Tests](#tests-1) - [Contributors ✨](#contributors-) - [Credits](#credits) @@ -106,9 +109,10 @@ vercel env add SUPABASE_ANON_KEY # the max rows allowed to fetch from supabase (default 1000) vercel env add SUPABASE_MAX_ROWS # below are all taken from auth0.com -vercel env add jwksuri -vercel env add audience -vercel env add issuer +# the v3 api does not need them anymore +# vercel env add jwksuri +# vercel env add audience +# vercel env add issuer ``` To let these variables take effect you need to deploy your application once more. @@ -117,9 +121,9 @@ To let these variables take effect you need to deploy your application once more vercel --prod ``` -## API Routes +## API Routes /v3 -There are 3 main routes `/get`, `/post` and `/delete`. +There are 3 main routes `/v3/get`, `/v3/post` and `/v3/delete`. On the `/get` route all actions are controlled by passing URL params. On the `/post` and `/delete` route you will have to work with additional POST bodies. For example to fetch a specific tree run the following command. @@ -133,20 +137,48 @@ You can see all the available routes in the [docs/api.http](./docs/api.http) fil Currently we have these routes -| `/get` | `/post` | `/delete` | -| -------------------- | -------- | ---------- | -| `/byid` | `/adopt` | `/unadopt` | -| `/treesbyids` | `/water` | `/unwater` | -| `/adopted` | | | -| `/istreeadopted` | | | -| `/wateredandadopted` | | | -| `/lastwatered` | | | -| `/wateredbyuser` | | | +| `/v3/get` | `/v3/post` | `/v3/delete` | +| :------------------- | :--------- | :----------- | +| `/byid` | `/adopt` | `/unadopt` | +| `/treesbyids` | `/water` | `/unwater` | +| `/adopted` | | | +| `/istreeadopted` | | | +| `/wateredandadopted` | | | +| `/lastwatered` | | | +| `/wateredbyuser` | | | + +### ### API Authorization Some of the request will need an authorization header. You can obtain a token by making a request to your auth0 token issuer. +### Supabase + +You can sign up with the request below. You will get an access token to use in your requests. + +```bash +curl --request POST \ + --url http://localhost:54321/auth/v1/signup \ + --header 'apikey: ' \ + --header 'content-type: application/json' \ + --header 'user-agent: vscode-restclient' \ + --data '{"email": "someone@email.com","password": "1234567890"}' +``` + +```bash +curl --request POST \ + --url http://localhost:8080/post/adopt \ + --header 'authorization: Bearer ' \ + --header 'content-type: application/json' \ + --data '{"tree_id":"_01","uuid": ""}' + +``` + +The user id will be removed in future versions since the supabase SDK can get the user id from the access token and each token is bound to a specific user. + +#### Auth0 (deprecated) + ```bash curl --request POST \ --url https://your-tenant.eu.auth0.com/oauth/token \ @@ -159,10 +191,10 @@ This will respond with an `access_token`. Use it to make authenticated requests. ```bash curl --request POST \ - --url http://localhost:3000/post \ + --url http://localhost:8080/post/adopt \ --header 'authorization: Bearer ' \ --header 'content-type: application/json' \ - --data '{"queryType":"adopt","tree_id":"_01","uuid": "auth0|123"}' + --data '{"tree_id":"_01","uuid": "auth0|123"}' ``` Take a look into [docs/api.http](./docs/api.http). The requests in this file can be run with the VSCode extension [REST Client](https://marketplace.visualstudio.com/items?itemName=humao.rest-client). @@ -237,7 +269,7 @@ On the `/get` route all actions are controlled by passing URL params. On the `/p ```bash curl --request GET \ - --url 'http://localhost:3000/get/byid&id=_123456789' \ + --url 'http://localhost:8080/get/byid&id=_123456789' \ ``` @@ -299,7 +331,7 @@ This will respond with an `access_token`. Use it to make authenticated requests. ```bash curl --request POST \ - --url http://localhost:3000/post \ + --url http://localhost:8080/post \ --header 'authorization: Bearer ' \ --header 'content-type: application/json' \ --data '{"queryType":"adopt","tree_id":"_01","uuid": "auth0|123"}' diff --git a/supabase/migrations/20230329185408_username_constraints.sql b/supabase/migrations/20230329185408_username_constraints.sql new file mode 100644 index 00000000..3fbeaffc --- /dev/null +++ b/supabase/migrations/20230329185408_username_constraints.sql @@ -0,0 +1,88 @@ +CREATE UNIQUE INDEX username_unique_constraint ON public.profiles USING btree (username); + +ALTER TABLE "public"."profiles" + ADD CONSTRAINT "username_length_constraint" CHECK (((length(username) >= 3) AND (length(username) <= 50))) NOT valid; + +ALTER TABLE "public"."profiles" validate CONSTRAINT "username_length_constraint"; + +ALTER TABLE "public"."profiles" + ADD CONSTRAINT "username_unique_constraint" UNIQUE USING INDEX "username_unique_constraint"; + +SET check_function_bodies = OFF; + +CREATE OR REPLACE FUNCTION public.username_append_uuid () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $function$ +BEGIN + IF EXISTS ( + SELECT + 1 + FROM + public.profiles + WHERE + username = NEW.username) THEN + NEW.username := NEW.username || '-' || TRIM(BOTH FROM SUBSTRING( + LEFT (CAST(uuid_generate_v4 () AS text), 8), 1, 6)); +END IF; + RETURN NEW; +END; +$function$; + +CREATE TRIGGER username_check_trigger + BEFORE INSERT OR UPDATE ON public.profiles + FOR EACH ROW + EXECUTE FUNCTION username_append_uuid (); + +CREATE OR REPLACE FUNCTION public.delete_user () + RETURNS TRIGGER + LANGUAGE plpgsql + SECURITY DEFINER + AS $function$ +DECLARE + row_count int; +BEGIN + DELETE FROM public.profiles p + WHERE p.id = OLD.id; + IF found THEN + GET DIAGNOSTICS row_count = ROW_COUNT; + RAISE NOTICE 'DELETEd % row(s) FROM profiles', row_count; + END IF; + UPDATE + trees_watered + SET + uuid = NULL, + username = NULL + WHERE + uuid = OLD.id::text; + DELETE FROM trees_adopted ta + WHERE ta.uuid = OLD.id::text; + RETURN OLD; +END; +$function$; + +CREATE OR REPLACE FUNCTION public.remove_account () + RETURNS void + LANGUAGE sql + SECURITY DEFINER + AS $function$ + DELETE FROM auth.users + WHERE id = auth.uid (); + +$function$; + +CREATE OR REPLACE FUNCTION public.update_username_on_trees_watered () + RETURNS TRIGGER + LANGUAGE plpgsql + AS $function$ +BEGIN + UPDATE + trees_watered + SET + username = NEW.username + WHERE + uuid = OLD.id::text; + RETURN NEW; +END; +$function$; +