X-Git-Url: https://git.openstreetmap.org./rails.git/blobdiff_plain/f00a12a2ec91e67485810d9fb3a31203b1d40123..4bca24a7beb4a78cecfeaa775d41662497f9930f:/db/structure.sql diff --git a/db/structure.sql b/db/structure.sql index 17f269666..f74d4d571 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -91,7 +91,8 @@ CREATE TYPE public.nwr_enum AS ENUM ( CREATE TYPE public.user_role_enum AS ENUM ( 'administrator', - 'moderator' + 'moderator', + 'importer' ); @@ -107,6 +108,67 @@ CREATE TYPE public.user_status_enum AS ENUM ( 'deleted' ); + +-- +-- Name: api_rate_limit(bigint); Type: FUNCTION; Schema: public; Owner: - +-- + +CREATE FUNCTION public.api_rate_limit(user_id bigint) RETURNS integer + LANGUAGE plpgsql STABLE + AS $$ + DECLARE + min_changes_per_hour int4 := 100; + initial_changes_per_hour int4 := 1000; + max_changes_per_hour int4 := 100000; + days_to_max_changes int4 := 7; + importer_changes_per_hour int4 := 1000000; + moderator_changes_per_hour int4 := 1000000; + roles text[]; + last_block timestamp without time zone; + first_change timestamp without time zone; + active_reports int4; + time_since_first_change double precision; + max_changes double precision; + recent_changes int4; + BEGIN + SELECT ARRAY_AGG(user_roles.role) INTO STRICT roles FROM user_roles WHERE user_roles.user_id = api_rate_limit.user_id; + + IF 'moderator' = ANY(roles) THEN + max_changes := moderator_changes_per_hour; + ELSIF 'importer' = ANY(roles) THEN + max_changes := importer_changes_per_hour; + ELSE + SELECT user_blocks.created_at INTO last_block FROM user_blocks WHERE user_blocks.user_id = api_rate_limit.user_id ORDER BY user_blocks.created_at DESC LIMIT 1; + + IF FOUND THEN + SELECT changesets.created_at INTO first_change FROM changesets WHERE changesets.user_id = api_rate_limit.user_id AND changesets.created_at > last_block ORDER BY changesets.created_at LIMIT 1; + ELSE + SELECT changesets.created_at INTO first_change FROM changesets WHERE changesets.user_id = api_rate_limit.user_id ORDER BY changesets.created_at LIMIT 1; + END IF; + + IF NOT FOUND THEN + first_change := CURRENT_TIMESTAMP AT TIME ZONE 'UTC'; + END IF; + + SELECT COUNT(*) INTO STRICT active_reports + FROM issues INNER JOIN reports ON reports.issue_id = issues.id + WHERE issues.reported_user_id = api_rate_limit.user_id AND issues.status = 'open' AND reports.updated_at >= COALESCE(issues.resolved_at, '1970-01-01'); + + time_since_first_change := EXTRACT(EPOCH FROM CURRENT_TIMESTAMP AT TIME ZONE 'UTC' - first_change); + + max_changes := max_changes_per_hour * POWER(time_since_first_change, 2) / POWER(days_to_max_changes * 24 * 60 * 60, 2); + max_changes := GREATEST(initial_changes_per_hour, LEAST(max_changes_per_hour, FLOOR(max_changes))); + max_changes := max_changes / POWER(2, active_reports); + max_changes := GREATEST(min_changes_per_hour, LEAST(max_changes_per_hour, max_changes)); + END IF; + + SELECT COALESCE(SUM(changesets.num_changes), 0) INTO STRICT recent_changes FROM changesets WHERE changesets.user_id = api_rate_limit.user_id AND changesets.created_at >= CURRENT_TIMESTAMP AT TIME ZONE 'UTC' - '1 hour'::interval; + + RETURN max_changes - recent_changes; + END; + $$; + + SET default_tablespace = ''; SET default_table_access_method = heap; @@ -2437,6 +2499,13 @@ CREATE INDEX index_changeset_comments_on_changeset_id_and_created_at ON public.c CREATE INDEX index_changeset_comments_on_created_at ON public.changeset_comments USING btree (created_at); +-- +-- Name: index_changesets_on_user_id_and_closed_at; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_changesets_on_user_id_and_closed_at ON public.changesets USING btree (user_id, closed_at); + + -- -- Name: index_changesets_subscribers_on_changeset_id; Type: INDEX; Schema: public; Owner: - -- @@ -3437,6 +3506,9 @@ INSERT INTO "schema_migrations" (version) VALUES ('23'), ('22'), ('21'), +('20231117170422'), +('20231101222146'), +('20231029151516'), ('20231010194809'), ('20231007141103'), ('20230830115220'),