1 # frozen_string_literal: true
3 module DatabaseFunctions
5 CREATE OR REPLACE FUNCTION api_rate_limit(user_id int8)
9 min_changes_per_hour int4 := #{Settings.min_changes_per_hour};
10 initial_changes_per_hour int4 := #{Settings.initial_changes_per_hour};
11 max_changes_per_hour int4 := #{Settings.max_changes_per_hour};
12 days_to_max_changes int4 := #{Settings.days_to_max_changes};
13 importer_changes_per_hour int4 := #{Settings.importer_changes_per_hour};
14 moderator_changes_per_hour int4 := #{Settings.moderator_changes_per_hour};
16 last_block timestamp without time zone;
17 first_change timestamp without time zone;
19 time_since_first_change double precision;
20 max_changes double precision;
23 SELECT ARRAY_AGG(user_roles.role) INTO STRICT roles FROM user_roles WHERE user_roles.user_id = api_rate_limit.user_id;
25 IF 'moderator' = ANY(roles) THEN
26 max_changes := moderator_changes_per_hour;
27 ELSIF 'importer' = ANY(roles) THEN
28 max_changes := importer_changes_per_hour;
30 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;
33 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;
35 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;
39 first_change := CURRENT_TIMESTAMP AT TIME ZONE 'UTC';
42 SELECT COUNT(*) INTO STRICT active_reports
43 FROM issues INNER JOIN reports ON reports.issue_id = issues.id
44 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');
46 time_since_first_change := EXTRACT(EPOCH FROM CURRENT_TIMESTAMP AT TIME ZONE 'UTC' - first_change);
48 max_changes := max_changes_per_hour * POWER(time_since_first_change, 2) / POWER(days_to_max_changes * 24 * 60 * 60, 2);
49 max_changes := GREATEST(initial_changes_per_hour, LEAST(max_changes_per_hour, FLOOR(max_changes)));
50 max_changes := max_changes / POWER(2, active_reports);
51 max_changes := GREATEST(min_changes_per_hour, LEAST(max_changes_per_hour, max_changes));
54 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;
56 RETURN max_changes - recent_changes;
58 $$ LANGUAGE plpgsql STABLE;
62 CREATE OR REPLACE FUNCTION api_size_limit(user_id int8)
66 min_size_limit int8 := #{Settings.min_size_limit};
67 initial_size_limit int8 := #{Settings.initial_size_limit};
68 max_size_limit int8 := #{Settings.max_size_limit};
69 days_to_max_size_limit int4 := #{Settings.days_to_max_size_limit};
70 importer_size_limit int8 := #{Settings.importer_size_limit};
71 moderator_size_limit int8 := #{Settings.moderator_size_limit};
73 last_block timestamp without time zone;
74 first_change timestamp without time zone;
76 time_since_first_change double precision;
79 SELECT ARRAY_AGG(user_roles.role) INTO STRICT roles FROM user_roles WHERE user_roles.user_id = api_size_limit.user_id;
81 IF 'moderator' = ANY(roles) THEN
82 size_limit := moderator_size_limit;
83 ELSIF 'importer' = ANY(roles) THEN
84 size_limit := importer_size_limit;
86 SELECT user_blocks.created_at INTO last_block FROM user_blocks WHERE user_blocks.user_id = api_size_limit.user_id ORDER BY user_blocks.created_at DESC LIMIT 1;
89 SELECT changesets.created_at INTO first_change FROM changesets WHERE changesets.user_id = api_size_limit.user_id AND changesets.created_at > last_block ORDER BY changesets.created_at LIMIT 1;
91 SELECT changesets.created_at INTO first_change FROM changesets WHERE changesets.user_id = api_size_limit.user_id ORDER BY changesets.created_at LIMIT 1;
95 first_change := CURRENT_TIMESTAMP AT TIME ZONE 'UTC';
98 SELECT COUNT(*) INTO STRICT active_reports
99 FROM issues INNER JOIN reports ON reports.issue_id = issues.id
100 WHERE issues.reported_user_id = api_size_limit.user_id AND issues.status = 'open' AND reports.updated_at >= COALESCE(issues.resolved_at, '1970-01-01');
102 time_since_first_change := EXTRACT(EPOCH FROM CURRENT_TIMESTAMP AT TIME ZONE 'UTC' - first_change);
104 size_limit := max_size_limit * POWER(time_since_first_change, 2) / POWER(days_to_max_size_limit * 24 * 60 * 60, 2);
105 size_limit := GREATEST(initial_size_limit, LEAST(max_size_limit, FLOOR(size_limit)));
106 size_limit := size_limit / POWER(2, active_reports);
107 size_limit := GREATEST(min_size_limit, LEAST(max_size_limit, size_limit));
112 $$ LANGUAGE plpgsql STABLE;