liquid_feedback_core

annotate update/core-update.v3.2.2-v4.0.0.sql @ 563:fc09088587b2

Bugfix regarding locking when logging initiative revocation (cannot combine DISTINCT with FOR SHARE)
author jbe
date Mon Sep 25 14:44:35 2017 +0200 (2017-09-25)
parents c3931054bb55
children dc48b79b8a7e 17c9cca2938b
rev   line source
jbe@536 1 ALTER TYPE "event_type" ADD VALUE IF NOT EXISTS 'unit_created';
jbe@536 2 ALTER TYPE "event_type" ADD VALUE IF NOT EXISTS 'unit_updated';
jbe@539 3 ALTER TYPE "event_type" ADD VALUE IF NOT EXISTS 'area_created';
jbe@539 4 ALTER TYPE "event_type" ADD VALUE IF NOT EXISTS 'area_updated';
jbe@536 5 ALTER TYPE "event_type" ADD VALUE IF NOT EXISTS 'policy_created';
jbe@536 6 ALTER TYPE "event_type" ADD VALUE IF NOT EXISTS 'policy_updated';
jbe@554 7 ALTER TYPE "event_type" ADD VALUE IF NOT EXISTS 'suggestion_deleted';
jbe@532 8 ALTER TYPE "event_type" ADD VALUE IF NOT EXISTS 'member_activated';
jbe@554 9 ALTER TYPE "event_type" ADD VALUE IF NOT EXISTS 'member_deleted';
jbe@532 10 ALTER TYPE "event_type" ADD VALUE IF NOT EXISTS 'member_active';
jbe@532 11 ALTER TYPE "event_type" ADD VALUE IF NOT EXISTS 'member_name_updated';
jbe@532 12 ALTER TYPE "event_type" ADD VALUE IF NOT EXISTS 'member_profile_updated';
jbe@532 13 ALTER TYPE "event_type" ADD VALUE IF NOT EXISTS 'member_image_updated';
jbe@532 14 ALTER TYPE "event_type" ADD VALUE IF NOT EXISTS 'interest';
jbe@532 15 ALTER TYPE "event_type" ADD VALUE IF NOT EXISTS 'initiator';
jbe@532 16 ALTER TYPE "event_type" ADD VALUE IF NOT EXISTS 'support';
jbe@532 17 ALTER TYPE "event_type" ADD VALUE IF NOT EXISTS 'support_updated';
jbe@532 18 ALTER TYPE "event_type" ADD VALUE IF NOT EXISTS 'suggestion_rated';
jbe@532 19 ALTER TYPE "event_type" ADD VALUE IF NOT EXISTS 'delegation';
jbe@532 20 ALTER TYPE "event_type" ADD VALUE IF NOT EXISTS 'contact';
jbe@532 21
jbe@532 22
jbe@532 23 BEGIN;
jbe@532 24
jbe@532 25
jbe@532 26 CREATE OR REPLACE VIEW "liquid_feedback_version" AS
jbe@532 27 SELECT * FROM (VALUES ('4.0-dev', 4, 0, -1))
jbe@532 28 AS "subquery"("string", "major", "minor", "revision");
jbe@532 29
jbe@532 30
jbe@532 31 ALTER TABLE "system_setting" ADD COLUMN "snapshot_retention" INTERVAL;
jbe@532 32
jbe@532 33 COMMENT ON COLUMN "system_setting"."snapshot_retention" IS 'Unreferenced snapshots are retained for the given period of time after creation; set to NULL for infinite retention.';
jbe@552 34
jbe@552 35
jbe@557 36 CREATE TABLE "verification" (
jbe@557 37 "id" SERIAL8 PRIMARY KEY,
jbe@557 38 "requested" TIMESTAMPTZ,
jbe@557 39 "request_origin" JSONB,
jbe@557 40 "request_data" JSONB,
jbe@560 41 "requesting_member_id" INT4 REFERENCES "member" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
jbe@560 42 "verifying_member_id" INT4 REFERENCES "member" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
jbe@560 43 "verified_member_id" INT4 REFERENCES "member" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
jbe@557 44 "verified" TIMESTAMPTZ,
jbe@557 45 "verification_data" JSONB,
jbe@557 46 "denied" TIMESTAMPTZ,
jbe@557 47 "comment" TEXT,
jbe@557 48 CONSTRAINT "verified_and_denied_conflict" CHECK (
jbe@557 49 "verified" ISNULL OR "denied" ISNULL ) );
jbe@557 50 CREATE INDEX "verification_requested_idx" ON "verification" ("requested");
jbe@557 51 CREATE INDEX "verification_open_request_idx" ON "verification" ("requested") WHERE "verified" ISNULL AND "denied" ISNULL;
jbe@560 52 CREATE INDEX "verification_requesting_member_id_idx" ON "verification" ("requesting_member_id");
jbe@560 53 CREATE INDEX "verification_verified_member_id_idx" ON "verification" ("verified_member_id");
jbe@557 54 CREATE INDEX "verification_verified_idx" ON "verification" ("verified");
jbe@557 55 CREATE INDEX "verification_denied_idx" ON "verification" ("denied");
jbe@557 56
jbe@557 57 COMMENT ON TABLE "verification" IS 'Request to verify a participant';
jbe@557 58
jbe@560 59 COMMENT ON COLUMN "verification"."requested" IS 'Timestamp when request for verification has been submitted';
jbe@560 60 COMMENT ON COLUMN "verification"."request_origin" IS 'JSON data containing information about the origin of the request (e.g. IP address or hostname)';
jbe@560 61 COMMENT ON COLUMN "verification"."request_data" IS 'JSON data containing information about the entity to be verified (e.g. real name, address, etc.)';
jbe@560 62 COMMENT ON COLUMN "verification"."requesting_member_id" IS 'Member who requested verification';
jbe@560 63 COMMENT ON COLUMN "verification"."verifying_member_id" IS 'Member who processed the verification request (i.e. who accepted or denied the request)';
jbe@560 64 COMMENT ON COLUMN "verification"."verified_member_id" IS 'Member entry containing verified information (not necessarily equal to "requesting_member_id" but may be merged with requesting member later)';
jbe@560 65 COMMENT ON COLUMN "verification"."verified" IS 'Timestamp when request for verification has been accepted by authority';
jbe@560 66 COMMENT ON COLUMN "verification"."verification_data" IS 'JSON data containing additional verified data or information about the authority or operator who accepted or denied the request, but all public information shall be copied to "member"."identification", "member"."verification" and/or "member"."name" if applicable for setup';
jbe@560 67 COMMENT ON COLUMN "verification"."denied" IS 'Timestamp when request for verification has been denied by authority';
jbe@560 68 COMMENT ON COLUMN "verification"."comment" IS 'Administrative comment';
jbe@557 69
jbe@557 70
jbe@552 71 ALTER TABLE "member" ADD COLUMN "deleted" TIMESTAMPTZ;
jbe@552 72 ALTER TABLE "member" ADD CONSTRAINT "deleted_requires_locked"
jbe@552 73 CHECK ("deleted" ISNULL OR "locked" = TRUE);
jbe@532 74
jbe@552 75 COMMENT ON COLUMN "member"."deleted" IS 'Timestamp of deletion (set by "delete_member" function)';
jbe@552 76
jbe@532 77
jbe@544 78 CREATE TABLE "member_settings" (
jbe@544 79 "member_id" INT4 PRIMARY KEY REFERENCES "member" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
jbe@544 80 "settings" JSONB NOT NULL CHECK (jsonb_typeof("settings") = 'object') );
jbe@544 81
jbe@544 82 COMMENT ON TABLE "member_settings" IS 'Stores a JSON document for each member containing optional (additional) settings for the respective member';
jbe@544 83
jbe@544 84
jbe@544 85 CREATE TABLE "member_useterms" (
jbe@559 86 "id" SERIAL8 PRIMARY KEY,
jbe@559 87 "member_id" INT4 NOT NULL REFERENCES "member" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
jbe@558 88 "accepted" TIMESTAMPTZ NOT NULL DEFAULT now(),
jbe@544 89 "contract_identifier" TEXT NOT NULL );
jbe@544 90
jbe@544 91 COMMENT ON TABLE "member_useterms" IS 'Keeps record of accepted terms of use; may contain multiple rows per member';
jbe@544 92
jbe@544 93 COMMENT ON COLUMN "member_useterms"."accepted" IS 'Point in time when user accepted the terms of use';
jbe@544 94 COMMENT ON COLUMN "member_useterms"."contract_identifier" IS 'String identifier to denote the accepted terms of use, including their version or revision';
jbe@544 95
jbe@544 96
jbe@532 97 CREATE TABLE "member_profile" (
jbe@532 98 "member_id" INT4 PRIMARY KEY REFERENCES "member" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
jbe@532 99 "formatting_engine" TEXT,
jbe@532 100 "statement" TEXT,
jbe@544 101 "profile" JSONB NOT NULL DEFAULT '{}' CHECK (jsonb_typeof("profile") = 'object'),
jbe@532 102 "profile_text_data" TEXT,
jbe@532 103 "text_search_data" TSVECTOR );
jbe@532 104 CREATE INDEX "member_profile_text_search_data_idx" ON "member_profile" USING gin ("text_search_data");
jbe@532 105 CREATE TRIGGER "update_text_search_data"
jbe@532 106 BEFORE INSERT OR UPDATE ON "member_profile"
jbe@532 107 FOR EACH ROW EXECUTE PROCEDURE
jbe@532 108 tsvector_update_trigger('text_search_data', 'pg_catalog.simple',
jbe@532 109 'statement', 'profile_text_data');
jbe@532 110
jbe@532 111 COMMENT ON COLUMN "member_profile"."formatting_engine" IS 'Allows different formatting engines (i.e. wiki formats) to be used for "member_profile"."statement"';
jbe@532 112 COMMENT ON COLUMN "member_profile"."statement" IS 'Freely chosen text of the member for his/her profile';
jbe@532 113 COMMENT ON COLUMN "member_profile"."profile" IS 'Additional profile data as JSON document';
jbe@532 114 COMMENT ON COLUMN "member_profile"."profile_text_data" IS 'Text data from "profile" field for full text search';
jbe@532 115
jbe@532 116
jbe@532 117 INSERT INTO "member_profile"
jbe@532 118 ( "member_id", "formatting_engine", "statement", "profile")
jbe@532 119 SELECT
jbe@532 120 "id" AS "member_id",
jbe@532 121 "formatting_engine",
jbe@532 122 "statement",
jbe@532 123 json_build_object(
jbe@532 124 'organizational_unit', "organizational_unit",
jbe@532 125 'internal_posts', "internal_posts",
jbe@532 126 'realname', "realname",
jbe@532 127 'birthday', to_char("birthday", 'YYYY-MM-DD'),
jbe@532 128 'address', "address",
jbe@532 129 'email', "email",
jbe@532 130 'xmpp_address', "xmpp_address",
jbe@532 131 'website', "website",
jbe@532 132 'phone', "phone",
jbe@532 133 'mobile_phone', "mobile_phone",
jbe@532 134 'profession', "profession",
jbe@532 135 'external_memberships', "external_memberships",
jbe@532 136 'external_posts', "external_posts"
jbe@532 137 ) AS "profile"
jbe@532 138 FROM "member";
jbe@532 139
jbe@532 140 UPDATE "member_profile" SET "profile_text_data" =
jbe@532 141 coalesce(("profile"->>'organizational_unit') || ' ', '') ||
jbe@532 142 coalesce(("profile"->>'internal_posts') || ' ', '') ||
jbe@532 143 coalesce(("profile"->>'realname') || ' ', '') ||
jbe@532 144 coalesce(("profile"->>'birthday') || ' ', '') ||
jbe@532 145 coalesce(("profile"->>'address') || ' ', '') ||
jbe@532 146 coalesce(("profile"->>'email') || ' ', '') ||
jbe@532 147 coalesce(("profile"->>'xmpp_address') || ' ', '') ||
jbe@532 148 coalesce(("profile"->>'website') || ' ', '') ||
jbe@532 149 coalesce(("profile"->>'phone') || ' ', '') ||
jbe@532 150 coalesce(("profile"->>'mobile_phone') || ' ', '') ||
jbe@532 151 coalesce(("profile"->>'profession') || ' ', '') ||
jbe@532 152 coalesce(("profile"->>'external_memberships') || ' ', '') ||
jbe@532 153 coalesce(("profile"->>'external_posts') || ' ', '');
jbe@532 154
jbe@532 155
jbe@532 156 DROP VIEW "newsletter_to_send";
jbe@532 157 DROP VIEW "scheduled_notification_to_send";
jbe@532 158 DROP VIEW "member_to_notify";
jbe@532 159 DROP VIEW "member_eligible_to_be_notified";
jbe@532 160
jbe@532 161
jbe@532 162 ALTER TABLE "member" DROP COLUMN "organizational_unit";
jbe@532 163 ALTER TABLE "member" DROP COLUMN "internal_posts";
jbe@532 164 ALTER TABLE "member" DROP COLUMN "realname";
jbe@532 165 ALTER TABLE "member" DROP COLUMN "birthday";
jbe@532 166 ALTER TABLE "member" DROP COLUMN "address";
jbe@532 167 ALTER TABLE "member" DROP COLUMN "email";
jbe@532 168 ALTER TABLE "member" DROP COLUMN "xmpp_address";
jbe@532 169 ALTER TABLE "member" DROP COLUMN "website";
jbe@532 170 ALTER TABLE "member" DROP COLUMN "phone";
jbe@532 171 ALTER TABLE "member" DROP COLUMN "mobile_phone";
jbe@532 172 ALTER TABLE "member" DROP COLUMN "profession";
jbe@532 173 ALTER TABLE "member" DROP COLUMN "external_memberships";
jbe@532 174 ALTER TABLE "member" DROP COLUMN "external_posts";
jbe@532 175 ALTER TABLE "member" DROP COLUMN "formatting_engine";
jbe@532 176 ALTER TABLE "member" DROP COLUMN "statement";
jbe@532 177
jbe@532 178 ALTER TABLE "member" ADD COLUMN "location" JSONB;
jbe@532 179 COMMENT ON COLUMN "member"."location" IS 'Geographic location on earth as GeoJSON object';
jbe@532 180 CREATE INDEX "member_location_idx" ON "member" USING gist ((GeoJSON_to_ecluster("location")));
jbe@532 181
jbe@532 182 DROP TRIGGER "update_text_search_data" ON "member";
jbe@532 183 CREATE TRIGGER "update_text_search_data"
jbe@532 184 BEFORE INSERT OR UPDATE ON "member"
jbe@532 185 FOR EACH ROW EXECUTE PROCEDURE
jbe@532 186 tsvector_update_trigger('text_search_data', 'pg_catalog.simple',
jbe@532 187 "name", "identification");
jbe@532 188
jbe@532 189
jbe@532 190 CREATE VIEW "member_eligible_to_be_notified" AS
jbe@532 191 SELECT * FROM "member"
jbe@532 192 WHERE "activated" NOTNULL AND "locked" = FALSE;
jbe@532 193
jbe@532 194 COMMENT ON VIEW "member_eligible_to_be_notified" IS 'Filtered "member" table containing only activated and non-locked members (used as helper view for "member_to_notify" and "newsletter_to_send")';
jbe@532 195
jbe@532 196
jbe@532 197 CREATE VIEW "member_to_notify" AS
jbe@532 198 SELECT * FROM "member_eligible_to_be_notified"
jbe@532 199 WHERE "disable_notifications" = FALSE;
jbe@532 200
jbe@532 201 COMMENT ON VIEW "member_to_notify" IS 'Filtered "member" table containing only members that are eligible to and wish to receive notifications; NOTE: "notify_email" may still be NULL and might need to be checked by frontend (this allows other means of messaging)';
jbe@532 202
jbe@532 203
jbe@532 204 CREATE VIEW "scheduled_notification_to_send" AS
jbe@532 205 SELECT * FROM (
jbe@532 206 SELECT
jbe@532 207 "id" AS "recipient_id",
jbe@532 208 now() - CASE WHEN "notification_dow" ISNULL THEN
jbe@532 209 ( "notification_sent"::DATE + CASE
jbe@532 210 WHEN EXTRACT(HOUR FROM "notification_sent") < "notification_hour"
jbe@532 211 THEN 0 ELSE 1 END
jbe@532 212 )::TIMESTAMP + '1 hour'::INTERVAL * "notification_hour"
jbe@532 213 ELSE
jbe@532 214 ( "notification_sent"::DATE +
jbe@532 215 ( 7 + "notification_dow" -
jbe@532 216 EXTRACT(DOW FROM
jbe@532 217 ( "notification_sent"::DATE + CASE
jbe@532 218 WHEN EXTRACT(HOUR FROM "notification_sent") < "notification_hour"
jbe@532 219 THEN 0 ELSE 1 END
jbe@532 220 )::TIMESTAMP + '1 hour'::INTERVAL * "notification_hour"
jbe@532 221 )::INTEGER
jbe@532 222 ) % 7 +
jbe@532 223 CASE
jbe@532 224 WHEN EXTRACT(HOUR FROM "notification_sent") < "notification_hour"
jbe@532 225 THEN 0 ELSE 1
jbe@532 226 END
jbe@532 227 )::TIMESTAMP + '1 hour'::INTERVAL * "notification_hour"
jbe@532 228 END AS "pending"
jbe@532 229 FROM (
jbe@532 230 SELECT
jbe@532 231 "id",
jbe@532 232 COALESCE("notification_sent", "activated") AS "notification_sent",
jbe@532 233 "notification_dow",
jbe@532 234 "notification_hour"
jbe@532 235 FROM "member_to_notify"
jbe@532 236 WHERE "notification_hour" NOTNULL
jbe@532 237 ) AS "subquery1"
jbe@532 238 ) AS "subquery2"
jbe@532 239 WHERE "pending" > '0'::INTERVAL;
jbe@532 240
jbe@532 241 COMMENT ON VIEW "scheduled_notification_to_send" IS 'Set of members where a scheduled notification mail is pending';
jbe@532 242
jbe@532 243 COMMENT ON COLUMN "scheduled_notification_to_send"."recipient_id" IS '"id" of the member who needs to receive a notification mail';
jbe@532 244 COMMENT ON COLUMN "scheduled_notification_to_send"."pending" IS 'Duration for which the notification mail has already been pending';
jbe@532 245
jbe@532 246
jbe@532 247 CREATE VIEW "newsletter_to_send" AS
jbe@532 248 SELECT
jbe@532 249 "member"."id" AS "recipient_id",
jbe@532 250 "newsletter"."id" AS "newsletter_id",
jbe@532 251 "newsletter"."published"
jbe@532 252 FROM "newsletter" CROSS JOIN "member_eligible_to_be_notified" AS "member"
jbe@556 253 LEFT JOIN "privilege" ON
jbe@556 254 "privilege"."member_id" = "member"."id" AND
jbe@556 255 "privilege"."unit_id" = "newsletter"."unit_id" AND
jbe@556 256 "privilege"."voting_right" = TRUE
jbe@532 257 LEFT JOIN "subscription" ON
jbe@532 258 "subscription"."member_id" = "member"."id" AND
jbe@532 259 "subscription"."unit_id" = "newsletter"."unit_id"
jbe@532 260 WHERE "newsletter"."published" <= now()
jbe@532 261 AND "newsletter"."sent" ISNULL
jbe@532 262 AND (
jbe@532 263 "member"."disable_notifications" = FALSE OR
jbe@532 264 "newsletter"."include_all_members" = TRUE )
jbe@532 265 AND (
jbe@532 266 "newsletter"."unit_id" ISNULL OR
jbe@556 267 "privilege"."member_id" NOTNULL OR
jbe@532 268 "subscription"."member_id" NOTNULL );
jbe@532 269
jbe@532 270 COMMENT ON VIEW "newsletter_to_send" IS 'List of "newsletter_id"s for each member that are due to be sent out';
jbe@532 271
jbe@532 272 COMMENT ON COLUMN "newsletter"."published" IS 'Timestamp when the newsletter was supposed to be sent out (can be used for ordering)';
jbe@532 273
jbe@532 274
jbe@532 275 DROP VIEW "expired_session";
jbe@532 276 DROP TABLE "session";
jbe@532 277
jbe@532 278
jbe@532 279 CREATE TABLE "session" (
jbe@532 280 UNIQUE ("member_id", "id"), -- index needed for foreign-key on table "token"
jbe@532 281 "id" SERIAL8 PRIMARY KEY,
jbe@532 282 "ident" TEXT NOT NULL UNIQUE,
jbe@532 283 "additional_secret" TEXT,
jbe@532 284 "logout_token" TEXT,
jbe@532 285 "expiry" TIMESTAMPTZ NOT NULL DEFAULT now() + '24 hours',
jbe@532 286 "member_id" INT4 REFERENCES "member" ("id") ON DELETE SET NULL,
jbe@532 287 "authority" TEXT,
jbe@532 288 "authority_uid" TEXT,
jbe@532 289 "authority_login" TEXT,
jbe@532 290 "needs_delegation_check" BOOLEAN NOT NULL DEFAULT FALSE,
jbe@532 291 "lang" TEXT );
jbe@532 292 CREATE INDEX "session_expiry_idx" ON "session" ("expiry");
jbe@532 293
jbe@532 294 COMMENT ON TABLE "session" IS 'Sessions, i.e. for a web-frontend or API layer';
jbe@532 295
jbe@532 296 COMMENT ON COLUMN "session"."ident" IS 'Secret session identifier (i.e. random string)';
jbe@532 297 COMMENT ON COLUMN "session"."additional_secret" IS 'Additional field to store a secret, which can be used against CSRF attacks';
jbe@532 298 COMMENT ON COLUMN "session"."logout_token" IS 'Optional token to authorize logout through external component';
jbe@532 299 COMMENT ON COLUMN "session"."member_id" IS 'Reference to member, who is logged in';
jbe@532 300 COMMENT ON COLUMN "session"."authority" IS 'Temporary store for "member"."authority" during member account creation';
jbe@532 301 COMMENT ON COLUMN "session"."authority_uid" IS 'Temporary store for "member"."authority_uid" during member account creation';
jbe@532 302 COMMENT ON COLUMN "session"."authority_login" IS 'Temporary store for "member"."authority_login" during member account creation';
jbe@532 303 COMMENT ON COLUMN "session"."needs_delegation_check" IS 'Set to TRUE, if member must perform a delegation check to proceed with login; see column "last_delegation_check" in "member" table';
jbe@532 304 COMMENT ON COLUMN "session"."lang" IS 'Language code of the selected language';
jbe@532 305
jbe@532 306
jbe@532 307 CREATE TYPE "authflow" AS ENUM ('code', 'token');
jbe@532 308
jbe@532 309 COMMENT ON TYPE "authflow" IS 'OAuth 2.0 flows: ''code'' = Authorization Code flow, ''token'' = Implicit flow';
jbe@532 310
jbe@532 311
jbe@532 312 CREATE TABLE "system_application" (
jbe@532 313 "id" SERIAL4 PRIMARY KEY,
jbe@532 314 "name" TEXT NOT NULL,
jbe@548 315 "discovery_baseurl" TEXT,
jbe@532 316 "client_id" TEXT NOT NULL UNIQUE,
jbe@532 317 "default_redirect_uri" TEXT NOT NULL,
jbe@532 318 "cert_common_name" TEXT,
jbe@532 319 "client_cred_scope" TEXT,
jbe@532 320 "flow" "authflow",
jbe@532 321 "automatic_scope" TEXT,
jbe@532 322 "permitted_scope" TEXT,
jbe@532 323 "forbidden_scope" TEXT );
jbe@532 324
jbe@532 325 COMMENT ON TABLE "system_application" IS 'OAuth 2.0 clients that are registered by the system administrator';
jbe@532 326
jbe@532 327 COMMENT ON COLUMN "system_application"."name" IS 'Human readable name of application';
jbe@548 328 COMMENT ON COLUMN "system_application"."discovery_baseurl" IS 'Base URL for application discovery; NULL for hidden application';
jbe@532 329 COMMENT ON COLUMN "system_application"."client_id" IS 'OAuth 2.0 "client_id"';
jbe@532 330 COMMENT ON COLUMN "system_application"."cert_common_name" IS 'Value for CN field of TLS client certificate';
jbe@532 331 COMMENT ON COLUMN "system_application"."client_cred_scope" IS 'Space-separated list of scopes; If set, Client Credentials Grant is allowed; value determines scope';
jbe@532 332 COMMENT ON COLUMN "system_application"."flow" IS 'If set to ''code'' or ''token'', then Authorization Code or Implicit flow is allowed respectively';
jbe@532 333 COMMENT ON COLUMN "system_application"."automatic_scope" IS 'Space-separated list of scopes; Automatically granted scope for Authorization Code or Implicit flow';
jbe@532 334 COMMENT ON COLUMN "system_application"."permitted_scope" IS 'Space-separated list of scopes; If set, scope that members may grant to the application is limited to the given value';
jbe@532 335 COMMENT ON COLUMN "system_application"."forbidden_scope" IS 'Space-separated list of scopes that may not be granted to the application by a member';
jbe@532 336
jbe@532 337
jbe@532 338 CREATE TABLE "system_application_redirect_uri" (
jbe@532 339 PRIMARY KEY ("system_application_id", "redirect_uri"),
jbe@532 340 "system_application_id" INT4 REFERENCES "system_application" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
jbe@532 341 "redirect_uri" TEXT );
jbe@532 342
jbe@532 343 COMMENT ON TABLE "system_application_redirect_uri" IS 'Additional OAuth 2.0 redirection endpoints, which may be selected through the "redirect_uri" GET parameter';
jbe@532 344
jbe@532 345
jbe@532 346 CREATE TABLE "dynamic_application_scope" (
jbe@532 347 PRIMARY KEY ("redirect_uri", "flow", "scope"),
jbe@532 348 "redirect_uri" TEXT,
jbe@532 349 "flow" TEXT,
jbe@532 350 "scope" TEXT,
jbe@532 351 "expiry" TIMESTAMPTZ NOT NULL DEFAULT now() + '24 hours' );
jbe@532 352 CREATE INDEX "dynamic_application_scope_redirect_uri_scope_idx" ON "dynamic_application_scope" ("redirect_uri", "flow", "scope");
jbe@532 353 CREATE INDEX "dynamic_application_scope_expiry_idx" ON "dynamic_application_scope" ("expiry");
jbe@532 354
jbe@532 355 COMMENT ON TABLE "dynamic_application_scope" IS 'Dynamic OAuth 2.0 client registration data';
jbe@532 356
jbe@532 357 COMMENT ON COLUMN "dynamic_application_scope"."redirect_uri" IS 'Redirection endpoint for which the registration has been done';
jbe@532 358 COMMENT ON COLUMN "dynamic_application_scope"."flow" IS 'OAuth 2.0 flow for which the registration has been done (see also "system_application"."flow")';
jbe@532 359 COMMENT ON COLUMN "dynamic_application_scope"."scope" IS 'Single scope without space characters (use multiple rows for more scopes)';
jbe@532 360 COMMENT ON COLUMN "dynamic_application_scope"."expiry" IS 'Expiry unless renewed';
jbe@532 361
jbe@532 362
jbe@532 363 CREATE TABLE "member_application" (
jbe@532 364 "id" SERIAL4 PRIMARY KEY,
jbe@532 365 UNIQUE ("system_application_id", "member_id"),
jbe@532 366 UNIQUE ("domain", "member_id"),
jbe@532 367 "member_id" INT4 NOT NULL REFERENCES "member" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
jbe@532 368 "system_application_id" INT4 REFERENCES "system_application" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
jbe@532 369 "domain" TEXT,
jbe@532 370 "session_id" INT8,
jbe@532 371 FOREIGN KEY ("member_id", "session_id") REFERENCES "session" ("member_id", "id") ON DELETE CASCADE ON UPDATE CASCADE,
jbe@532 372 "scope" TEXT NOT NULL,
jbe@532 373 CONSTRAINT "system_application_or_domain_but_not_both" CHECK (
jbe@532 374 ("system_application_id" NOTNULL AND "domain" ISNULL) OR
jbe@532 375 ("system_application_id" ISNULL AND "domain" NOTNULL) ) );
jbe@532 376 CREATE INDEX "member_application_member_id_idx" ON "member_application" ("member_id");
jbe@532 377
jbe@532 378 COMMENT ON TABLE "member_application" IS 'Application authorized by a member';
jbe@532 379
jbe@532 380 COMMENT ON COLUMN "member_application"."system_application_id" IS 'If set, then application is a system application';
jbe@532 381 COMMENT ON COLUMN "member_application"."domain" IS 'If set, then application is a dynamically registered OAuth 2.0 client; value is set to client''s domain';
jbe@532 382 COMMENT ON COLUMN "member_application"."session_id" IS 'If set, registration ends with session';
jbe@532 383 COMMENT ON COLUMN "member_application"."scope" IS 'Granted scope as space-separated list of strings';
jbe@532 384
jbe@532 385
jbe@532 386 CREATE TYPE "token_type" AS ENUM ('authorization', 'refresh', 'access');
jbe@532 387
jbe@532 388 COMMENT ON TYPE "token_type" IS 'Types for entries in "token" table';
jbe@532 389
jbe@532 390
jbe@532 391 CREATE TABLE "token" (
jbe@532 392 "id" SERIAL8 PRIMARY KEY,
jbe@532 393 "token" TEXT NOT NULL UNIQUE,
jbe@532 394 "token_type" "token_type" NOT NULL,
jbe@532 395 "authorization_token_id" INT8 REFERENCES "token" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
jbe@532 396 "member_id" INT4 NOT NULL REFERENCES "member" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
jbe@532 397 "system_application_id" INT4 REFERENCES "system_application" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
jbe@532 398 "domain" TEXT,
jbe@532 399 FOREIGN KEY ("member_id", "domain") REFERENCES "member_application" ("member_id", "domain") ON DELETE CASCADE ON UPDATE CASCADE,
jbe@532 400 "session_id" INT8,
jbe@532 401 FOREIGN KEY ("member_id", "session_id") REFERENCES "session" ("member_id", "id") ON DELETE RESTRICT ON UPDATE CASCADE, -- NOTE: deletion through "detach_token_from_session" trigger on table "session"
jbe@532 402 "redirect_uri" TEXT,
jbe@532 403 "redirect_uri_explicit" BOOLEAN,
jbe@532 404 "created" TIMESTAMPTZ NOT NULL DEFAULT now(),
jbe@532 405 "expiry" TIMESTAMPTZ DEFAULT now() + '1 hour',
jbe@532 406 "used" BOOLEAN NOT NULL DEFAULT FALSE,
jbe@532 407 "scope" TEXT NOT NULL,
jbe@532 408 CONSTRAINT "access_token_needs_expiry"
jbe@532 409 CHECK ("token_type" != 'access'::"token_type" OR "expiry" NOTNULL),
jbe@532 410 CONSTRAINT "authorization_token_needs_redirect_uri"
jbe@532 411 CHECK ("token_type" != 'authorization'::"token_type" OR ("redirect_uri" NOTNULL AND "redirect_uri_explicit" NOTNULL) ) );
jbe@532 412 CREATE INDEX "token_member_id_idx" ON "token" ("member_id");
jbe@532 413 CREATE INDEX "token_authorization_token_id_idx" ON "token" ("authorization_token_id");
jbe@532 414 CREATE INDEX "token_expiry_idx" ON "token" ("expiry");
jbe@532 415
jbe@532 416 COMMENT ON TABLE "token" IS 'Issued OAuth 2.0 authorization codes and access/refresh tokens';
jbe@532 417
jbe@532 418 COMMENT ON COLUMN "token"."token" IS 'String secret (the actual token)';
jbe@532 419 COMMENT ON COLUMN "token"."authorization_token_id" IS 'Reference to authorization token if tokens were originally created by Authorization Code flow (allows deletion if code is used twice)';
jbe@532 420 COMMENT ON COLUMN "token"."system_application_id" IS 'If set, then application is a system application';
jbe@532 421 COMMENT ON COLUMN "token"."domain" IS 'If set, then application is a dynamically registered OAuth 2.0 client; value is set to client''s domain';
jbe@532 422 COMMENT ON COLUMN "token"."session_id" IS 'If set, then token is tied to a session; Deletion of session sets value to NULL (via trigger) and removes all scopes without suffix ''_detached''';
jbe@532 423 COMMENT ON COLUMN "token"."redirect_uri" IS 'Authorization codes must be bound to a specific redirect URI';
jbe@532 424 COMMENT ON COLUMN "token"."redirect_uri_explicit" IS 'True if ''redirect_uri'' parameter was explicitly specified during authorization request of the Authorization Code flow (since RFC 6749 requires it to be included in the access token request in this case)';
jbe@532 425 COMMENT ON COLUMN "token"."expiry" IS 'Point in time when code or token expired; In case of "used" authorization codes, authorization code must not be deleted as long as tokens exist which refer to the authorization code';
jbe@532 426 COMMENT ON COLUMN "token"."used" IS 'Can be set to TRUE for authorization codes that have been used (enables deletion of authorization codes that were used twice)';
jbe@532 427 COMMENT ON COLUMN "token"."scope" IS 'Scope as space-separated list of strings (detached scopes are marked with ''_detached'' suffix)';
jbe@532 428
jbe@532 429
jbe@532 430 CREATE TABLE "token_scope" (
jbe@532 431 PRIMARY KEY ("token_id", "index"),
jbe@532 432 "token_id" INT8 REFERENCES "token" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
jbe@532 433 "index" INT4,
jbe@532 434 "scope" TEXT NOT NULL );
jbe@532 435
jbe@532 436 COMMENT ON TABLE "token_scope" IS 'Additional scopes for an authorization code if ''scope1'', ''scope2'', etc. parameters were used during Authorization Code flow to request several access and refresh tokens at once';
jbe@532 437
jbe@532 438
jbe@532 439 ALTER TABLE "policy" ADD COLUMN "issue_quorum" INT4 CHECK ("issue_quorum" >= 1);
jbe@532 440 ALTER TABLE "policy" ADD COLUMN "initiative_quorum" INT4 CHECK ("initiative_quorum" >= 1);
jbe@532 441
jbe@532 442 UPDATE "policy" SET "issue_quorum" = 1 WHERE "issue_quorum_num" NOTNULL;
jbe@532 443 UPDATE "policy" SET "initiative_quorum" = 1;
jbe@532 444
jbe@532 445 ALTER TABLE "policy" ALTER COLUMN "initiative_quorum" SET NOT NULL;
jbe@532 446
jbe@532 447 ALTER TABLE "policy" DROP CONSTRAINT "timing";
jbe@532 448 ALTER TABLE "policy" DROP CONSTRAINT "issue_quorum_if_and_only_if_not_polling";
jbe@532 449 ALTER TABLE "policy" ADD CONSTRAINT
jbe@532 450 "issue_quorum_if_and_only_if_not_polling" CHECK (
jbe@532 451 "polling" = ("issue_quorum" ISNULL) AND
jbe@532 452 "polling" = ("issue_quorum_num" ISNULL) AND
jbe@532 453 "polling" = ("issue_quorum_den" ISNULL)
jbe@532 454 );
jbe@532 455 ALTER TABLE "policy" ADD CONSTRAINT
jbe@532 456 "min_admission_time_smaller_than_max_admission_time" CHECK (
jbe@532 457 "min_admission_time" < "max_admission_time"
jbe@532 458 );
jbe@532 459 ALTER TABLE "policy" ADD CONSTRAINT
jbe@532 460 "timing_null_or_not_null_constraints" CHECK (
jbe@532 461 ( "polling" = FALSE AND
jbe@532 462 "min_admission_time" NOTNULL AND "max_admission_time" NOTNULL AND
jbe@532 463 "discussion_time" NOTNULL AND
jbe@532 464 "verification_time" NOTNULL AND
jbe@532 465 "voting_time" NOTNULL ) OR
jbe@532 466 ( "polling" = TRUE AND
jbe@532 467 "min_admission_time" ISNULL AND "max_admission_time" ISNULL AND
jbe@532 468 "discussion_time" NOTNULL AND
jbe@532 469 "verification_time" NOTNULL AND
jbe@532 470 "voting_time" NOTNULL ) OR
jbe@532 471 ( "polling" = TRUE AND
jbe@532 472 "min_admission_time" ISNULL AND "max_admission_time" ISNULL AND
jbe@532 473 "discussion_time" ISNULL AND
jbe@532 474 "verification_time" ISNULL AND
jbe@532 475 "voting_time" ISNULL )
jbe@532 476 );
jbe@532 477
jbe@532 478 COMMENT ON COLUMN "policy"."min_admission_time" IS 'Minimum duration of issue state ''admission''; Minimum time an issue stays open; Note: should be considerably smaller than "max_admission_time"';
jbe@532 479 COMMENT ON COLUMN "policy"."issue_quorum" IS 'Absolute number of supporters needed by an initiative to be "accepted", i.e. pass from ''admission'' to ''discussion'' state';
jbe@532 480 COMMENT ON COLUMN "policy"."issue_quorum_num" IS 'Numerator of supporter quorum to be reached by an initiative to be "accepted", i.e. pass from ''admission'' to ''discussion'' state (Note: further requirements apply, see quorum columns of "area" table)';
jbe@532 481 COMMENT ON COLUMN "policy"."issue_quorum_den" IS 'Denominator of supporter quorum to be reached by an initiative to be "accepted", i.e. pass from ''admission'' to ''discussion'' state (Note: further requirements apply, see quorum columns of "area" table)';
jbe@532 482 COMMENT ON COLUMN "policy"."initiative_quorum" IS 'Absolute number of satisfied supporters to be reached by an initiative to be "admitted" for voting';
jbe@532 483 COMMENT ON COLUMN "policy"."initiative_quorum_num" IS 'Numerator of satisfied supporter quorum to be reached by an initiative to be "admitted" for voting';
jbe@532 484 COMMENT ON COLUMN "policy"."initiative_quorum_den" IS 'Denominator of satisfied supporter quorum to be reached by an initiative to be "admitted" for voting';
jbe@532 485
jbe@532 486
jbe@551 487 ALTER TABLE "unit" ADD COLUMN "location" JSONB;
jbe@551 488
jbe@551 489 CREATE INDEX "unit_location_idx" ON "unit" USING gist ((GeoJSON_to_ecluster("location")));
jbe@532 490
jbe@556 491 COMMENT ON COLUMN "unit"."member_count" IS 'Count of members as determined by column "voting_right" in table "privilege" (only active members counted)';
jbe@551 492 COMMENT ON COLUMN "unit"."location" IS 'Geographic location on earth as GeoJSON object indicating valid coordinates for initiatives of issues with this policy';
jbe@532 493
jbe@532 494
jbe@532 495 DROP INDEX "area_unit_id_idx";
jbe@532 496 ALTER TABLE "area" ADD UNIQUE ("unit_id", "id");
jbe@532 497
jbe@532 498 ALTER TABLE "area" ADD COLUMN "quorum_standard" NUMERIC NOT NULL DEFAULT 2 CHECK ("quorum_standard" >= 0);
jbe@532 499 ALTER TABLE "area" ADD COLUMN "quorum_issues" NUMERIC NOT NULL DEFAULT 1 CHECK ("quorum_issues" > 0);
jbe@532 500 ALTER TABLE "area" ADD COLUMN "quorum_time" INTERVAL NOT NULL DEFAULT '1 day' CHECK ("quorum_time" > '0'::INTERVAL);
jbe@532 501 ALTER TABLE "area" ADD COLUMN "quorum_exponent" NUMERIC NOT NULL DEFAULT 0.5 CHECK ("quorum_exponent" BETWEEN 0 AND 1);
jbe@532 502 ALTER TABLE "area" ADD COLUMN "quorum_factor" NUMERIC NOT NULL DEFAULT 2 CHECK ("quorum_factor" >= 1);
jbe@532 503 ALTER TABLE "area" ADD COLUMN "quorum_den" INT4 CHECK ("quorum_den" > 0);
jbe@532 504 ALTER TABLE "area" ADD COLUMN "issue_quorum" INT4;
jbe@551 505 ALTER TABLE "area" ADD COLUMN "location" JSONB;
jbe@532 506
jbe@532 507 ALTER TABLE "area" DROP COLUMN "direct_member_count";
jbe@532 508 ALTER TABLE "area" DROP COLUMN "member_weight";
jbe@532 509
jbe@551 510 CREATE INDEX "area_location_idx" ON "area" USING gist ((GeoJSON_to_ecluster("location")));
jbe@532 511
jbe@532 512 COMMENT ON COLUMN "area"."quorum_standard" IS 'Parameter for dynamic issue quorum: default quorum';
jbe@532 513 COMMENT ON COLUMN "area"."quorum_issues" IS 'Parameter for dynamic issue quorum: number of open issues for default quorum';
jbe@532 514 COMMENT ON COLUMN "area"."quorum_time" IS 'Parameter for dynamic issue quorum: discussion, verification, and voting time of open issues to result in the given default quorum (open issues with shorter time will increase quorum and open issues with longer time will reduce quorum if "quorum_exponent" is greater than zero)';
jbe@532 515 COMMENT ON COLUMN "area"."quorum_exponent" IS 'Parameter for dynamic issue quorum: set to zero to ignore duration of open issues, set to one to fully take duration of open issues into account; defaults to 0.5';
jbe@532 516 COMMENT ON COLUMN "area"."quorum_factor" IS 'Parameter for dynamic issue quorum: factor to increase dynamic quorum when a number of "quorum_issues" issues with "quorum_time" duration of discussion, verification, and voting phase are added to the number of open admitted issues';
jbe@532 517 COMMENT ON COLUMN "area"."quorum_den" IS 'Parameter for dynamic issue quorum: when set, dynamic quorum is multiplied with "issue"."population" and divided by "quorum_den" (and then rounded up)';
jbe@532 518 COMMENT ON COLUMN "area"."issue_quorum" IS 'Additional dynamic issue quorum based on the number of open accepted issues; automatically calculated by function "issue_admission"';
jbe@532 519 COMMENT ON COLUMN "area"."external_reference" IS 'Opaque data field to store an external reference';
jbe@551 520 COMMENT ON COLUMN "area"."location" IS 'Geographic location on earth as GeoJSON object indicating valid coordinates for initiatives of issues with this policy';
jbe@532 521
jbe@532 522
jbe@532 523 CREATE TABLE "snapshot" (
jbe@532 524 UNIQUE ("issue_id", "id"), -- index needed for foreign-key on table "issue"
jbe@532 525 "id" SERIAL8 PRIMARY KEY,
jbe@532 526 "calculated" TIMESTAMPTZ NOT NULL DEFAULT now(),
jbe@532 527 "population" INT4,
jbe@532 528 "area_id" INT4 NOT NULL REFERENCES "area" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
jbe@532 529 "issue_id" INT4 ); -- NOTE: following (cyclic) reference is added later through ALTER command: REFERENCES "issue" ("id") ON DELETE CASCADE ON UPDATE CASCADE
jbe@532 530
jbe@532 531 COMMENT ON TABLE "snapshot" IS 'Point in time when a snapshot of one or more issues (see table "snapshot_issue") and their supporter situation is taken';
jbe@532 532
jbe@532 533
jbe@532 534 CREATE TABLE "snapshot_population" (
jbe@532 535 PRIMARY KEY ("snapshot_id", "member_id"),
jbe@532 536 "snapshot_id" INT8 REFERENCES "snapshot" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
jbe@532 537 "member_id" INT4 REFERENCES "member" ("id") ON DELETE RESTRICT ON UPDATE CASCADE );
jbe@532 538
jbe@532 539 COMMENT ON TABLE "snapshot_population" IS 'Members with voting right relevant for a snapshot';
jbe@532 540
jbe@532 541
jbe@532 542 ALTER TABLE "issue" ADD UNIQUE ("area_id", "id");
jbe@532 543 DROP INDEX "issue_area_id_idx";
jbe@536 544 ALTER TABLE "issue" ADD UNIQUE ("policy_id", "id");
jbe@536 545 DROP INDEX "issue_policy_id_idx";
jbe@532 546
jbe@532 547 ALTER TABLE "issue" RENAME COLUMN "snapshot" TO "calculated";
jbe@532 548
jbe@532 549 ALTER TABLE "issue" ADD COLUMN "latest_snapshot_id" INT8 REFERENCES "snapshot" ("id") ON DELETE RESTRICT ON UPDATE CASCADE;
jbe@532 550 ALTER TABLE "issue" ADD COLUMN "admission_snapshot_id" INT8 REFERENCES "snapshot" ("id") ON DELETE SET NULL ON UPDATE CASCADE;
jbe@532 551 ALTER TABLE "issue" ADD COLUMN "half_freeze_snapshot_id" INT8;
jbe@532 552 ALTER TABLE "issue" ADD COLUMN "full_freeze_snapshot_id" INT8;
jbe@532 553
jbe@532 554 ALTER TABLE "issue" ADD FOREIGN KEY ("id", "half_freeze_snapshot_id")
jbe@532 555 REFERENCES "snapshot" ("issue_id", "id") ON DELETE RESTRICT ON UPDATE CASCADE;
jbe@532 556 ALTER TABLE "issue" ADD FOREIGN KEY ("id", "full_freeze_snapshot_id")
jbe@532 557 REFERENCES "snapshot" ("issue_id", "id") ON DELETE RESTRICT ON UPDATE CASCADE;
jbe@532 558
jbe@532 559 ALTER TABLE "issue" DROP CONSTRAINT "last_snapshot_on_full_freeze";
jbe@532 560 ALTER TABLE "issue" DROP CONSTRAINT "freeze_requires_snapshot";
jbe@532 561 ALTER TABLE "issue" DROP CONSTRAINT "set_both_or_none_of_snapshot_and_latest_snapshot_event";
jbe@532 562
jbe@532 563 CREATE INDEX "issue_state_idx" ON "issue" ("state");
jbe@532 564 CREATE INDEX "issue_latest_snapshot_id" ON "issue" ("latest_snapshot_id");
jbe@532 565 CREATE INDEX "issue_admission_snapshot_id" ON "issue" ("admission_snapshot_id");
jbe@532 566 CREATE INDEX "issue_half_freeze_snapshot_id" ON "issue" ("half_freeze_snapshot_id");
jbe@532 567 CREATE INDEX "issue_full_freeze_snapshot_id" ON "issue" ("full_freeze_snapshot_id");
jbe@532 568
jbe@532 569 COMMENT ON COLUMN "issue"."accepted" IS 'Point in time, when the issue was accepted for further discussion (see columns "issue_quorum_num" and "issue_quorum_den" of table "policy" and quorum columns of table "area")';
jbe@532 570 COMMENT ON COLUMN "issue"."calculated" IS 'Point in time, when most recent snapshot and "population" and *_count values were calculated (NOTE: value is equal to "snapshot"."calculated" of snapshot with "id"="issue"."latest_snapshot_id")';
jbe@532 571 COMMENT ON COLUMN "issue"."latest_snapshot_id" IS 'Snapshot id of most recent snapshot';
jbe@532 572 COMMENT ON COLUMN "issue"."admission_snapshot_id" IS 'Snapshot id when issue as accepted or canceled in admission phase';
jbe@532 573 COMMENT ON COLUMN "issue"."half_freeze_snapshot_id" IS 'Snapshot id at end of discussion phase';
jbe@532 574 COMMENT ON COLUMN "issue"."full_freeze_snapshot_id" IS 'Snapshot id at end of verification phase';
jbe@532 575 COMMENT ON COLUMN "issue"."population" IS 'Count of members in "snapshot_population" table with "snapshot_id" equal to "issue"."latest_snapshot_id"';
jbe@532 576
jbe@532 577
jbe@532 578 ALTER TABLE "snapshot" ADD FOREIGN KEY ("issue_id") REFERENCES "issue" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
jbe@532 579
jbe@532 580
jbe@532 581 ALTER TABLE "initiative" DROP CONSTRAINT "initiative_suggested_initiative_id_fkey";
jbe@532 582 ALTER TABLE "initiative" ADD FOREIGN KEY ("suggested_initiative_id") REFERENCES "initiative" ("id") ON DELETE SET NULL ON UPDATE CASCADE;
jbe@532 583
jbe@532 584 ALTER TABLE "initiative" ADD COLUMN "location" JSONB;
jbe@532 585 ALTER TABLE "initiative" ADD COLUMN "draft_text_search_data" TSVECTOR;
jbe@532 586
jbe@532 587 CREATE INDEX "initiative_location_idx" ON "initiative" USING gist ((GeoJSON_to_ecluster("location")));
jbe@532 588 CREATE INDEX "initiative_draft_text_search_data_idx" ON "initiative" USING gin ("draft_text_search_data");
jbe@532 589
jbe@532 590 COMMENT ON COLUMN "initiative"."location" IS 'Geographic location of initiative as GeoJSON object (automatically copied from most recent draft)';
jbe@532 591
jbe@532 592
jbe@532 593 ALTER TABLE "draft" ADD COLUMN "location" JSONB;
jbe@532 594
jbe@532 595 CREATE INDEX "draft_location_idx" ON "draft" USING gist ((GeoJSON_to_ecluster("location")));
jbe@532 596
jbe@532 597 COMMENT ON COLUMN "draft"."location" IS 'Geographic location of initiative as GeoJSON object (automatically copied to "initiative" table if draft is most recent)';
jbe@532 598
jbe@532 599
jbe@532 600 ALTER TABLE "suggestion" ADD COLUMN "location" JSONB;
jbe@532 601
jbe@532 602 CREATE INDEX "suggestion_location_idx" ON "suggestion" USING gist ((GeoJSON_to_ecluster("location")));
jbe@532 603
jbe@532 604 COMMENT ON COLUMN "suggestion"."location" IS 'Geographic location of suggestion as GeoJSON object';
jbe@532 605
jbe@532 606
jbe@532 607 CREATE TABLE "temporary_suggestion_counts" (
jbe@532 608 "id" INT8 PRIMARY KEY, -- NOTE: no referential integrity due to performance/locking issues; REFERENCES "suggestion" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
jbe@532 609 "minus2_unfulfilled_count" INT4 NOT NULL,
jbe@532 610 "minus2_fulfilled_count" INT4 NOT NULL,
jbe@532 611 "minus1_unfulfilled_count" INT4 NOT NULL,
jbe@532 612 "minus1_fulfilled_count" INT4 NOT NULL,
jbe@532 613 "plus1_unfulfilled_count" INT4 NOT NULL,
jbe@532 614 "plus1_fulfilled_count" INT4 NOT NULL,
jbe@532 615 "plus2_unfulfilled_count" INT4 NOT NULL,
jbe@532 616 "plus2_fulfilled_count" INT4 NOT NULL );
jbe@532 617
jbe@532 618 COMMENT ON TABLE "temporary_suggestion_counts" IS 'Holds certain calculated values (suggestion counts) temporarily until they can be copied into table "suggestion"';
jbe@532 619
jbe@532 620 COMMENT ON COLUMN "temporary_suggestion_counts"."id" IS 'References "suggestion" ("id") but has no referential integrity trigger associated, due to performance/locking issues';
jbe@532 621
jbe@532 622
jbe@532 623 ALTER TABLE "interest" DROP CONSTRAINT "interest_member_id_fkey";
jbe@532 624 ALTER TABLE "interest" ADD FOREIGN KEY ("member_id") REFERENCES "member" ("id") ON DELETE RESTRICT ON UPDATE CASCADE;
jbe@532 625
jbe@532 626
jbe@532 627 ALTER TABLE "initiator" DROP CONSTRAINT "initiator_member_id_fkey";
jbe@532 628 ALTER TABLE "initiator" ADD FOREIGN KEY ("member_id") REFERENCES "member" ("id") ON DELETE RESTRICT ON UPDATE CASCADE;
jbe@532 629
jbe@532 630
jbe@532 631 ALTER TABLE "delegation" DROP CONSTRAINT "delegation_trustee_id_fkey";
jbe@532 632 ALTER TABLE "delegation" ADD FOREIGN KEY ("trustee_id") REFERENCES "member" ("id") ON DELETE RESTRICT ON UPDATE CASCADE;
jbe@532 633
jbe@532 634
jbe@532 635 CREATE TABLE "snapshot_issue" (
jbe@532 636 PRIMARY KEY ("snapshot_id", "issue_id"),
jbe@532 637 "snapshot_id" INT8 REFERENCES "snapshot" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
jbe@532 638 "issue_id" INT4 REFERENCES "issue" ("id") ON DELETE CASCADE ON UPDATE CASCADE );
jbe@532 639 CREATE INDEX "snapshot_issue_issue_id_idx" ON "snapshot_issue" ("issue_id");
jbe@532 640
jbe@532 641 COMMENT ON TABLE "snapshot_issue" IS 'List of issues included in a snapshot';
jbe@532 642
jbe@532 643 COMMENT ON COLUMN "snapshot_issue"."issue_id" IS 'Issue being part of the snapshot; Trigger "delete_snapshot_on_partial_delete" on "snapshot_issue" table will delete snapshot if an issue of the snapshot is deleted.';
jbe@532 644
jbe@532 645
jbe@532 646 ALTER TABLE "direct_interest_snapshot" RENAME TO "direct_interest_snapshot_old"; -- TODO!
jbe@532 647 ALTER INDEX "direct_interest_snapshot_pkey" RENAME TO "direct_interest_snapshot_old_pkey";
jbe@532 648 ALTER INDEX "direct_interest_snapshot_member_id_idx" RENAME TO "direct_interest_snapshot_old_member_id_idx";
jbe@532 649
jbe@532 650 ALTER TABLE "delegating_interest_snapshot" RENAME TO "delegating_interest_snapshot_old"; -- TODO!
jbe@532 651 ALTER INDEX "delegating_interest_snapshot_pkey" RENAME TO "delegating_interest_snapshot_old_pkey";
jbe@532 652 ALTER INDEX "delegating_interest_snapshot_member_id_idx" RENAME TO "delegating_interest_snapshot_old_member_id_idx";
jbe@532 653
jbe@532 654 ALTER TABLE "direct_supporter_snapshot" RENAME TO "direct_supporter_snapshot_old"; -- TODO!
jbe@532 655 ALTER INDEX "direct_supporter_snapshot_pkey" RENAME TO "direct_supporter_snapshot_old_pkey";
jbe@532 656 ALTER INDEX "direct_supporter_snapshot_member_id_idx" RENAME TO "direct_supporter_snapshot_old_member_id_idx";
jbe@532 657
jbe@532 658
jbe@532 659 CREATE TABLE "direct_interest_snapshot" (
jbe@532 660 PRIMARY KEY ("snapshot_id", "issue_id", "member_id"),
jbe@532 661 "snapshot_id" INT8,
jbe@532 662 "issue_id" INT4,
jbe@532 663 FOREIGN KEY ("snapshot_id", "issue_id")
jbe@532 664 REFERENCES "snapshot_issue" ("snapshot_id", "issue_id") ON DELETE CASCADE ON UPDATE CASCADE,
jbe@532 665 "member_id" INT4 REFERENCES "member" ("id") ON DELETE RESTRICT ON UPDATE RESTRICT,
jbe@532 666 "weight" INT4 );
jbe@532 667 CREATE INDEX "direct_interest_snapshot_member_id_idx" ON "direct_interest_snapshot" ("member_id");
jbe@532 668
jbe@532 669 COMMENT ON TABLE "direct_interest_snapshot" IS 'Snapshot of active members having an "interest" in the "issue"; for corrections refer to column "issue_notice" of "issue" table';
jbe@532 670
jbe@532 671 COMMENT ON COLUMN "direct_interest_snapshot"."weight" IS 'Weight of member (1 or higher) according to "delegating_interest_snapshot"';
jbe@532 672
jbe@532 673
jbe@532 674 CREATE TABLE "delegating_interest_snapshot" (
jbe@532 675 PRIMARY KEY ("snapshot_id", "issue_id", "member_id"),
jbe@532 676 "snapshot_id" INT8,
jbe@532 677 "issue_id" INT4,
jbe@532 678 FOREIGN KEY ("snapshot_id", "issue_id")
jbe@532 679 REFERENCES "snapshot_issue" ("snapshot_id", "issue_id") ON DELETE CASCADE ON UPDATE CASCADE,
jbe@532 680 "member_id" INT4 REFERENCES "member" ("id") ON DELETE RESTRICT ON UPDATE RESTRICT,
jbe@532 681 "weight" INT4,
jbe@532 682 "scope" "delegation_scope" NOT NULL,
jbe@532 683 "delegate_member_ids" INT4[] NOT NULL );
jbe@532 684 CREATE INDEX "delegating_interest_snapshot_member_id_idx" ON "delegating_interest_snapshot" ("member_id");
jbe@532 685
jbe@532 686 COMMENT ON TABLE "delegating_interest_snapshot" IS 'Delegations increasing the weight of entries in the "direct_interest_snapshot" table; for corrections refer to column "issue_notice" of "issue" table';
jbe@532 687
jbe@532 688 COMMENT ON COLUMN "delegating_interest_snapshot"."member_id" IS 'Delegating member';
jbe@532 689 COMMENT ON COLUMN "delegating_interest_snapshot"."weight" IS 'Intermediate weight';
jbe@532 690 COMMENT ON COLUMN "delegating_interest_snapshot"."delegate_member_ids" IS 'Chain of members who act as delegates; last entry referes to "member_id" column of table "direct_interest_snapshot"';
jbe@532 691
jbe@532 692
jbe@532 693 CREATE TABLE "direct_supporter_snapshot" (
jbe@532 694 PRIMARY KEY ("snapshot_id", "initiative_id", "member_id"),
jbe@532 695 "snapshot_id" INT8,
jbe@532 696 "issue_id" INT4 NOT NULL,
jbe@532 697 FOREIGN KEY ("snapshot_id", "issue_id")
jbe@532 698 REFERENCES "snapshot_issue" ("snapshot_id", "issue_id") ON DELETE CASCADE ON UPDATE CASCADE,
jbe@532 699 "initiative_id" INT4,
jbe@532 700 "member_id" INT4 REFERENCES "member" ("id") ON DELETE RESTRICT ON UPDATE RESTRICT,
jbe@532 701 "draft_id" INT8 NOT NULL,
jbe@532 702 "informed" BOOLEAN NOT NULL,
jbe@532 703 "satisfied" BOOLEAN NOT NULL,
jbe@532 704 FOREIGN KEY ("issue_id", "initiative_id") REFERENCES "initiative" ("issue_id", "id") ON DELETE CASCADE ON UPDATE CASCADE,
jbe@532 705 FOREIGN KEY ("initiative_id", "draft_id") REFERENCES "draft" ("initiative_id", "id") ON DELETE NO ACTION ON UPDATE CASCADE,
jbe@532 706 FOREIGN KEY ("snapshot_id", "issue_id", "member_id") REFERENCES "direct_interest_snapshot" ("snapshot_id", "issue_id", "member_id") ON DELETE CASCADE ON UPDATE CASCADE );
jbe@532 707 CREATE INDEX "direct_supporter_snapshot_member_id_idx" ON "direct_supporter_snapshot" ("member_id");
jbe@532 708
jbe@532 709 COMMENT ON TABLE "direct_supporter_snapshot" IS 'Snapshot of supporters of initiatives (weight is stored in "direct_interest_snapshot"); for corrections refer to column "issue_notice" of "issue" table';
jbe@532 710
jbe@532 711 COMMENT ON COLUMN "direct_supporter_snapshot"."issue_id" IS 'WARNING: No index: For selections use column "initiative_id" and join via table "initiative" where neccessary';
jbe@532 712 COMMENT ON COLUMN "direct_supporter_snapshot"."informed" IS 'Supporter has seen the latest draft of the initiative';
jbe@532 713 COMMENT ON COLUMN "direct_supporter_snapshot"."satisfied" IS 'Supporter has no "critical_opinion"s';
jbe@532 714
jbe@532 715
jbe@532 716 ALTER TABLE "non_voter" DROP CONSTRAINT "non_voter_pkey";
jbe@532 717 DROP INDEX "non_voter_member_id_idx";
jbe@532 718
jbe@532 719 ALTER TABLE "non_voter" ADD PRIMARY KEY ("member_id", "issue_id");
jbe@532 720 CREATE INDEX "non_voter_issue_id_idx" ON "non_voter" ("issue_id");
jbe@532 721
jbe@532 722
jbe@545 723 INSERT INTO "member_useterms" ("member_id", "accepted", "contract_identifier")
jbe@545 724 SELECT
jbe@545 725 "member_id",
jbe@545 726 regexp_replace("value", '^accepted at ', '')::TIMESTAMPTZ AS "accepted",
jbe@545 727 regexp_replace("key", '^use_terms_checkbox_', '') AS "contract_identifier"
jbe@545 728 FROM "setting" WHERE "key" LIKE 'use_terms_checkbox_%';
jbe@545 729
jbe@545 730
jbe@542 731 DROP TABLE "setting";
jbe@542 732 DROP TABLE "setting_map";
jbe@542 733 DROP TABLE "member_relation_setting";
jbe@542 734 DROP TABLE "unit_setting";
jbe@542 735 DROP TABLE "area_setting";
jbe@542 736 DROP TABLE "initiative_setting";
jbe@542 737 DROP TABLE "suggestion_setting";
jbe@542 738
jbe@542 739
jbe@532 740 ALTER TABLE "event" ADD COLUMN "other_member_id" INT4 REFERENCES "member" ("id") ON DELETE RESTRICT ON UPDATE CASCADE;
jbe@532 741 ALTER TABLE "event" ADD COLUMN "scope" "delegation_scope";
jbe@532 742 ALTER TABLE "event" ADD COLUMN "unit_id" INT4 REFERENCES "unit" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
jbe@532 743 ALTER TABLE "event" ADD COLUMN "area_id" INT4;
jbe@536 744 ALTER TABLE "event" ADD COLUMN "policy_id" INT4 REFERENCES "policy" ("id") ON DELETE CASCADE ON UPDATE CASCADE;
jbe@532 745 ALTER TABLE "event" ADD COLUMN "boolean_value" BOOLEAN;
jbe@532 746 ALTER TABLE "event" ADD COLUMN "numeric_value" INT4;
jbe@532 747 ALTER TABLE "event" ADD COLUMN "text_value" TEXT;
jbe@532 748 ALTER TABLE "event" ADD COLUMN "old_text_value" TEXT;
jbe@532 749
jbe@532 750 ALTER TABLE "event" ADD FOREIGN KEY ("unit_id", "area_id") REFERENCES "area" ("unit_id", "id") ON DELETE CASCADE ON UPDATE CASCADE;
jbe@532 751 ALTER TABLE "event" ADD FOREIGN KEY ("area_id", "issue_id") REFERENCES "issue" ("area_id", "id") ON DELETE CASCADE ON UPDATE CASCADE;
jbe@536 752 ALTER TABLE "event" ADD FOREIGN KEY ("policy_id", "issue_id") REFERENCES "issue" ("policy_id", "id") ON DELETE CASCADE ON UPDATE CASCADE;
jbe@532 753
jbe@532 754 ALTER TABLE "event" DROP CONSTRAINT "event_initiative_id_fkey1";
jbe@532 755 ALTER TABLE "event" DROP CONSTRAINT "null_constr_for_issue_state_changed";
jbe@532 756 ALTER TABLE "event" DROP CONSTRAINT "null_constr_for_initiative_creation_or_revocation_or_new_draft";
jbe@532 757 ALTER TABLE "event" DROP CONSTRAINT "null_constr_for_suggestion_creation";
jbe@532 758
jbe@553 759 UPDATE "event" SET
jbe@553 760 "unit_id" = "area"."unit_id",
jbe@553 761 "area_id" = "issue"."area_id",
jbe@553 762 "policy_id" = "issue"."policy_id"
jbe@532 763 FROM "issue", "area"
jbe@532 764 WHERE "issue"."id" = "event"."issue_id" AND "area"."id" = "issue"."area_id";
jbe@532 765
jbe@532 766 ALTER TABLE "event" ADD CONSTRAINT "constr_for_issue_state_changed" CHECK (
jbe@532 767 "event" != 'issue_state_changed' OR (
jbe@532 768 "member_id" ISNULL AND
jbe@532 769 "other_member_id" ISNULL AND
jbe@532 770 "scope" ISNULL AND
jbe@532 771 "unit_id" NOTNULL AND
jbe@532 772 "area_id" NOTNULL AND
jbe@536 773 "policy_id" NOTNULL AND
jbe@532 774 "issue_id" NOTNULL AND
jbe@532 775 "state" NOTNULL AND
jbe@532 776 "initiative_id" ISNULL AND
jbe@532 777 "draft_id" ISNULL AND
jbe@532 778 "suggestion_id" ISNULL AND
jbe@532 779 "boolean_value" ISNULL AND
jbe@532 780 "numeric_value" ISNULL AND
jbe@532 781 "text_value" ISNULL AND
jbe@532 782 "old_text_value" ISNULL ));
jbe@532 783 ALTER TABLE "event" ADD CONSTRAINT "constr_for_initiative_creation_or_revocation_or_new_draft" CHECK (
jbe@532 784 "event" NOT IN (
jbe@532 785 'initiative_created_in_new_issue',
jbe@532 786 'initiative_created_in_existing_issue',
jbe@532 787 'initiative_revoked',
jbe@532 788 'new_draft_created'
jbe@532 789 ) OR (
jbe@532 790 "member_id" NOTNULL AND
jbe@532 791 "other_member_id" ISNULL AND
jbe@532 792 "scope" ISNULL AND
jbe@532 793 "unit_id" NOTNULL AND
jbe@532 794 "area_id" NOTNULL AND
jbe@536 795 "policy_id" NOTNULL AND
jbe@532 796 "issue_id" NOTNULL AND
jbe@532 797 "state" NOTNULL AND
jbe@532 798 "initiative_id" NOTNULL AND
jbe@532 799 "draft_id" NOTNULL AND
jbe@532 800 "suggestion_id" ISNULL AND
jbe@532 801 "boolean_value" ISNULL AND
jbe@532 802 "numeric_value" ISNULL AND
jbe@532 803 "text_value" ISNULL AND
jbe@532 804 "old_text_value" ISNULL ));
jbe@532 805 ALTER TABLE "event" ADD CONSTRAINT "constr_for_suggestion_creation" CHECK (
jbe@532 806 "event" != 'suggestion_created' OR (
jbe@532 807 "member_id" NOTNULL AND
jbe@532 808 "other_member_id" ISNULL AND
jbe@532 809 "scope" ISNULL AND
jbe@532 810 "unit_id" NOTNULL AND
jbe@532 811 "area_id" NOTNULL AND
jbe@536 812 "policy_id" NOTNULL AND
jbe@532 813 "issue_id" NOTNULL AND
jbe@532 814 "state" NOTNULL AND
jbe@532 815 "initiative_id" NOTNULL AND
jbe@532 816 "draft_id" ISNULL AND
jbe@532 817 "suggestion_id" NOTNULL AND
jbe@532 818 "boolean_value" ISNULL AND
jbe@532 819 "numeric_value" ISNULL AND
jbe@532 820 "text_value" ISNULL AND
jbe@532 821 "old_text_value" ISNULL ));
jbe@532 822 ALTER TABLE "event" ADD CONSTRAINT "constr_for_suggestion_removal" CHECK (
jbe@554 823 "event" != 'suggestion_deleted' OR (
jbe@532 824 "member_id" ISNULL AND
jbe@532 825 "other_member_id" ISNULL AND
jbe@532 826 "scope" ISNULL AND
jbe@532 827 "unit_id" NOTNULL AND
jbe@532 828 "area_id" NOTNULL AND
jbe@536 829 "policy_id" NOTNULL AND
jbe@532 830 "issue_id" NOTNULL AND
jbe@532 831 "state" NOTNULL AND
jbe@532 832 "initiative_id" NOTNULL AND
jbe@532 833 "draft_id" ISNULL AND
jbe@532 834 "suggestion_id" NOTNULL AND
jbe@532 835 "boolean_value" ISNULL AND
jbe@532 836 "numeric_value" ISNULL AND
jbe@532 837 "text_value" ISNULL AND
jbe@532 838 "old_text_value" ISNULL ));
jbe@532 839 ALTER TABLE "event" ADD CONSTRAINT "constr_for_value_less_member_event" CHECK (
jbe@532 840 "event" NOT IN (
jbe@532 841 'member_activated',
jbe@554 842 'member_deleted',
jbe@532 843 'member_profile_updated',
jbe@532 844 'member_image_updated'
jbe@532 845 ) OR (
jbe@532 846 "member_id" NOTNULL AND
jbe@532 847 "other_member_id" ISNULL AND
jbe@532 848 "scope" ISNULL AND
jbe@532 849 "unit_id" ISNULL AND
jbe@532 850 "area_id" ISNULL AND
jbe@536 851 "policy_id" ISNULL AND
jbe@532 852 "issue_id" ISNULL AND
jbe@532 853 "state" ISNULL AND
jbe@532 854 "initiative_id" ISNULL AND
jbe@532 855 "draft_id" ISNULL AND
jbe@532 856 "suggestion_id" ISNULL AND
jbe@532 857 "boolean_value" ISNULL AND
jbe@532 858 "numeric_value" ISNULL AND
jbe@532 859 "text_value" ISNULL AND
jbe@532 860 "old_text_value" ISNULL ));
jbe@532 861 ALTER TABLE "event" ADD CONSTRAINT "constr_for_member_active" CHECK (
jbe@532 862 "event" != 'member_active' OR (
jbe@532 863 "member_id" NOTNULL AND
jbe@532 864 "other_member_id" ISNULL AND
jbe@532 865 "scope" ISNULL AND
jbe@532 866 "unit_id" ISNULL AND
jbe@532 867 "area_id" ISNULL AND
jbe@536 868 "policy_id" ISNULL AND
jbe@532 869 "issue_id" ISNULL AND
jbe@532 870 "state" ISNULL AND
jbe@532 871 "initiative_id" ISNULL AND
jbe@532 872 "draft_id" ISNULL AND
jbe@532 873 "suggestion_id" ISNULL AND
jbe@532 874 "boolean_value" NOTNULL AND
jbe@532 875 "numeric_value" ISNULL AND
jbe@532 876 "text_value" ISNULL AND
jbe@532 877 "old_text_value" ISNULL ));
jbe@532 878 ALTER TABLE "event" ADD CONSTRAINT "constr_for_member_name_updated" CHECK (
jbe@532 879 "event" != 'member_name_updated' OR (
jbe@532 880 "member_id" NOTNULL AND
jbe@532 881 "other_member_id" ISNULL AND
jbe@532 882 "scope" ISNULL AND
jbe@532 883 "unit_id" ISNULL AND
jbe@532 884 "area_id" ISNULL AND
jbe@536 885 "policy_id" ISNULL AND
jbe@532 886 "issue_id" ISNULL AND
jbe@532 887 "state" ISNULL AND
jbe@532 888 "initiative_id" ISNULL AND
jbe@532 889 "draft_id" ISNULL AND
jbe@532 890 "suggestion_id" ISNULL AND
jbe@532 891 "boolean_value" ISNULL AND
jbe@532 892 "numeric_value" ISNULL AND
jbe@532 893 "text_value" NOTNULL AND
jbe@532 894 "old_text_value" NOTNULL ));
jbe@532 895 ALTER TABLE "event" ADD CONSTRAINT "constr_for_interest" CHECK (
jbe@532 896 "event" != 'interest' OR (
jbe@532 897 "member_id" NOTNULL AND
jbe@532 898 "other_member_id" ISNULL AND
jbe@532 899 "scope" ISNULL AND
jbe@532 900 "unit_id" NOTNULL AND
jbe@532 901 "area_id" NOTNULL AND
jbe@536 902 "policy_id" NOTNULL AND
jbe@532 903 "issue_id" NOTNULL AND
jbe@532 904 "state" NOTNULL AND
jbe@532 905 "initiative_id" ISNULL AND
jbe@532 906 "draft_id" ISNULL AND
jbe@532 907 "suggestion_id" ISNULL AND
jbe@532 908 "boolean_value" NOTNULL AND
jbe@532 909 "numeric_value" ISNULL AND
jbe@532 910 "text_value" ISNULL AND
jbe@532 911 "old_text_value" ISNULL ));
jbe@532 912 ALTER TABLE "event" ADD CONSTRAINT "constr_for_initiator" CHECK (
jbe@532 913 "event" != 'initiator' OR (
jbe@532 914 "member_id" NOTNULL AND
jbe@532 915 "other_member_id" ISNULL AND
jbe@532 916 "scope" ISNULL AND
jbe@532 917 "unit_id" NOTNULL AND
jbe@532 918 "area_id" NOTNULL AND
jbe@536 919 "policy_id" NOTNULL AND
jbe@532 920 "issue_id" NOTNULL AND
jbe@532 921 "state" NOTNULL AND
jbe@532 922 "initiative_id" NOTNULL AND
jbe@532 923 "draft_id" ISNULL AND
jbe@532 924 "suggestion_id" ISNULL AND
jbe@532 925 "boolean_value" NOTNULL AND
jbe@532 926 "numeric_value" ISNULL AND
jbe@532 927 "text_value" ISNULL AND
jbe@532 928 "old_text_value" ISNULL ));
jbe@532 929 ALTER TABLE "event" ADD CONSTRAINT "constr_for_support" CHECK (
jbe@532 930 "event" != 'support' OR (
jbe@532 931 "member_id" NOTNULL AND
jbe@532 932 "other_member_id" ISNULL AND
jbe@532 933 "scope" ISNULL AND
jbe@532 934 "unit_id" NOTNULL AND
jbe@532 935 "area_id" NOTNULL AND
jbe@536 936 "policy_id" NOTNULL AND
jbe@532 937 "issue_id" NOTNULL AND
jbe@532 938 "state" NOTNULL AND
jbe@532 939 "initiative_id" NOTNULL AND
jbe@532 940 ("draft_id" NOTNULL) = ("boolean_value" = TRUE) AND
jbe@532 941 "suggestion_id" ISNULL AND
jbe@532 942 "boolean_value" NOTNULL AND
jbe@532 943 "numeric_value" ISNULL AND
jbe@532 944 "text_value" ISNULL AND
jbe@532 945 "old_text_value" ISNULL ));
jbe@532 946 ALTER TABLE "event" ADD CONSTRAINT "constr_for_support_updated" CHECK (
jbe@532 947 "event" != 'support_updated' OR (
jbe@532 948 "member_id" NOTNULL AND
jbe@532 949 "other_member_id" ISNULL AND
jbe@532 950 "scope" ISNULL AND
jbe@532 951 "unit_id" NOTNULL AND
jbe@532 952 "area_id" NOTNULL AND
jbe@536 953 "policy_id" NOTNULL AND
jbe@532 954 "issue_id" NOTNULL AND
jbe@532 955 "state" NOTNULL AND
jbe@532 956 "initiative_id" NOTNULL AND
jbe@532 957 "draft_id" NOTNULL AND
jbe@532 958 "suggestion_id" ISNULL AND
jbe@532 959 "boolean_value" ISNULL AND
jbe@532 960 "numeric_value" ISNULL AND
jbe@532 961 "text_value" ISNULL AND
jbe@532 962 "old_text_value" ISNULL ));
jbe@532 963 ALTER TABLE "event" ADD CONSTRAINT "constr_for_suggestion_rated" CHECK (
jbe@532 964 "event" != 'suggestion_rated' OR (
jbe@532 965 "member_id" NOTNULL AND
jbe@532 966 "other_member_id" ISNULL AND
jbe@532 967 "scope" ISNULL AND
jbe@532 968 "unit_id" NOTNULL AND
jbe@532 969 "area_id" NOTNULL AND
jbe@536 970 "policy_id" NOTNULL AND
jbe@532 971 "issue_id" NOTNULL AND
jbe@532 972 "state" NOTNULL AND
jbe@532 973 "initiative_id" NOTNULL AND
jbe@532 974 "draft_id" ISNULL AND
jbe@532 975 "suggestion_id" NOTNULL AND
jbe@532 976 ("boolean_value" NOTNULL) = ("numeric_value" != 0) AND
jbe@532 977 "numeric_value" NOTNULL AND
jbe@532 978 "numeric_value" IN (-2, -1, 0, 1, 2) AND
jbe@532 979 "text_value" ISNULL AND
jbe@532 980 "old_text_value" ISNULL ));
jbe@532 981 ALTER TABLE "event" ADD CONSTRAINT "constr_for_delegation" CHECK (
jbe@532 982 "event" != 'delegation' OR (
jbe@532 983 "member_id" NOTNULL AND
jbe@532 984 ("other_member_id" NOTNULL) OR ("boolean_value" = FALSE) AND
jbe@532 985 "scope" NOTNULL AND
jbe@532 986 "unit_id" NOTNULL AND
jbe@532 987 ("area_id" NOTNULL) = ("scope" != 'unit'::"delegation_scope") AND
jbe@536 988 "policy_id" ISNULL AND
jbe@532 989 ("issue_id" NOTNULL) = ("scope" = 'issue'::"delegation_scope") AND
jbe@532 990 ("state" NOTNULL) = ("scope" = 'issue'::"delegation_scope") AND
jbe@532 991 "initiative_id" ISNULL AND
jbe@532 992 "draft_id" ISNULL AND
jbe@532 993 "suggestion_id" ISNULL AND
jbe@532 994 "boolean_value" NOTNULL AND
jbe@532 995 "numeric_value" ISNULL AND
jbe@532 996 "text_value" ISNULL AND
jbe@532 997 "old_text_value" ISNULL ));
jbe@532 998 ALTER TABLE "event" ADD CONSTRAINT "constr_for_contact" CHECK (
jbe@532 999 "event" != 'contact' OR (
jbe@532 1000 "member_id" NOTNULL AND
jbe@532 1001 "other_member_id" NOTNULL AND
jbe@532 1002 "scope" ISNULL AND
jbe@532 1003 "unit_id" ISNULL AND
jbe@532 1004 "area_id" ISNULL AND
jbe@536 1005 "policy_id" ISNULL AND
jbe@532 1006 "issue_id" ISNULL AND
jbe@532 1007 "state" ISNULL AND
jbe@532 1008 "initiative_id" ISNULL AND
jbe@532 1009 "draft_id" ISNULL AND
jbe@532 1010 "suggestion_id" ISNULL AND
jbe@532 1011 "boolean_value" NOTNULL AND
jbe@532 1012 "numeric_value" ISNULL AND
jbe@532 1013 "text_value" ISNULL AND
jbe@532 1014 "old_text_value" ISNULL ));
jbe@532 1015
jbe@532 1016
jbe@534 1017 ALTER TABLE "notification_event_sent" RENAME TO "event_processed";
jbe@534 1018 ALTER INDEX "notification_event_sent_singleton_idx" RENAME TO "event_processed_singleton_idx";
jbe@534 1019
jbe@534 1020 COMMENT ON TABLE "event_processed" IS 'This table stores one row with the last event_id, for which event handlers have been executed (e.g. notifications having been sent out)';
jbe@534 1021 COMMENT ON INDEX "event_processed_singleton_idx" IS 'This index ensures that "event_processed" only contains one row maximum.';
jbe@534 1022
jbe@534 1023
jbe@537 1024 CREATE FUNCTION "write_event_unit_trigger"()
jbe@537 1025 RETURNS TRIGGER
jbe@537 1026 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@538 1027 DECLARE
jbe@538 1028 "event_v" "event_type";
jbe@537 1029 BEGIN
jbe@538 1030 IF TG_OP = 'UPDATE' THEN
jbe@538 1031 IF OLD."active" = FALSE AND NEW."active" = FALSE THEN
jbe@538 1032 RETURN NULL;
jbe@547 1033 --ELSIF OLD."active" = FALSE AND NEW."active" = TRUE THEN
jbe@547 1034 -- "event_v" := 'unit_created';
jbe@547 1035 --ELSIF OLD."active" = TRUE AND NEW."active" = FALSE THEN
jbe@554 1036 -- "event_v" := 'unit_deleted';
jbe@546 1037 ELSIF OLD != NEW THEN
jbe@546 1038 "event_v" := 'unit_updated';
jbe@538 1039 ELSE
jbe@546 1040 RETURN NULL;
jbe@538 1041 END IF;
jbe@538 1042 ELSE
jbe@538 1043 "event_v" := 'unit_created';
jbe@538 1044 END IF;
jbe@538 1045 INSERT INTO "event" ("event", "unit_id") VALUES ("event_v", NEW."id");
jbe@537 1046 RETURN NULL;
jbe@537 1047 END;
jbe@537 1048 $$;
jbe@537 1049
jbe@537 1050 CREATE TRIGGER "write_event_unit" AFTER INSERT OR UPDATE ON "unit"
jbe@537 1051 FOR EACH ROW EXECUTE PROCEDURE "write_event_unit_trigger"();
jbe@537 1052
jbe@537 1053 COMMENT ON FUNCTION "write_event_unit_trigger"() IS 'Implementation of trigger "write_event_unit" on table "unit"';
jbe@537 1054 COMMENT ON TRIGGER "write_event_unit" ON "unit" IS 'Create entry in "event" table on new or changed/disabled units';
jbe@537 1055
jbe@537 1056
jbe@537 1057 CREATE FUNCTION "write_event_area_trigger"()
jbe@537 1058 RETURNS TRIGGER
jbe@537 1059 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@538 1060 DECLARE
jbe@538 1061 "event_v" "event_type";
jbe@537 1062 BEGIN
jbe@538 1063 IF TG_OP = 'UPDATE' THEN
jbe@538 1064 IF OLD."active" = FALSE AND NEW."active" = FALSE THEN
jbe@538 1065 RETURN NULL;
jbe@547 1066 --ELSIF OLD."active" = FALSE AND NEW."active" = TRUE THEN
jbe@547 1067 -- "event_v" := 'area_created';
jbe@547 1068 --ELSIF OLD."active" = TRUE AND NEW."active" = FALSE THEN
jbe@554 1069 -- "event_v" := 'area_deleted';
jbe@546 1070 ELSIF OLD != NEW THEN
jbe@546 1071 "event_v" := 'area_updated';
jbe@538 1072 ELSE
jbe@546 1073 RETURN NULL;
jbe@538 1074 END IF;
jbe@538 1075 ELSE
jbe@538 1076 "event_v" := 'area_created';
jbe@538 1077 END IF;
jbe@538 1078 INSERT INTO "event" ("event", "area_id") VALUES ("event_v", NEW."id");
jbe@537 1079 RETURN NULL;
jbe@537 1080 END;
jbe@537 1081 $$;
jbe@537 1082
jbe@537 1083 CREATE TRIGGER "write_event_area" AFTER INSERT OR UPDATE ON "area"
jbe@537 1084 FOR EACH ROW EXECUTE PROCEDURE "write_event_area_trigger"();
jbe@537 1085
jbe@537 1086 COMMENT ON FUNCTION "write_event_area_trigger"() IS 'Implementation of trigger "write_event_area" on table "area"';
jbe@537 1087 COMMENT ON TRIGGER "write_event_area" ON "area" IS 'Create entry in "event" table on new or changed/disabled areas';
jbe@537 1088
jbe@537 1089
jbe@537 1090 CREATE FUNCTION "write_event_policy_trigger"()
jbe@537 1091 RETURNS TRIGGER
jbe@537 1092 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@538 1093 DECLARE
jbe@538 1094 "event_v" "event_type";
jbe@537 1095 BEGIN
jbe@538 1096 IF TG_OP = 'UPDATE' THEN
jbe@538 1097 IF OLD."active" = FALSE AND NEW."active" = FALSE THEN
jbe@538 1098 RETURN NULL;
jbe@547 1099 --ELSIF OLD."active" = FALSE AND NEW."active" = TRUE THEN
jbe@547 1100 -- "event_v" := 'policy_created';
jbe@547 1101 --ELSIF OLD."active" = TRUE AND NEW."active" = FALSE THEN
jbe@554 1102 -- "event_v" := 'policy_deleted';
jbe@546 1103 ELSIF OLD != NEW THEN
jbe@546 1104 "event_v" := 'policy_updated';
jbe@538 1105 ELSE
jbe@546 1106 RETURN NULL;
jbe@538 1107 END IF;
jbe@538 1108 ELSE
jbe@538 1109 "event_v" := 'policy_created';
jbe@538 1110 END IF;
jbe@538 1111 INSERT INTO "event" ("event", "policy_id") VALUES ("event_v", NEW."id");
jbe@537 1112 RETURN NULL;
jbe@537 1113 END;
jbe@537 1114 $$;
jbe@537 1115
jbe@537 1116 CREATE TRIGGER "write_event_policy" AFTER INSERT OR UPDATE ON "policy"
jbe@537 1117 FOR EACH ROW EXECUTE PROCEDURE "write_event_policy_trigger"();
jbe@537 1118
jbe@537 1119 COMMENT ON FUNCTION "write_event_policy_trigger"() IS 'Implementation of trigger "write_event_policy" on table "policy"';
jbe@537 1120 COMMENT ON TRIGGER "write_event_policy" ON "policy" IS 'Create entry in "event" table on new or changed/disabled policies';
jbe@537 1121
jbe@537 1122
jbe@532 1123 CREATE OR REPLACE FUNCTION "write_event_issue_state_changed_trigger"()
jbe@532 1124 RETURNS TRIGGER
jbe@532 1125 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 1126 DECLARE
jbe@532 1127 "area_row" "area"%ROWTYPE;
jbe@532 1128 BEGIN
jbe@532 1129 IF NEW."state" != OLD."state" THEN
jbe@532 1130 SELECT * INTO "area_row" FROM "area" WHERE "id" = NEW."area_id"
jbe@532 1131 FOR SHARE;
jbe@532 1132 INSERT INTO "event" (
jbe@532 1133 "event",
jbe@536 1134 "unit_id", "area_id", "policy_id", "issue_id", "state"
jbe@532 1135 ) VALUES (
jbe@532 1136 'issue_state_changed',
jbe@536 1137 "area_row"."unit_id", NEW."area_id", NEW."policy_id",
jbe@536 1138 NEW."id", NEW."state"
jbe@532 1139 );
jbe@532 1140 END IF;
jbe@532 1141 RETURN NULL;
jbe@532 1142 END;
jbe@532 1143 $$;
jbe@532 1144
jbe@532 1145
jbe@532 1146 CREATE OR REPLACE FUNCTION "write_event_initiative_or_draft_created_trigger"()
jbe@532 1147 RETURNS TRIGGER
jbe@532 1148 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 1149 DECLARE
jbe@532 1150 "initiative_row" "initiative"%ROWTYPE;
jbe@532 1151 "issue_row" "issue"%ROWTYPE;
jbe@532 1152 "area_row" "area"%ROWTYPE;
jbe@532 1153 "event_v" "event_type";
jbe@532 1154 BEGIN
jbe@532 1155 SELECT * INTO "initiative_row" FROM "initiative"
jbe@532 1156 WHERE "id" = NEW."initiative_id" FOR SHARE;
jbe@532 1157 SELECT * INTO "issue_row" FROM "issue"
jbe@532 1158 WHERE "id" = "initiative_row"."issue_id" FOR SHARE;
jbe@532 1159 SELECT * INTO "area_row" FROM "area"
jbe@532 1160 WHERE "id" = "issue_row"."area_id" FOR SHARE;
jbe@532 1161 IF EXISTS (
jbe@532 1162 SELECT NULL FROM "draft"
jbe@532 1163 WHERE "initiative_id" = NEW."initiative_id" AND "id" != NEW."id"
jbe@532 1164 FOR SHARE
jbe@532 1165 ) THEN
jbe@532 1166 "event_v" := 'new_draft_created';
jbe@532 1167 ELSE
jbe@532 1168 IF EXISTS (
jbe@532 1169 SELECT NULL FROM "initiative"
jbe@532 1170 WHERE "issue_id" = "initiative_row"."issue_id"
jbe@532 1171 AND "id" != "initiative_row"."id"
jbe@532 1172 FOR SHARE
jbe@532 1173 ) THEN
jbe@532 1174 "event_v" := 'initiative_created_in_existing_issue';
jbe@532 1175 ELSE
jbe@532 1176 "event_v" := 'initiative_created_in_new_issue';
jbe@532 1177 END IF;
jbe@532 1178 END IF;
jbe@532 1179 INSERT INTO "event" (
jbe@532 1180 "event", "member_id",
jbe@536 1181 "unit_id", "area_id", "policy_id", "issue_id", "state",
jbe@532 1182 "initiative_id", "draft_id"
jbe@532 1183 ) VALUES (
jbe@532 1184 "event_v", NEW."author_id",
jbe@536 1185 "area_row"."unit_id", "issue_row"."area_id", "issue_row"."policy_id",
jbe@532 1186 "initiative_row"."issue_id", "issue_row"."state",
jbe@532 1187 NEW."initiative_id", NEW."id"
jbe@532 1188 );
jbe@532 1189 RETURN NULL;
jbe@532 1190 END;
jbe@532 1191 $$;
jbe@532 1192
jbe@532 1193
jbe@532 1194 CREATE OR REPLACE FUNCTION "write_event_initiative_revoked_trigger"()
jbe@532 1195 RETURNS TRIGGER
jbe@532 1196 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 1197 DECLARE
jbe@532 1198 "issue_row" "issue"%ROWTYPE;
jbe@532 1199 "area_row" "area"%ROWTYPE;
jbe@532 1200 "draft_id_v" "draft"."id"%TYPE;
jbe@532 1201 BEGIN
jbe@532 1202 IF OLD."revoked" ISNULL AND NEW."revoked" NOTNULL THEN
jbe@563 1203 -- NOTE: lock for primary key update to avoid new drafts
jbe@563 1204 SELECT NULL FROM "initiative" WHERE "id" = NEW."id" FOR UPDATE;
jbe@532 1205 SELECT * INTO "issue_row" FROM "issue"
jbe@532 1206 WHERE "id" = NEW."issue_id" FOR SHARE;
jbe@532 1207 SELECT * INTO "area_row" FROM "area"
jbe@532 1208 WHERE "id" = "issue_row"."area_id" FOR SHARE;
jbe@563 1209 -- NOTE: FOR SHARE cannot be used with DISTINCT in view "current_draft"
jbe@563 1210 SELECT NULL FROM "draft" WHERE "initiative_id" = NEW."id" FOR SHARE;
jbe@532 1211 SELECT "id" INTO "draft_id_v" FROM "current_draft"
jbe@563 1212 WHERE "initiative_id" = NEW."id";
jbe@532 1213 INSERT INTO "event" (
jbe@532 1214 "event", "member_id",
jbe@536 1215 "unit_id", "area_id", "policy_id", "issue_id", "state",
jbe@532 1216 "initiative_id", "draft_id"
jbe@532 1217 ) VALUES (
jbe@532 1218 'initiative_revoked', NEW."revoked_by_member_id",
jbe@532 1219 "area_row"."unit_id", "issue_row"."area_id",
jbe@536 1220 "issue_row"."policy_id",
jbe@532 1221 NEW."issue_id", "issue_row"."state",
jbe@532 1222 NEW."id", "draft_id_v"
jbe@532 1223 );
jbe@532 1224 END IF;
jbe@532 1225 RETURN NULL;
jbe@532 1226 END;
jbe@532 1227 $$;
jbe@532 1228
jbe@532 1229
jbe@532 1230 CREATE OR REPLACE FUNCTION "write_event_suggestion_created_trigger"()
jbe@532 1231 RETURNS TRIGGER
jbe@532 1232 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 1233 DECLARE
jbe@532 1234 "initiative_row" "initiative"%ROWTYPE;
jbe@532 1235 "issue_row" "issue"%ROWTYPE;
jbe@532 1236 "area_row" "area"%ROWTYPE;
jbe@532 1237 BEGIN
jbe@532 1238 SELECT * INTO "initiative_row" FROM "initiative"
jbe@532 1239 WHERE "id" = NEW."initiative_id" FOR SHARE;
jbe@532 1240 SELECT * INTO "issue_row" FROM "issue"
jbe@532 1241 WHERE "id" = "initiative_row"."issue_id" FOR SHARE;
jbe@532 1242 SELECT * INTO "area_row" FROM "area"
jbe@532 1243 WHERE "id" = "issue_row"."area_id" FOR SHARE;
jbe@532 1244 INSERT INTO "event" (
jbe@532 1245 "event", "member_id",
jbe@536 1246 "unit_id", "area_id", "policy_id", "issue_id", "state",
jbe@532 1247 "initiative_id", "suggestion_id"
jbe@532 1248 ) VALUES (
jbe@532 1249 'suggestion_created', NEW."author_id",
jbe@536 1250 "area_row"."unit_id", "issue_row"."area_id", "issue_row"."policy_id",
jbe@532 1251 "initiative_row"."issue_id", "issue_row"."state",
jbe@532 1252 NEW."initiative_id", NEW."id"
jbe@532 1253 );
jbe@532 1254 RETURN NULL;
jbe@532 1255 END;
jbe@532 1256 $$;
jbe@532 1257
jbe@532 1258
jbe@532 1259 CREATE FUNCTION "write_event_suggestion_removed_trigger"()
jbe@532 1260 RETURNS TRIGGER
jbe@532 1261 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 1262 DECLARE
jbe@532 1263 "initiative_row" "initiative"%ROWTYPE;
jbe@532 1264 "issue_row" "issue"%ROWTYPE;
jbe@532 1265 "area_row" "area"%ROWTYPE;
jbe@532 1266 BEGIN
jbe@532 1267 SELECT * INTO "initiative_row" FROM "initiative"
jbe@532 1268 WHERE "id" = OLD."initiative_id" FOR SHARE;
jbe@532 1269 IF "initiative_row"."id" NOTNULL THEN
jbe@532 1270 SELECT * INTO "issue_row" FROM "issue"
jbe@532 1271 WHERE "id" = "initiative_row"."issue_id" FOR SHARE;
jbe@532 1272 SELECT * INTO "area_row" FROM "area"
jbe@532 1273 WHERE "id" = "issue_row"."area_id" FOR SHARE;
jbe@532 1274 INSERT INTO "event" (
jbe@532 1275 "event",
jbe@536 1276 "unit_id", "area_id", "policy_id", "issue_id", "state",
jbe@532 1277 "initiative_id", "suggestion_id"
jbe@532 1278 ) VALUES (
jbe@554 1279 'suggestion_deleted',
jbe@532 1280 "area_row"."unit_id", "issue_row"."area_id",
jbe@536 1281 "issue_row"."policy_id",
jbe@532 1282 "initiative_row"."issue_id", "issue_row"."state",
jbe@532 1283 OLD."initiative_id", OLD."id"
jbe@532 1284 );
jbe@532 1285 END IF;
jbe@532 1286 RETURN NULL;
jbe@532 1287 END;
jbe@532 1288 $$;
jbe@532 1289
jbe@532 1290 CREATE TRIGGER "write_event_suggestion_removed"
jbe@532 1291 AFTER DELETE ON "suggestion" FOR EACH ROW EXECUTE PROCEDURE
jbe@532 1292 "write_event_suggestion_removed_trigger"();
jbe@532 1293
jbe@532 1294 COMMENT ON FUNCTION "write_event_suggestion_removed_trigger"() IS 'Implementation of trigger "write_event_suggestion_removed" on table "issue"';
jbe@532 1295 COMMENT ON TRIGGER "write_event_suggestion_removed" ON "suggestion" IS 'Create entry in "event" table on suggestion creation';
jbe@532 1296
jbe@532 1297
jbe@532 1298 CREATE FUNCTION "write_event_member_trigger"()
jbe@532 1299 RETURNS TRIGGER
jbe@532 1300 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 1301 BEGIN
jbe@532 1302 IF TG_OP = 'INSERT' THEN
jbe@552 1303 IF NEW."activated" NOTNULL AND NEW."deleted" ISNULL THEN
jbe@532 1304 INSERT INTO "event" ("event", "member_id")
jbe@532 1305 VALUES ('member_activated', NEW."id");
jbe@532 1306 END IF;
jbe@532 1307 IF NEW."active" THEN
jbe@532 1308 INSERT INTO "event" ("event", "member_id", "boolean_value")
jbe@532 1309 VALUES ('member_active', NEW."id", TRUE);
jbe@532 1310 END IF;
jbe@532 1311 ELSIF TG_OP = 'UPDATE' THEN
jbe@532 1312 IF OLD."id" != NEW."id" THEN
jbe@532 1313 RAISE EXCEPTION 'Cannot change member ID';
jbe@532 1314 END IF;
jbe@552 1315 IF
jbe@552 1316 (OLD."activated" ISNULL OR OLD."deleted" NOTNULL) AND
jbe@552 1317 NEW."activated" NOTNULL AND NEW."deleted" ISNULL
jbe@552 1318 THEN
jbe@552 1319 INSERT INTO "event" ("event", "member_id")
jbe@552 1320 VALUES ('member_activated', NEW."id");
jbe@552 1321 END IF;
jbe@552 1322 IF OLD."active" != NEW."active" THEN
jbe@552 1323 INSERT INTO "event" ("event", "member_id", "boolean_value") VALUES (
jbe@552 1324 'member_active', NEW."id", NEW."active"
jbe@552 1325 );
jbe@552 1326 END IF;
jbe@532 1327 IF OLD."name" != NEW."name" THEN
jbe@532 1328 INSERT INTO "event" (
jbe@532 1329 "event", "member_id", "text_value", "old_text_value"
jbe@532 1330 ) VALUES (
jbe@532 1331 'member_name_updated', NEW."id", NEW."name", OLD."name"
jbe@532 1332 );
jbe@532 1333 END IF;
jbe@532 1334 IF
jbe@552 1335 OLD."activated" NOTNULL AND OLD."deleted" ISNULL AND
jbe@552 1336 (NEW."activated" ISNULL OR NEW."deleted" NOTNULL)
jbe@532 1337 THEN
jbe@532 1338 INSERT INTO "event" ("event", "member_id")
jbe@554 1339 VALUES ('member_deleted', NEW."id");
jbe@532 1340 END IF;
jbe@532 1341 END IF;
jbe@532 1342 RETURN NULL;
jbe@532 1343 END;
jbe@532 1344 $$;
jbe@532 1345
jbe@532 1346 CREATE TRIGGER "write_event_member"
jbe@532 1347 AFTER INSERT OR UPDATE ON "member" FOR EACH ROW EXECUTE PROCEDURE
jbe@532 1348 "write_event_member_trigger"();
jbe@532 1349
jbe@532 1350 COMMENT ON FUNCTION "write_event_member_trigger"() IS 'Implementation of trigger "write_event_member" on table "member"';
jbe@532 1351 COMMENT ON TRIGGER "write_event_member" ON "member" IS 'Create entries in "event" table on insertion to member table';
jbe@532 1352
jbe@532 1353
jbe@532 1354 CREATE FUNCTION "write_event_member_profile_updated_trigger"()
jbe@532 1355 RETURNS TRIGGER
jbe@532 1356 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 1357 BEGIN
jbe@532 1358 IF TG_OP = 'DELETE' OR TG_OP = 'UPDATE' THEN
jbe@532 1359 IF EXISTS (SELECT NULL FROM "member" WHERE "id" = OLD."member_id") THEN
jbe@532 1360 INSERT INTO "event" ("event", "member_id") VALUES (
jbe@532 1361 'member_profile_updated', OLD."member_id"
jbe@532 1362 );
jbe@532 1363 END IF;
jbe@532 1364 END IF;
jbe@532 1365 IF TG_OP = 'UPDATE' THEN
jbe@532 1366 IF OLD."member_id" = NEW."member_id" THEN
jbe@532 1367 RETURN NULL;
jbe@532 1368 END IF;
jbe@532 1369 END IF;
jbe@532 1370 IF TG_OP = 'INSERT' OR TG_OP = 'UPDATE' THEN
jbe@532 1371 INSERT INTO "event" ("event", "member_id") VALUES (
jbe@532 1372 'member_profile_updated', NEW."member_id"
jbe@532 1373 );
jbe@532 1374 END IF;
jbe@532 1375 RETURN NULL;
jbe@532 1376 END;
jbe@532 1377 $$;
jbe@532 1378
jbe@532 1379 CREATE TRIGGER "write_event_member_profile_updated"
jbe@532 1380 AFTER INSERT OR UPDATE OR DELETE ON "member_profile"
jbe@532 1381 FOR EACH ROW EXECUTE PROCEDURE
jbe@532 1382 "write_event_member_profile_updated_trigger"();
jbe@532 1383
jbe@532 1384 COMMENT ON FUNCTION "write_event_member_profile_updated_trigger"() IS 'Implementation of trigger "write_event_member_profile_updated" on table "member_profile"';
jbe@532 1385 COMMENT ON TRIGGER "write_event_member_profile_updated" ON "member_profile" IS 'Creates entries in "event" table on member profile update';
jbe@532 1386
jbe@532 1387
jbe@532 1388 CREATE FUNCTION "write_event_member_image_updated_trigger"()
jbe@532 1389 RETURNS TRIGGER
jbe@532 1390 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 1391 BEGIN
jbe@532 1392 IF TG_OP = 'DELETE' OR TG_OP = 'UPDATE' THEN
jbe@532 1393 IF NOT OLD."scaled" THEN
jbe@532 1394 IF EXISTS (SELECT NULL FROM "member" WHERE "id" = OLD."member_id") THEN
jbe@532 1395 INSERT INTO "event" ("event", "member_id") VALUES (
jbe@532 1396 'member_image_updated', OLD."member_id"
jbe@532 1397 );
jbe@532 1398 END IF;
jbe@532 1399 END IF;
jbe@532 1400 END IF;
jbe@532 1401 IF TG_OP = 'UPDATE' THEN
jbe@532 1402 IF
jbe@532 1403 OLD."member_id" = NEW."member_id" AND
jbe@532 1404 OLD."scaled" = NEW."scaled"
jbe@532 1405 THEN
jbe@532 1406 RETURN NULL;
jbe@532 1407 END IF;
jbe@532 1408 END IF;
jbe@532 1409 IF TG_OP = 'INSERT' OR TG_OP = 'UPDATE' THEN
jbe@532 1410 IF NOT NEW."scaled" THEN
jbe@532 1411 INSERT INTO "event" ("event", "member_id") VALUES (
jbe@532 1412 'member_image_updated', NEW."member_id"
jbe@532 1413 );
jbe@532 1414 END IF;
jbe@532 1415 END IF;
jbe@532 1416 RETURN NULL;
jbe@532 1417 END;
jbe@532 1418 $$;
jbe@532 1419
jbe@532 1420 CREATE TRIGGER "write_event_member_image_updated"
jbe@532 1421 AFTER INSERT OR UPDATE OR DELETE ON "member_image"
jbe@532 1422 FOR EACH ROW EXECUTE PROCEDURE
jbe@532 1423 "write_event_member_image_updated_trigger"();
jbe@532 1424
jbe@532 1425 COMMENT ON FUNCTION "write_event_member_image_updated_trigger"() IS 'Implementation of trigger "write_event_member_image_updated" on table "member_image"';
jbe@532 1426 COMMENT ON TRIGGER "write_event_member_image_updated" ON "member_image" IS 'Creates entries in "event" table on member image update';
jbe@532 1427
jbe@532 1428
jbe@532 1429 CREATE FUNCTION "write_event_interest_trigger"()
jbe@532 1430 RETURNS TRIGGER
jbe@532 1431 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 1432 DECLARE
jbe@532 1433 "issue_row" "issue"%ROWTYPE;
jbe@532 1434 "area_row" "area"%ROWTYPE;
jbe@532 1435 BEGIN
jbe@532 1436 IF TG_OP = 'UPDATE' THEN
jbe@532 1437 IF OLD = NEW THEN
jbe@532 1438 RETURN NULL;
jbe@532 1439 END IF;
jbe@532 1440 END IF;
jbe@532 1441 IF TG_OP = 'DELETE' OR TG_OP = 'UPDATE' THEN
jbe@532 1442 SELECT * INTO "issue_row" FROM "issue"
jbe@532 1443 WHERE "id" = OLD."issue_id" FOR SHARE;
jbe@532 1444 SELECT * INTO "area_row" FROM "area"
jbe@532 1445 WHERE "id" = "issue_row"."area_id" FOR SHARE;
jbe@532 1446 IF "issue_row"."id" NOTNULL THEN
jbe@532 1447 INSERT INTO "event" (
jbe@532 1448 "event", "member_id",
jbe@536 1449 "unit_id", "area_id", "policy_id", "issue_id", "state",
jbe@532 1450 "boolean_value"
jbe@532 1451 ) VALUES (
jbe@532 1452 'interest', OLD."member_id",
jbe@532 1453 "area_row"."unit_id", "issue_row"."area_id",
jbe@536 1454 "issue_row"."policy_id",
jbe@532 1455 OLD."issue_id", "issue_row"."state",
jbe@532 1456 FALSE
jbe@532 1457 );
jbe@532 1458 END IF;
jbe@532 1459 END IF;
jbe@532 1460 IF TG_OP = 'INSERT' OR TG_OP = 'UPDATE' THEN
jbe@532 1461 SELECT * INTO "issue_row" FROM "issue"
jbe@532 1462 WHERE "id" = NEW."issue_id" FOR SHARE;
jbe@532 1463 SELECT * INTO "area_row" FROM "area"
jbe@532 1464 WHERE "id" = "issue_row"."area_id" FOR SHARE;
jbe@532 1465 INSERT INTO "event" (
jbe@532 1466 "event", "member_id",
jbe@536 1467 "unit_id", "area_id", "policy_id", "issue_id", "state",
jbe@532 1468 "boolean_value"
jbe@532 1469 ) VALUES (
jbe@532 1470 'interest', NEW."member_id",
jbe@532 1471 "area_row"."unit_id", "issue_row"."area_id",
jbe@536 1472 "issue_row"."policy_id",
jbe@532 1473 NEW."issue_id", "issue_row"."state",
jbe@532 1474 TRUE
jbe@532 1475 );
jbe@532 1476 END IF;
jbe@532 1477 RETURN NULL;
jbe@532 1478 END;
jbe@532 1479 $$;
jbe@532 1480
jbe@532 1481 CREATE TRIGGER "write_event_interest"
jbe@532 1482 AFTER INSERT OR UPDATE OR DELETE ON "interest" FOR EACH ROW EXECUTE PROCEDURE
jbe@532 1483 "write_event_interest_trigger"();
jbe@532 1484
jbe@532 1485 COMMENT ON FUNCTION "write_event_interest_trigger"() IS 'Implementation of trigger "write_event_interest_inserted" on table "interest"';
jbe@532 1486 COMMENT ON TRIGGER "write_event_interest" ON "interest" IS 'Create entry in "event" table on adding or removing interest';
jbe@532 1487
jbe@532 1488
jbe@532 1489 CREATE FUNCTION "write_event_initiator_trigger"()
jbe@532 1490 RETURNS TRIGGER
jbe@532 1491 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 1492 DECLARE
jbe@532 1493 "initiative_row" "initiative"%ROWTYPE;
jbe@532 1494 "issue_row" "issue"%ROWTYPE;
jbe@532 1495 "area_row" "area"%ROWTYPE;
jbe@549 1496 "accepted_v" BOOLEAN = FALSE;
jbe@549 1497 "rejected_v" BOOLEAN = FALSE;
jbe@532 1498 BEGIN
jbe@532 1499 IF TG_OP = 'UPDATE' THEN
jbe@532 1500 IF
jbe@532 1501 OLD."initiative_id" = NEW."initiative_id" AND
jbe@549 1502 OLD."member_id" = NEW."member_id"
jbe@532 1503 THEN
jbe@549 1504 IF
jbe@549 1505 coalesce(OLD."accepted", FALSE) = coalesce(NEW."accepted", FALSE)
jbe@549 1506 THEN
jbe@549 1507 RETURN NULL;
jbe@549 1508 END IF;
jbe@549 1509 IF coalesce(NEW."accepted", FALSE) = TRUE THEN
jbe@549 1510 "accepted_v" := TRUE;
jbe@549 1511 ELSE
jbe@549 1512 "rejected_v" := TRUE;
jbe@549 1513 END IF;
jbe@532 1514 END IF;
jbe@532 1515 END IF;
jbe@532 1516 IF (TG_OP = 'DELETE' OR TG_OP = 'UPDATE') AND NOT "accepted_v" THEN
jbe@532 1517 IF coalesce(OLD."accepted", FALSE) = TRUE THEN
jbe@532 1518 SELECT * INTO "initiative_row" FROM "initiative"
jbe@532 1519 WHERE "id" = OLD."initiative_id" FOR SHARE;
jbe@532 1520 IF "initiative_row"."id" NOTNULL THEN
jbe@532 1521 SELECT * INTO "issue_row" FROM "issue"
jbe@532 1522 WHERE "id" = "initiative_row"."issue_id" FOR SHARE;
jbe@532 1523 SELECT * INTO "area_row" FROM "area"
jbe@532 1524 WHERE "id" = "issue_row"."area_id" FOR SHARE;
jbe@532 1525 INSERT INTO "event" (
jbe@532 1526 "event", "member_id",
jbe@536 1527 "unit_id", "area_id", "policy_id", "issue_id", "state",
jbe@532 1528 "initiative_id", "boolean_value"
jbe@532 1529 ) VALUES (
jbe@532 1530 'initiator', OLD."member_id",
jbe@532 1531 "area_row"."unit_id", "issue_row"."area_id",
jbe@536 1532 "issue_row"."policy_id",
jbe@532 1533 "issue_row"."id", "issue_row"."state",
jbe@532 1534 OLD."initiative_id", FALSE
jbe@532 1535 );
jbe@532 1536 END IF;
jbe@532 1537 END IF;
jbe@532 1538 END IF;
jbe@532 1539 IF TG_OP = 'UPDATE' AND NOT "rejected_v" THEN
jbe@532 1540 IF coalesce(NEW."accepted", FALSE) = TRUE THEN
jbe@532 1541 SELECT * INTO "initiative_row" FROM "initiative"
jbe@532 1542 WHERE "id" = NEW."initiative_id" FOR SHARE;
jbe@532 1543 SELECT * INTO "issue_row" FROM "issue"
jbe@532 1544 WHERE "id" = "initiative_row"."issue_id" FOR SHARE;
jbe@532 1545 SELECT * INTO "area_row" FROM "area"
jbe@532 1546 WHERE "id" = "issue_row"."area_id" FOR SHARE;
jbe@532 1547 INSERT INTO "event" (
jbe@532 1548 "event", "member_id",
jbe@536 1549 "unit_id", "area_id", "policy_id", "issue_id", "state",
jbe@532 1550 "initiative_id", "boolean_value"
jbe@532 1551 ) VALUES (
jbe@532 1552 'initiator', NEW."member_id",
jbe@532 1553 "area_row"."unit_id", "issue_row"."area_id",
jbe@536 1554 "issue_row"."policy_id",
jbe@532 1555 "issue_row"."id", "issue_row"."state",
jbe@532 1556 NEW."initiative_id", TRUE
jbe@532 1557 );
jbe@532 1558 END IF;
jbe@532 1559 END IF;
jbe@532 1560 RETURN NULL;
jbe@532 1561 END;
jbe@532 1562 $$;
jbe@532 1563
jbe@532 1564 CREATE TRIGGER "write_event_initiator"
jbe@532 1565 AFTER UPDATE OR DELETE ON "initiator" FOR EACH ROW EXECUTE PROCEDURE
jbe@532 1566 "write_event_initiator_trigger"();
jbe@532 1567
jbe@532 1568 COMMENT ON FUNCTION "write_event_initiator_trigger"() IS 'Implementation of trigger "write_event_initiator" on table "initiator"';
jbe@532 1569 COMMENT ON TRIGGER "write_event_initiator" ON "initiator" IS 'Create entry in "event" table when accepting or removing initiatorship (NOTE: trigger does not fire on INSERT to avoid events on initiative creation)';
jbe@532 1570
jbe@532 1571
jbe@532 1572 CREATE FUNCTION "write_event_support_trigger"()
jbe@532 1573 RETURNS TRIGGER
jbe@532 1574 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 1575 DECLARE
jbe@532 1576 "issue_row" "issue"%ROWTYPE;
jbe@532 1577 "area_row" "area"%ROWTYPE;
jbe@532 1578 BEGIN
jbe@532 1579 IF TG_OP = 'UPDATE' THEN
jbe@532 1580 IF
jbe@532 1581 OLD."initiative_id" = NEW."initiative_id" AND
jbe@532 1582 OLD."member_id" = NEW."member_id"
jbe@532 1583 THEN
jbe@532 1584 IF OLD."draft_id" != NEW."draft_id" THEN
jbe@532 1585 SELECT * INTO "issue_row" FROM "issue"
jbe@532 1586 WHERE "id" = NEW."issue_id" FOR SHARE;
jbe@532 1587 SELECT * INTO "area_row" FROM "area"
jbe@532 1588 WHERE "id" = "issue_row"."area_id" FOR SHARE;
jbe@532 1589 INSERT INTO "event" (
jbe@532 1590 "event", "member_id",
jbe@536 1591 "unit_id", "area_id", "policy_id", "issue_id", "state",
jbe@532 1592 "initiative_id", "draft_id"
jbe@532 1593 ) VALUES (
jbe@532 1594 'support_updated', NEW."member_id",
jbe@532 1595 "area_row"."unit_id", "issue_row"."area_id",
jbe@536 1596 "issue_row"."policy_id",
jbe@532 1597 "issue_row"."id", "issue_row"."state",
jbe@532 1598 NEW."initiative_id", NEW."draft_id"
jbe@532 1599 );
jbe@532 1600 END IF;
jbe@532 1601 RETURN NULL;
jbe@532 1602 END IF;
jbe@532 1603 END IF;
jbe@532 1604 IF TG_OP = 'DELETE' OR TG_OP = 'UPDATE' THEN
jbe@532 1605 IF EXISTS (
jbe@532 1606 SELECT NULL FROM "initiative" WHERE "id" = OLD."initiative_id"
jbe@532 1607 FOR SHARE
jbe@532 1608 ) THEN
jbe@532 1609 SELECT * INTO "issue_row" FROM "issue"
jbe@532 1610 WHERE "id" = OLD."issue_id" FOR SHARE;
jbe@532 1611 SELECT * INTO "area_row" FROM "area"
jbe@532 1612 WHERE "id" = "issue_row"."area_id" FOR SHARE;
jbe@532 1613 INSERT INTO "event" (
jbe@532 1614 "event", "member_id",
jbe@536 1615 "unit_id", "area_id", "policy_id", "issue_id", "state",
jbe@535 1616 "initiative_id", "boolean_value"
jbe@532 1617 ) VALUES (
jbe@532 1618 'support', OLD."member_id",
jbe@532 1619 "area_row"."unit_id", "issue_row"."area_id",
jbe@536 1620 "issue_row"."policy_id",
jbe@532 1621 "issue_row"."id", "issue_row"."state",
jbe@535 1622 OLD."initiative_id", FALSE
jbe@532 1623 );
jbe@532 1624 END IF;
jbe@532 1625 END IF;
jbe@532 1626 IF TG_OP = 'INSERT' OR TG_OP = 'UPDATE' THEN
jbe@532 1627 SELECT * INTO "issue_row" FROM "issue"
jbe@532 1628 WHERE "id" = NEW."issue_id" FOR SHARE;
jbe@532 1629 SELECT * INTO "area_row" FROM "area"
jbe@532 1630 WHERE "id" = "issue_row"."area_id" FOR SHARE;
jbe@532 1631 INSERT INTO "event" (
jbe@532 1632 "event", "member_id",
jbe@536 1633 "unit_id", "area_id", "policy_id", "issue_id", "state",
jbe@532 1634 "initiative_id", "draft_id", "boolean_value"
jbe@532 1635 ) VALUES (
jbe@532 1636 'support', NEW."member_id",
jbe@532 1637 "area_row"."unit_id", "issue_row"."area_id",
jbe@536 1638 "issue_row"."policy_id",
jbe@532 1639 "issue_row"."id", "issue_row"."state",
jbe@532 1640 NEW."initiative_id", NEW."draft_id", TRUE
jbe@532 1641 );
jbe@532 1642 END IF;
jbe@532 1643 RETURN NULL;
jbe@532 1644 END;
jbe@532 1645 $$;
jbe@532 1646
jbe@532 1647 CREATE TRIGGER "write_event_support"
jbe@532 1648 AFTER INSERT OR UPDATE OR DELETE ON "supporter" FOR EACH ROW EXECUTE PROCEDURE
jbe@532 1649 "write_event_support_trigger"();
jbe@532 1650
jbe@532 1651 COMMENT ON FUNCTION "write_event_support_trigger"() IS 'Implementation of trigger "write_event_support" on table "supporter"';
jbe@532 1652 COMMENT ON TRIGGER "write_event_support" ON "supporter" IS 'Create entry in "event" table when adding, updating, or removing support';
jbe@532 1653
jbe@532 1654
jbe@532 1655 CREATE FUNCTION "write_event_suggestion_rated_trigger"()
jbe@532 1656 RETURNS TRIGGER
jbe@532 1657 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 1658 DECLARE
jbe@532 1659 "same_pkey_v" BOOLEAN = FALSE;
jbe@532 1660 "initiative_row" "initiative"%ROWTYPE;
jbe@532 1661 "issue_row" "issue"%ROWTYPE;
jbe@532 1662 "area_row" "area"%ROWTYPE;
jbe@532 1663 BEGIN
jbe@532 1664 IF TG_OP = 'UPDATE' THEN
jbe@532 1665 IF
jbe@532 1666 OLD."suggestion_id" = NEW."suggestion_id" AND
jbe@532 1667 OLD."member_id" = NEW."member_id"
jbe@532 1668 THEN
jbe@532 1669 IF
jbe@532 1670 OLD."degree" = NEW."degree" AND
jbe@532 1671 OLD."fulfilled" = NEW."fulfilled"
jbe@532 1672 THEN
jbe@532 1673 RETURN NULL;
jbe@532 1674 END IF;
jbe@532 1675 "same_pkey_v" := TRUE;
jbe@532 1676 END IF;
jbe@532 1677 END IF;
jbe@532 1678 IF (TG_OP = 'DELETE' OR TG_OP = 'UPDATE') AND NOT "same_pkey_v" THEN
jbe@532 1679 IF EXISTS (
jbe@532 1680 SELECT NULL FROM "suggestion" WHERE "id" = OLD."suggestion_id"
jbe@532 1681 FOR SHARE
jbe@532 1682 ) THEN
jbe@532 1683 SELECT * INTO "initiative_row" FROM "initiative"
jbe@532 1684 WHERE "id" = OLD."initiative_id" FOR SHARE;
jbe@532 1685 SELECT * INTO "issue_row" FROM "issue"
jbe@532 1686 WHERE "id" = "initiative_row"."issue_id" FOR SHARE;
jbe@532 1687 SELECT * INTO "area_row" FROM "area"
jbe@532 1688 WHERE "id" = "issue_row"."area_id" FOR SHARE;
jbe@532 1689 INSERT INTO "event" (
jbe@532 1690 "event", "member_id",
jbe@536 1691 "unit_id", "area_id", "policy_id", "issue_id", "state",
jbe@532 1692 "initiative_id", "suggestion_id",
jbe@532 1693 "boolean_value", "numeric_value"
jbe@532 1694 ) VALUES (
jbe@532 1695 'suggestion_rated', OLD."member_id",
jbe@532 1696 "area_row"."unit_id", "issue_row"."area_id",
jbe@536 1697 "issue_row"."policy_id",
jbe@532 1698 "initiative_row"."issue_id", "issue_row"."state",
jbe@532 1699 OLD."initiative_id", OLD."suggestion_id",
jbe@532 1700 NULL, 0
jbe@532 1701 );
jbe@532 1702 END IF;
jbe@532 1703 END IF;
jbe@532 1704 IF TG_OP = 'INSERT' OR TG_OP = 'UPDATE' THEN
jbe@532 1705 SELECT * INTO "initiative_row" FROM "initiative"
jbe@532 1706 WHERE "id" = NEW."initiative_id" FOR SHARE;
jbe@532 1707 SELECT * INTO "issue_row" FROM "issue"
jbe@532 1708 WHERE "id" = "initiative_row"."issue_id" FOR SHARE;
jbe@532 1709 SELECT * INTO "area_row" FROM "area"
jbe@532 1710 WHERE "id" = "issue_row"."area_id" FOR SHARE;
jbe@532 1711 INSERT INTO "event" (
jbe@532 1712 "event", "member_id",
jbe@536 1713 "unit_id", "area_id", "policy_id", "issue_id", "state",
jbe@532 1714 "initiative_id", "suggestion_id",
jbe@532 1715 "boolean_value", "numeric_value"
jbe@532 1716 ) VALUES (
jbe@532 1717 'suggestion_rated', NEW."member_id",
jbe@532 1718 "area_row"."unit_id", "issue_row"."area_id",
jbe@536 1719 "issue_row"."policy_id",
jbe@532 1720 "initiative_row"."issue_id", "issue_row"."state",
jbe@532 1721 NEW."initiative_id", NEW."suggestion_id",
jbe@532 1722 NEW."fulfilled", NEW."degree"
jbe@532 1723 );
jbe@532 1724 END IF;
jbe@532 1725 RETURN NULL;
jbe@532 1726 END;
jbe@532 1727 $$;
jbe@532 1728
jbe@532 1729 CREATE TRIGGER "write_event_suggestion_rated"
jbe@532 1730 AFTER INSERT OR UPDATE OR DELETE ON "opinion" FOR EACH ROW EXECUTE PROCEDURE
jbe@532 1731 "write_event_suggestion_rated_trigger"();
jbe@532 1732
jbe@532 1733 COMMENT ON FUNCTION "write_event_suggestion_rated_trigger"() IS 'Implementation of trigger "write_event_suggestion_rated" on table "opinion"';
jbe@532 1734 COMMENT ON TRIGGER "write_event_suggestion_rated" ON "opinion" IS 'Create entry in "event" table when adding, updating, or removing support';
jbe@532 1735
jbe@532 1736
jbe@532 1737 CREATE FUNCTION "write_event_delegation_trigger"()
jbe@532 1738 RETURNS TRIGGER
jbe@532 1739 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 1740 DECLARE
jbe@532 1741 "issue_row" "issue"%ROWTYPE;
jbe@532 1742 "area_row" "area"%ROWTYPE;
jbe@532 1743 BEGIN
jbe@532 1744 IF TG_OP = 'DELETE' THEN
jbe@532 1745 IF EXISTS (
jbe@532 1746 SELECT NULL FROM "member" WHERE "id" = OLD."truster_id"
jbe@532 1747 ) AND (CASE OLD."scope"
jbe@532 1748 WHEN 'unit'::"delegation_scope" THEN EXISTS (
jbe@532 1749 SELECT NULL FROM "unit" WHERE "id" = OLD."unit_id"
jbe@532 1750 )
jbe@532 1751 WHEN 'area'::"delegation_scope" THEN EXISTS (
jbe@532 1752 SELECT NULL FROM "area" WHERE "id" = OLD."area_id"
jbe@532 1753 )
jbe@532 1754 WHEN 'issue'::"delegation_scope" THEN EXISTS (
jbe@532 1755 SELECT NULL FROM "issue" WHERE "id" = OLD."issue_id"
jbe@532 1756 )
jbe@532 1757 END) THEN
jbe@532 1758 SELECT * INTO "issue_row" FROM "issue"
jbe@532 1759 WHERE "id" = OLD."issue_id" FOR SHARE;
jbe@532 1760 SELECT * INTO "area_row" FROM "area"
jbe@532 1761 WHERE "id" = COALESCE(OLD."area_id", "issue_row"."area_id")
jbe@532 1762 FOR SHARE;
jbe@532 1763 INSERT INTO "event" (
jbe@532 1764 "event", "member_id", "scope",
jbe@532 1765 "unit_id", "area_id", "issue_id", "state",
jbe@532 1766 "boolean_value"
jbe@532 1767 ) VALUES (
jbe@532 1768 'delegation', OLD."truster_id", OLD."scope",
jbe@532 1769 COALESCE(OLD."unit_id", "area_row"."unit_id"), "area_row"."id",
jbe@532 1770 OLD."issue_id", "issue_row"."state",
jbe@532 1771 FALSE
jbe@532 1772 );
jbe@532 1773 END IF;
jbe@532 1774 ELSE
jbe@532 1775 SELECT * INTO "issue_row" FROM "issue"
jbe@532 1776 WHERE "id" = NEW."issue_id" FOR SHARE;
jbe@532 1777 SELECT * INTO "area_row" FROM "area"
jbe@532 1778 WHERE "id" = COALESCE(NEW."area_id", "issue_row"."area_id")
jbe@532 1779 FOR SHARE;
jbe@532 1780 INSERT INTO "event" (
jbe@532 1781 "event", "member_id", "other_member_id", "scope",
jbe@532 1782 "unit_id", "area_id", "issue_id", "state",
jbe@532 1783 "boolean_value"
jbe@532 1784 ) VALUES (
jbe@532 1785 'delegation', NEW."truster_id", NEW."trustee_id", NEW."scope",
jbe@532 1786 COALESCE(NEW."unit_id", "area_row"."unit_id"), "area_row"."id",
jbe@532 1787 NEW."issue_id", "issue_row"."state",
jbe@532 1788 TRUE
jbe@532 1789 );
jbe@532 1790 END IF;
jbe@532 1791 RETURN NULL;
jbe@532 1792 END;
jbe@532 1793 $$;
jbe@532 1794
jbe@532 1795 CREATE TRIGGER "write_event_delegation"
jbe@532 1796 AFTER INSERT OR UPDATE OR DELETE ON "delegation" FOR EACH ROW EXECUTE PROCEDURE
jbe@532 1797 "write_event_delegation_trigger"();
jbe@532 1798
jbe@532 1799 COMMENT ON FUNCTION "write_event_delegation_trigger"() IS 'Implementation of trigger "write_event_delegation" on table "delegation"';
jbe@532 1800 COMMENT ON TRIGGER "write_event_delegation" ON "delegation" IS 'Create entry in "event" table when adding, updating, or removing a delegation';
jbe@532 1801
jbe@532 1802
jbe@532 1803 CREATE FUNCTION "write_event_contact_trigger"()
jbe@532 1804 RETURNS TRIGGER
jbe@532 1805 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 1806 BEGIN
jbe@532 1807 IF TG_OP = 'UPDATE' THEN
jbe@532 1808 IF
jbe@532 1809 OLD."member_id" = NEW."member_id" AND
jbe@532 1810 OLD."other_member_id" = NEW."other_member_id" AND
jbe@532 1811 OLD."public" = NEW."public"
jbe@532 1812 THEN
jbe@532 1813 RETURN NULL;
jbe@532 1814 END IF;
jbe@532 1815 END IF;
jbe@532 1816 IF TG_OP = 'DELETE' OR TG_OP = 'UPDATE' THEN
jbe@532 1817 IF OLD."public" THEN
jbe@532 1818 IF EXISTS (
jbe@532 1819 SELECT NULL FROM "member" WHERE "id" = OLD."member_id"
jbe@532 1820 FOR SHARE
jbe@532 1821 ) AND EXISTS (
jbe@532 1822 SELECT NULL FROM "member" WHERE "id" = OLD."other_member_id"
jbe@532 1823 FOR SHARE
jbe@532 1824 ) THEN
jbe@532 1825 INSERT INTO "event" (
jbe@532 1826 "event", "member_id", "other_member_id", "boolean_value"
jbe@532 1827 ) VALUES (
jbe@532 1828 'contact', OLD."member_id", OLD."other_member_id", FALSE
jbe@532 1829 );
jbe@532 1830 END IF;
jbe@532 1831 END IF;
jbe@532 1832 END IF;
jbe@532 1833 IF TG_OP = 'INSERT' OR TG_OP = 'UPDATE' THEN
jbe@532 1834 IF NEW."public" THEN
jbe@532 1835 INSERT INTO "event" (
jbe@532 1836 "event", "member_id", "other_member_id", "boolean_value"
jbe@532 1837 ) VALUES (
jbe@532 1838 'contact', NEW."member_id", NEW."other_member_id", TRUE
jbe@532 1839 );
jbe@532 1840 END IF;
jbe@532 1841 END IF;
jbe@532 1842 RETURN NULL;
jbe@532 1843 END;
jbe@532 1844 $$;
jbe@532 1845
jbe@532 1846 CREATE TRIGGER "write_event_contact"
jbe@532 1847 AFTER INSERT OR UPDATE OR DELETE ON "contact" FOR EACH ROW EXECUTE PROCEDURE
jbe@532 1848 "write_event_contact_trigger"();
jbe@532 1849
jbe@532 1850 COMMENT ON FUNCTION "write_event_contact_trigger"() IS 'Implementation of trigger "write_event_contact" on table "contact"';
jbe@532 1851 COMMENT ON TRIGGER "write_event_contact" ON "contact" IS 'Create entry in "event" table when adding or removing public contacts';
jbe@532 1852
jbe@532 1853
jbe@532 1854 CREATE FUNCTION "send_event_notify_trigger"()
jbe@532 1855 RETURNS TRIGGER
jbe@532 1856 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 1857 BEGIN
jbe@532 1858 EXECUTE 'NOTIFY "event", ''' || NEW."event" || '''';
jbe@532 1859 RETURN NULL;
jbe@532 1860 END;
jbe@532 1861 $$;
jbe@532 1862
jbe@532 1863 CREATE TRIGGER "send_notify"
jbe@532 1864 AFTER INSERT OR UPDATE ON "event" FOR EACH ROW EXECUTE PROCEDURE
jbe@532 1865 "send_event_notify_trigger"();
jbe@532 1866
jbe@532 1867
jbe@532 1868 CREATE FUNCTION "delete_extended_scope_tokens_trigger"()
jbe@532 1869 RETURNS TRIGGER
jbe@532 1870 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 1871 DECLARE
jbe@532 1872 "system_application_row" "system_application"%ROWTYPE;
jbe@532 1873 BEGIN
jbe@532 1874 IF OLD."system_application_id" NOTNULL THEN
jbe@532 1875 SELECT * FROM "system_application" INTO "system_application_row"
jbe@532 1876 WHERE "id" = OLD."system_application_id";
jbe@532 1877 DELETE FROM "token"
jbe@532 1878 WHERE "member_id" = OLD."member_id"
jbe@532 1879 AND "system_application_id" = OLD."system_application_id"
jbe@532 1880 AND NOT COALESCE(
jbe@532 1881 regexp_split_to_array("scope", E'\\s+') <@
jbe@532 1882 regexp_split_to_array(
jbe@532 1883 "system_application_row"."automatic_scope", E'\\s+'
jbe@532 1884 ),
jbe@532 1885 FALSE
jbe@532 1886 );
jbe@532 1887 END IF;
jbe@532 1888 RETURN OLD;
jbe@532 1889 END;
jbe@532 1890 $$;
jbe@532 1891
jbe@532 1892 CREATE TRIGGER "delete_extended_scope_tokens"
jbe@532 1893 BEFORE DELETE ON "member_application" FOR EACH ROW EXECUTE PROCEDURE
jbe@532 1894 "delete_extended_scope_tokens_trigger"();
jbe@532 1895
jbe@532 1896
jbe@532 1897 CREATE FUNCTION "detach_token_from_session_trigger"()
jbe@532 1898 RETURNS TRIGGER
jbe@532 1899 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 1900 BEGIN
jbe@532 1901 UPDATE "token" SET "session_id" = NULL
jbe@532 1902 WHERE "session_id" = OLD."id";
jbe@532 1903 RETURN OLD;
jbe@532 1904 END;
jbe@532 1905 $$;
jbe@532 1906
jbe@532 1907 CREATE TRIGGER "detach_token_from_session"
jbe@532 1908 BEFORE DELETE ON "session" FOR EACH ROW EXECUTE PROCEDURE
jbe@532 1909 "detach_token_from_session_trigger"();
jbe@532 1910
jbe@532 1911
jbe@532 1912 CREATE FUNCTION "delete_non_detached_scope_with_session_trigger"()
jbe@532 1913 RETURNS TRIGGER
jbe@532 1914 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 1915 BEGIN
jbe@532 1916 IF NEW."session_id" ISNULL THEN
jbe@532 1917 SELECT coalesce(string_agg("element", ' '), '') INTO NEW."scope"
jbe@532 1918 FROM unnest(regexp_split_to_array(NEW."scope", E'\\s+')) AS "element"
jbe@532 1919 WHERE "element" LIKE '%_detached';
jbe@532 1920 END IF;
jbe@532 1921 RETURN NEW;
jbe@532 1922 END;
jbe@532 1923 $$;
jbe@532 1924
jbe@532 1925 CREATE TRIGGER "delete_non_detached_scope_with_session"
jbe@532 1926 BEFORE INSERT OR UPDATE ON "token" FOR EACH ROW EXECUTE PROCEDURE
jbe@532 1927 "delete_non_detached_scope_with_session_trigger"();
jbe@532 1928
jbe@532 1929
jbe@532 1930 CREATE FUNCTION "delete_token_with_empty_scope_trigger"()
jbe@532 1931 RETURNS TRIGGER
jbe@532 1932 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 1933 BEGIN
jbe@532 1934 IF NEW."scope" = '' THEN
jbe@532 1935 DELETE FROM "token" WHERE "id" = NEW."id";
jbe@532 1936 END IF;
jbe@532 1937 RETURN NULL;
jbe@532 1938 END;
jbe@532 1939 $$;
jbe@532 1940
jbe@532 1941 CREATE TRIGGER "delete_token_with_empty_scope"
jbe@532 1942 AFTER INSERT OR UPDATE ON "token" FOR EACH ROW EXECUTE PROCEDURE
jbe@532 1943 "delete_token_with_empty_scope_trigger"();
jbe@532 1944
jbe@532 1945
jbe@532 1946 CREATE FUNCTION "delete_snapshot_on_partial_delete_trigger"()
jbe@532 1947 RETURNS TRIGGER
jbe@532 1948 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 1949 BEGIN
jbe@532 1950 IF TG_OP = 'UPDATE' THEN
jbe@532 1951 IF
jbe@532 1952 OLD."snapshot_id" = NEW."snapshot_id" AND
jbe@532 1953 OLD."issue_id" = NEW."issue_id"
jbe@532 1954 THEN
jbe@532 1955 RETURN NULL;
jbe@532 1956 END IF;
jbe@532 1957 END IF;
jbe@532 1958 DELETE FROM "snapshot" WHERE "id" = OLD."snapshot_id";
jbe@532 1959 RETURN NULL;
jbe@532 1960 END;
jbe@532 1961 $$;
jbe@532 1962
jbe@532 1963 CREATE TRIGGER "delete_snapshot_on_partial_delete"
jbe@532 1964 AFTER UPDATE OR DELETE ON "snapshot_issue"
jbe@532 1965 FOR EACH ROW EXECUTE PROCEDURE
jbe@532 1966 "delete_snapshot_on_partial_delete_trigger"();
jbe@532 1967
jbe@532 1968 COMMENT ON FUNCTION "delete_snapshot_on_partial_delete_trigger"() IS 'Implementation of trigger "delete_snapshot_on_partial_delete" on table "snapshot_issue"';
jbe@532 1969 COMMENT ON TRIGGER "delete_snapshot_on_partial_delete" ON "snapshot_issue" IS 'Deletes whole snapshot if one issue is deleted from the snapshot';
jbe@532 1970
jbe@532 1971
jbe@532 1972 CREATE FUNCTION "copy_current_draft_data"
jbe@532 1973 ("initiative_id_p" "initiative"."id"%TYPE )
jbe@532 1974 RETURNS VOID
jbe@532 1975 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 1976 BEGIN
jbe@532 1977 PERFORM NULL FROM "initiative" WHERE "id" = "initiative_id_p"
jbe@532 1978 FOR UPDATE;
jbe@532 1979 UPDATE "initiative" SET
jbe@532 1980 "location" = "draft"."location",
jbe@532 1981 "draft_text_search_data" = "draft"."text_search_data"
jbe@532 1982 FROM "current_draft" AS "draft"
jbe@532 1983 WHERE "initiative"."id" = "initiative_id_p"
jbe@532 1984 AND "draft"."initiative_id" = "initiative_id_p";
jbe@532 1985 END;
jbe@532 1986 $$;
jbe@532 1987
jbe@532 1988 COMMENT ON FUNCTION "copy_current_draft_data"
jbe@532 1989 ( "initiative"."id"%TYPE )
jbe@532 1990 IS 'Helper function for function "copy_current_draft_data_trigger"';
jbe@532 1991
jbe@532 1992
jbe@532 1993 CREATE FUNCTION "copy_current_draft_data_trigger"()
jbe@532 1994 RETURNS TRIGGER
jbe@532 1995 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 1996 BEGIN
jbe@532 1997 IF TG_OP='DELETE' THEN
jbe@532 1998 PERFORM "copy_current_draft_data"(OLD."initiative_id");
jbe@532 1999 ELSE
jbe@532 2000 IF TG_OP='UPDATE' THEN
jbe@532 2001 IF COALESCE(OLD."inititiave_id" != NEW."initiative_id", TRUE) THEN
jbe@532 2002 PERFORM "copy_current_draft_data"(OLD."initiative_id");
jbe@532 2003 END IF;
jbe@532 2004 END IF;
jbe@532 2005 PERFORM "copy_current_draft_data"(NEW."initiative_id");
jbe@532 2006 END IF;
jbe@532 2007 RETURN NULL;
jbe@532 2008 END;
jbe@532 2009 $$;
jbe@532 2010
jbe@532 2011 CREATE TRIGGER "copy_current_draft_data"
jbe@532 2012 AFTER INSERT OR UPDATE OR DELETE ON "draft"
jbe@532 2013 FOR EACH ROW EXECUTE PROCEDURE
jbe@532 2014 "copy_current_draft_data_trigger"();
jbe@532 2015
jbe@532 2016 COMMENT ON FUNCTION "copy_current_draft_data_trigger"() IS 'Implementation of trigger "copy_current_draft_data" on table "draft"';
jbe@532 2017 COMMENT ON TRIGGER "copy_current_draft_data" ON "draft" IS 'Copy certain fields from most recent "draft" to "initiative"';
jbe@532 2018
jbe@532 2019
jbe@532 2020 CREATE VIEW "area_quorum" AS
jbe@532 2021 SELECT
jbe@532 2022 "area"."id" AS "area_id",
jbe@532 2023 ceil(
jbe@532 2024 "area"."quorum_standard"::FLOAT8 * "quorum_factor"::FLOAT8 ^ (
jbe@532 2025 coalesce(
jbe@532 2026 ( SELECT sum(
jbe@532 2027 ( extract(epoch from "area"."quorum_time")::FLOAT8 /
jbe@532 2028 extract(epoch from
jbe@532 2029 ("issue"."accepted"-"issue"."created") +
jbe@532 2030 "issue"."discussion_time" +
jbe@532 2031 "issue"."verification_time" +
jbe@532 2032 "issue"."voting_time"
jbe@532 2033 )::FLOAT8
jbe@532 2034 ) ^ "area"."quorum_exponent"::FLOAT8
jbe@532 2035 )
jbe@532 2036 FROM "issue" JOIN "policy"
jbe@532 2037 ON "issue"."policy_id" = "policy"."id"
jbe@532 2038 WHERE "issue"."area_id" = "area"."id"
jbe@532 2039 AND "issue"."accepted" NOTNULL
jbe@532 2040 AND "issue"."closed" ISNULL
jbe@532 2041 AND "policy"."polling" = FALSE
jbe@532 2042 )::FLOAT8, 0::FLOAT8
jbe@532 2043 ) / "area"."quorum_issues"::FLOAT8 - 1::FLOAT8
jbe@532 2044 ) * CASE WHEN "area"."quorum_den" ISNULL THEN 1 ELSE (
jbe@532 2045 SELECT "snapshot"."population"
jbe@532 2046 FROM "snapshot"
jbe@532 2047 WHERE "snapshot"."area_id" = "area"."id"
jbe@532 2048 AND "snapshot"."issue_id" ISNULL
jbe@532 2049 ORDER BY "snapshot"."id" DESC
jbe@532 2050 LIMIT 1
jbe@532 2051 ) END / coalesce("area"."quorum_den", 1)
jbe@532 2052
jbe@532 2053 )::INT4 AS "issue_quorum"
jbe@532 2054 FROM "area";
jbe@532 2055
jbe@532 2056 COMMENT ON VIEW "area_quorum" IS 'Area-based quorum considering number of open (accepted) issues';
jbe@532 2057
jbe@532 2058
jbe@532 2059 CREATE VIEW "area_with_unaccepted_issues" AS
jbe@532 2060 SELECT DISTINCT ON ("area"."id") "area".*
jbe@532 2061 FROM "area" JOIN "issue" ON "area"."id" = "issue"."area_id"
jbe@532 2062 WHERE "issue"."state" = 'admission';
jbe@532 2063
jbe@532 2064 COMMENT ON VIEW "area_with_unaccepted_issues" IS 'All areas with unaccepted open issues (needed for issue admission system)';
jbe@532 2065
jbe@532 2066
jbe@532 2067 DROP VIEW "area_member_count";
jbe@532 2068
jbe@532 2069
jbe@532 2070 DROP TABLE "membership";
jbe@532 2071
jbe@532 2072
jbe@532 2073 DROP FUNCTION "membership_weight"
jbe@532 2074 ( "area_id_p" "area"."id"%TYPE,
jbe@532 2075 "member_id_p" "member"."id"%TYPE );
jbe@532 2076
jbe@532 2077
jbe@532 2078 DROP FUNCTION "membership_weight_with_skipping"
jbe@532 2079 ( "area_id_p" "area"."id"%TYPE,
jbe@532 2080 "member_id_p" "member"."id"%TYPE,
jbe@532 2081 "skip_member_ids_p" INT4[] ); -- TODO: ordering/cascade
jbe@532 2082
jbe@532 2083
jbe@532 2084 CREATE OR REPLACE VIEW "issue_delegation" AS
jbe@532 2085 SELECT DISTINCT ON ("issue"."id", "delegation"."truster_id")
jbe@532 2086 "issue"."id" AS "issue_id",
jbe@532 2087 "delegation"."id",
jbe@532 2088 "delegation"."truster_id",
jbe@532 2089 "delegation"."trustee_id",
jbe@532 2090 "delegation"."scope"
jbe@532 2091 FROM "issue"
jbe@532 2092 JOIN "area"
jbe@532 2093 ON "area"."id" = "issue"."area_id"
jbe@532 2094 JOIN "delegation"
jbe@532 2095 ON "delegation"."unit_id" = "area"."unit_id"
jbe@532 2096 OR "delegation"."area_id" = "area"."id"
jbe@532 2097 OR "delegation"."issue_id" = "issue"."id"
jbe@532 2098 JOIN "member"
jbe@532 2099 ON "delegation"."truster_id" = "member"."id"
jbe@556 2100 JOIN "privilege"
jbe@556 2101 ON "area"."unit_id" = "privilege"."unit_id"
jbe@556 2102 AND "delegation"."truster_id" = "privilege"."member_id"
jbe@556 2103 WHERE "member"."active" AND "privilege"."voting_right"
jbe@532 2104 ORDER BY
jbe@532 2105 "issue"."id",
jbe@532 2106 "delegation"."truster_id",
jbe@532 2107 "delegation"."scope" DESC;
jbe@532 2108
jbe@532 2109
jbe@532 2110 CREATE VIEW "unit_member" AS
jbe@532 2111 SELECT
jbe@532 2112 "unit"."id" AS "unit_id",
jbe@532 2113 "member"."id" AS "member_id"
jbe@556 2114 FROM "privilege"
jbe@556 2115 JOIN "unit" ON "unit_id" = "privilege"."unit_id"
jbe@556 2116 JOIN "member" ON "member"."id" = "privilege"."member_id"
jbe@556 2117 WHERE "privilege"."voting_right" AND "member"."active";
jbe@532 2118
jbe@532 2119 COMMENT ON VIEW "unit_member" IS 'Active members with voting right in a unit';
jbe@532 2120
jbe@532 2121
jbe@532 2122 CREATE OR REPLACE VIEW "unit_member_count" AS
jbe@532 2123 SELECT
jbe@532 2124 "unit"."id" AS "unit_id",
jbe@532 2125 count("unit_member"."member_id") AS "member_count"
jbe@532 2126 FROM "unit" LEFT JOIN "unit_member"
jbe@532 2127 ON "unit"."id" = "unit_member"."unit_id"
jbe@532 2128 GROUP BY "unit"."id";
jbe@532 2129
jbe@532 2130 COMMENT ON VIEW "unit_member_count" IS 'View used to update "member_count" column of "unit" table';
jbe@532 2131
jbe@532 2132
jbe@532 2133 CREATE OR REPLACE VIEW "opening_draft" AS
jbe@532 2134 SELECT DISTINCT ON ("initiative_id") * FROM "draft"
jbe@532 2135 ORDER BY "initiative_id", "id";
jbe@532 2136
jbe@532 2137
jbe@532 2138 CREATE OR REPLACE VIEW "current_draft" AS
jbe@532 2139 SELECT DISTINCT ON ("initiative_id") * FROM "draft"
jbe@532 2140 ORDER BY "initiative_id", "id" DESC;
jbe@532 2141
jbe@532 2142
jbe@532 2143 CREATE OR REPLACE VIEW "issue_supporter_in_admission_state" AS
jbe@532 2144 SELECT
jbe@532 2145 "area"."unit_id",
jbe@532 2146 "issue"."area_id",
jbe@532 2147 "issue"."id" AS "issue_id",
jbe@532 2148 "supporter"."member_id",
jbe@532 2149 "direct_interest_snapshot"."weight"
jbe@532 2150 FROM "issue"
jbe@532 2151 JOIN "area" ON "area"."id" = "issue"."area_id"
jbe@532 2152 JOIN "supporter" ON "supporter"."issue_id" = "issue"."id"
jbe@532 2153 JOIN "direct_interest_snapshot"
jbe@532 2154 ON "direct_interest_snapshot"."snapshot_id" = "issue"."latest_snapshot_id"
jbe@532 2155 AND "direct_interest_snapshot"."issue_id" = "issue"."id"
jbe@532 2156 AND "direct_interest_snapshot"."member_id" = "supporter"."member_id"
jbe@532 2157 WHERE "issue"."state" = 'admission'::"issue_state";
jbe@532 2158
jbe@532 2159
jbe@532 2160 CREATE OR REPLACE VIEW "individual_suggestion_ranking" AS
jbe@532 2161 SELECT
jbe@532 2162 "opinion"."initiative_id",
jbe@532 2163 "opinion"."member_id",
jbe@532 2164 "direct_interest_snapshot"."weight",
jbe@532 2165 CASE WHEN
jbe@532 2166 ("opinion"."degree" = 2 AND "opinion"."fulfilled" = FALSE) OR
jbe@532 2167 ("opinion"."degree" = -2 AND "opinion"."fulfilled" = TRUE)
jbe@532 2168 THEN 1 ELSE
jbe@532 2169 CASE WHEN
jbe@532 2170 ("opinion"."degree" = 1 AND "opinion"."fulfilled" = FALSE) OR
jbe@532 2171 ("opinion"."degree" = -1 AND "opinion"."fulfilled" = TRUE)
jbe@532 2172 THEN 2 ELSE
jbe@532 2173 CASE WHEN
jbe@532 2174 ("opinion"."degree" = 2 AND "opinion"."fulfilled" = TRUE) OR
jbe@532 2175 ("opinion"."degree" = -2 AND "opinion"."fulfilled" = FALSE)
jbe@532 2176 THEN 3 ELSE 4 END
jbe@532 2177 END
jbe@532 2178 END AS "preference",
jbe@532 2179 "opinion"."suggestion_id"
jbe@532 2180 FROM "opinion"
jbe@532 2181 JOIN "initiative" ON "initiative"."id" = "opinion"."initiative_id"
jbe@532 2182 JOIN "issue" ON "issue"."id" = "initiative"."issue_id"
jbe@532 2183 JOIN "direct_interest_snapshot"
jbe@532 2184 ON "direct_interest_snapshot"."snapshot_id" = "issue"."latest_snapshot_id"
jbe@532 2185 AND "direct_interest_snapshot"."issue_id" = "issue"."id"
jbe@532 2186 AND "direct_interest_snapshot"."member_id" = "opinion"."member_id";
jbe@532 2187
jbe@532 2188
jbe@532 2189 CREATE VIEW "expired_session" AS
jbe@532 2190 SELECT * FROM "session" WHERE now() > "expiry";
jbe@532 2191
jbe@532 2192 CREATE RULE "delete" AS ON DELETE TO "expired_session" DO INSTEAD
jbe@532 2193 DELETE FROM "session" WHERE "id" = OLD."id";
jbe@532 2194
jbe@532 2195 COMMENT ON VIEW "expired_session" IS 'View containing all expired sessions where DELETE is possible';
jbe@532 2196 COMMENT ON RULE "delete" ON "expired_session" IS 'Rule allowing DELETE on rows in "expired_session" view, i.e. DELETE FROM "expired_session"';
jbe@532 2197
jbe@532 2198
jbe@532 2199 CREATE VIEW "expired_token" AS
jbe@532 2200 SELECT * FROM "token" WHERE now() > "expiry" AND NOT (
jbe@532 2201 "token_type" = 'authorization' AND "used" AND EXISTS (
jbe@532 2202 SELECT NULL FROM "token" AS "other"
jbe@532 2203 WHERE "other"."authorization_token_id" = "id" ) );
jbe@532 2204
jbe@532 2205 CREATE RULE "delete" AS ON DELETE TO "expired_token" DO INSTEAD
jbe@532 2206 DELETE FROM "token" WHERE "id" = OLD."id";
jbe@532 2207
jbe@532 2208 COMMENT ON VIEW "expired_token" IS 'View containing all expired tokens where DELETE is possible; Note that used authorization codes must not be deleted if still referred to by other tokens';
jbe@532 2209
jbe@532 2210
jbe@532 2211 CREATE VIEW "unused_snapshot" AS
jbe@532 2212 SELECT "snapshot".* FROM "snapshot"
jbe@532 2213 LEFT JOIN "issue"
jbe@532 2214 ON "snapshot"."id" = "issue"."latest_snapshot_id"
jbe@532 2215 OR "snapshot"."id" = "issue"."admission_snapshot_id"
jbe@532 2216 OR "snapshot"."id" = "issue"."half_freeze_snapshot_id"
jbe@532 2217 OR "snapshot"."id" = "issue"."full_freeze_snapshot_id"
jbe@532 2218 WHERE "issue"."id" ISNULL;
jbe@532 2219
jbe@532 2220 CREATE RULE "delete" AS ON DELETE TO "unused_snapshot" DO INSTEAD
jbe@532 2221 DELETE FROM "snapshot" WHERE "id" = OLD."id";
jbe@532 2222
jbe@532 2223 COMMENT ON VIEW "unused_snapshot" IS 'Snapshots that are not referenced by any issue (either as latest snapshot or as snapshot at phase/state change)';
jbe@532 2224
jbe@532 2225
jbe@532 2226 CREATE VIEW "expired_snapshot" AS
jbe@532 2227 SELECT "unused_snapshot".* FROM "unused_snapshot" CROSS JOIN "system_setting"
jbe@532 2228 WHERE "unused_snapshot"."calculated" <
jbe@532 2229 now() - "system_setting"."snapshot_retention";
jbe@532 2230
jbe@532 2231 CREATE RULE "delete" AS ON DELETE TO "expired_snapshot" DO INSTEAD
jbe@532 2232 DELETE FROM "snapshot" WHERE "id" = OLD."id";
jbe@532 2233
jbe@532 2234 COMMENT ON VIEW "expired_snapshot" IS 'Contains "unused_snapshot"s that are older than "system_setting"."snapshot_retention" (for deletion)';
jbe@532 2235
jbe@532 2236
jbe@532 2237 COMMENT ON COLUMN "delegation_chain_row"."participation" IS 'In case of delegation chains for issues: interest; for area and global delegation chains: always null';
jbe@532 2238
jbe@532 2239
jbe@532 2240 CREATE OR REPLACE FUNCTION "delegation_chain"
jbe@532 2241 ( "member_id_p" "member"."id"%TYPE,
jbe@532 2242 "unit_id_p" "unit"."id"%TYPE,
jbe@532 2243 "area_id_p" "area"."id"%TYPE,
jbe@532 2244 "issue_id_p" "issue"."id"%TYPE,
jbe@532 2245 "simulate_trustee_id_p" "member"."id"%TYPE DEFAULT NULL,
jbe@532 2246 "simulate_default_p" BOOLEAN DEFAULT FALSE )
jbe@532 2247 RETURNS SETOF "delegation_chain_row"
jbe@532 2248 LANGUAGE 'plpgsql' STABLE AS $$
jbe@532 2249 DECLARE
jbe@532 2250 "scope_v" "delegation_scope";
jbe@532 2251 "unit_id_v" "unit"."id"%TYPE;
jbe@532 2252 "area_id_v" "area"."id"%TYPE;
jbe@532 2253 "issue_row" "issue"%ROWTYPE;
jbe@532 2254 "visited_member_ids" INT4[]; -- "member"."id"%TYPE[]
jbe@532 2255 "loop_member_id_v" "member"."id"%TYPE;
jbe@532 2256 "output_row" "delegation_chain_row";
jbe@532 2257 "output_rows" "delegation_chain_row"[];
jbe@532 2258 "simulate_v" BOOLEAN;
jbe@532 2259 "simulate_here_v" BOOLEAN;
jbe@532 2260 "delegation_row" "delegation"%ROWTYPE;
jbe@532 2261 "row_count" INT4;
jbe@532 2262 "i" INT4;
jbe@532 2263 "loop_v" BOOLEAN;
jbe@532 2264 BEGIN
jbe@532 2265 IF "simulate_trustee_id_p" NOTNULL AND "simulate_default_p" THEN
jbe@532 2266 RAISE EXCEPTION 'Both "simulate_trustee_id_p" is set, and "simulate_default_p" is true';
jbe@532 2267 END IF;
jbe@532 2268 IF "simulate_trustee_id_p" NOTNULL OR "simulate_default_p" THEN
jbe@532 2269 "simulate_v" := TRUE;
jbe@532 2270 ELSE
jbe@532 2271 "simulate_v" := FALSE;
jbe@532 2272 END IF;
jbe@532 2273 IF
jbe@532 2274 "unit_id_p" NOTNULL AND
jbe@532 2275 "area_id_p" ISNULL AND
jbe@532 2276 "issue_id_p" ISNULL
jbe@532 2277 THEN
jbe@532 2278 "scope_v" := 'unit';
jbe@532 2279 "unit_id_v" := "unit_id_p";
jbe@532 2280 ELSIF
jbe@532 2281 "unit_id_p" ISNULL AND
jbe@532 2282 "area_id_p" NOTNULL AND
jbe@532 2283 "issue_id_p" ISNULL
jbe@532 2284 THEN
jbe@532 2285 "scope_v" := 'area';
jbe@532 2286 "area_id_v" := "area_id_p";
jbe@532 2287 SELECT "unit_id" INTO "unit_id_v"
jbe@532 2288 FROM "area" WHERE "id" = "area_id_v";
jbe@532 2289 ELSIF
jbe@532 2290 "unit_id_p" ISNULL AND
jbe@532 2291 "area_id_p" ISNULL AND
jbe@532 2292 "issue_id_p" NOTNULL
jbe@532 2293 THEN
jbe@532 2294 SELECT INTO "issue_row" * FROM "issue" WHERE "id" = "issue_id_p";
jbe@532 2295 IF "issue_row"."id" ISNULL THEN
jbe@532 2296 RETURN;
jbe@532 2297 END IF;
jbe@532 2298 IF "issue_row"."closed" NOTNULL THEN
jbe@532 2299 IF "simulate_v" THEN
jbe@532 2300 RAISE EXCEPTION 'Tried to simulate delegation chain for closed issue.';
jbe@532 2301 END IF;
jbe@532 2302 FOR "output_row" IN
jbe@532 2303 SELECT * FROM
jbe@532 2304 "delegation_chain_for_closed_issue"("member_id_p", "issue_id_p")
jbe@532 2305 LOOP
jbe@532 2306 RETURN NEXT "output_row";
jbe@532 2307 END LOOP;
jbe@532 2308 RETURN;
jbe@532 2309 END IF;
jbe@532 2310 "scope_v" := 'issue';
jbe@532 2311 SELECT "area_id" INTO "area_id_v"
jbe@532 2312 FROM "issue" WHERE "id" = "issue_id_p";
jbe@532 2313 SELECT "unit_id" INTO "unit_id_v"
jbe@532 2314 FROM "area" WHERE "id" = "area_id_v";
jbe@532 2315 ELSE
jbe@532 2316 RAISE EXCEPTION 'Exactly one of unit_id_p, area_id_p, or issue_id_p must be NOTNULL.';
jbe@532 2317 END IF;
jbe@532 2318 "visited_member_ids" := '{}';
jbe@532 2319 "loop_member_id_v" := NULL;
jbe@532 2320 "output_rows" := '{}';
jbe@532 2321 "output_row"."index" := 0;
jbe@532 2322 "output_row"."member_id" := "member_id_p";
jbe@532 2323 "output_row"."member_valid" := TRUE;
jbe@532 2324 "output_row"."participation" := FALSE;
jbe@532 2325 "output_row"."overridden" := FALSE;
jbe@532 2326 "output_row"."disabled_out" := FALSE;
jbe@532 2327 "output_row"."scope_out" := NULL;
jbe@532 2328 LOOP
jbe@532 2329 IF "visited_member_ids" @> ARRAY["output_row"."member_id"] THEN
jbe@532 2330 "loop_member_id_v" := "output_row"."member_id";
jbe@532 2331 ELSE
jbe@532 2332 "visited_member_ids" :=
jbe@532 2333 "visited_member_ids" || "output_row"."member_id";
jbe@532 2334 END IF;
jbe@532 2335 IF "output_row"."participation" ISNULL THEN
jbe@532 2336 "output_row"."overridden" := NULL;
jbe@532 2337 ELSIF "output_row"."participation" THEN
jbe@532 2338 "output_row"."overridden" := TRUE;
jbe@532 2339 END IF;
jbe@532 2340 "output_row"."scope_in" := "output_row"."scope_out";
jbe@532 2341 "output_row"."member_valid" := EXISTS (
jbe@556 2342 SELECT NULL FROM "member" JOIN "privilege"
jbe@556 2343 ON "privilege"."member_id" = "member"."id"
jbe@556 2344 AND "privilege"."unit_id" = "unit_id_v"
jbe@532 2345 WHERE "id" = "output_row"."member_id"
jbe@556 2346 AND "member"."active" AND "privilege"."voting_right"
jbe@532 2347 );
jbe@532 2348 "simulate_here_v" := (
jbe@532 2349 "simulate_v" AND
jbe@532 2350 "output_row"."member_id" = "member_id_p"
jbe@532 2351 );
jbe@532 2352 "delegation_row" := ROW(NULL);
jbe@532 2353 IF "output_row"."member_valid" OR "simulate_here_v" THEN
jbe@532 2354 IF "scope_v" = 'unit' THEN
jbe@532 2355 IF NOT "simulate_here_v" THEN
jbe@532 2356 SELECT * INTO "delegation_row" FROM "delegation"
jbe@532 2357 WHERE "truster_id" = "output_row"."member_id"
jbe@532 2358 AND "unit_id" = "unit_id_v";
jbe@532 2359 END IF;
jbe@532 2360 ELSIF "scope_v" = 'area' THEN
jbe@532 2361 IF "simulate_here_v" THEN
jbe@532 2362 IF "simulate_trustee_id_p" ISNULL THEN
jbe@532 2363 SELECT * INTO "delegation_row" FROM "delegation"
jbe@532 2364 WHERE "truster_id" = "output_row"."member_id"
jbe@532 2365 AND "unit_id" = "unit_id_v";
jbe@532 2366 END IF;
jbe@532 2367 ELSE
jbe@532 2368 SELECT * INTO "delegation_row" FROM "delegation"
jbe@532 2369 WHERE "truster_id" = "output_row"."member_id"
jbe@532 2370 AND (
jbe@532 2371 "unit_id" = "unit_id_v" OR
jbe@532 2372 "area_id" = "area_id_v"
jbe@532 2373 )
jbe@532 2374 ORDER BY "scope" DESC;
jbe@532 2375 END IF;
jbe@532 2376 ELSIF "scope_v" = 'issue' THEN
jbe@532 2377 IF "issue_row"."fully_frozen" ISNULL THEN
jbe@532 2378 "output_row"."participation" := EXISTS (
jbe@532 2379 SELECT NULL FROM "interest"
jbe@532 2380 WHERE "issue_id" = "issue_id_p"
jbe@532 2381 AND "member_id" = "output_row"."member_id"
jbe@532 2382 );
jbe@532 2383 ELSE
jbe@532 2384 IF "output_row"."member_id" = "member_id_p" THEN
jbe@532 2385 "output_row"."participation" := EXISTS (
jbe@532 2386 SELECT NULL FROM "direct_voter"
jbe@532 2387 WHERE "issue_id" = "issue_id_p"
jbe@532 2388 AND "member_id" = "output_row"."member_id"
jbe@532 2389 );
jbe@532 2390 ELSE
jbe@532 2391 "output_row"."participation" := NULL;
jbe@532 2392 END IF;
jbe@532 2393 END IF;
jbe@532 2394 IF "simulate_here_v" THEN
jbe@532 2395 IF "simulate_trustee_id_p" ISNULL THEN
jbe@532 2396 SELECT * INTO "delegation_row" FROM "delegation"
jbe@532 2397 WHERE "truster_id" = "output_row"."member_id"
jbe@532 2398 AND (
jbe@532 2399 "unit_id" = "unit_id_v" OR
jbe@532 2400 "area_id" = "area_id_v"
jbe@532 2401 )
jbe@532 2402 ORDER BY "scope" DESC;
jbe@532 2403 END IF;
jbe@532 2404 ELSE
jbe@532 2405 SELECT * INTO "delegation_row" FROM "delegation"
jbe@532 2406 WHERE "truster_id" = "output_row"."member_id"
jbe@532 2407 AND (
jbe@532 2408 "unit_id" = "unit_id_v" OR
jbe@532 2409 "area_id" = "area_id_v" OR
jbe@532 2410 "issue_id" = "issue_id_p"
jbe@532 2411 )
jbe@532 2412 ORDER BY "scope" DESC;
jbe@532 2413 END IF;
jbe@532 2414 END IF;
jbe@532 2415 ELSE
jbe@532 2416 "output_row"."participation" := FALSE;
jbe@532 2417 END IF;
jbe@532 2418 IF "simulate_here_v" AND "simulate_trustee_id_p" NOTNULL THEN
jbe@532 2419 "output_row"."scope_out" := "scope_v";
jbe@532 2420 "output_rows" := "output_rows" || "output_row";
jbe@532 2421 "output_row"."member_id" := "simulate_trustee_id_p";
jbe@532 2422 ELSIF "delegation_row"."trustee_id" NOTNULL THEN
jbe@532 2423 "output_row"."scope_out" := "delegation_row"."scope";
jbe@532 2424 "output_rows" := "output_rows" || "output_row";
jbe@532 2425 "output_row"."member_id" := "delegation_row"."trustee_id";
jbe@532 2426 ELSIF "delegation_row"."scope" NOTNULL THEN
jbe@532 2427 "output_row"."scope_out" := "delegation_row"."scope";
jbe@532 2428 "output_row"."disabled_out" := TRUE;
jbe@532 2429 "output_rows" := "output_rows" || "output_row";
jbe@532 2430 EXIT;
jbe@532 2431 ELSE
jbe@532 2432 "output_row"."scope_out" := NULL;
jbe@532 2433 "output_rows" := "output_rows" || "output_row";
jbe@532 2434 EXIT;
jbe@532 2435 END IF;
jbe@532 2436 EXIT WHEN "loop_member_id_v" NOTNULL;
jbe@532 2437 "output_row"."index" := "output_row"."index" + 1;
jbe@532 2438 END LOOP;
jbe@532 2439 "row_count" := array_upper("output_rows", 1);
jbe@532 2440 "i" := 1;
jbe@532 2441 "loop_v" := FALSE;
jbe@532 2442 LOOP
jbe@532 2443 "output_row" := "output_rows"["i"];
jbe@532 2444 EXIT WHEN "output_row" ISNULL; -- NOTE: ISNULL and NOT ... NOTNULL produce different results!
jbe@532 2445 IF "loop_v" THEN
jbe@532 2446 IF "i" + 1 = "row_count" THEN
jbe@532 2447 "output_row"."loop" := 'last';
jbe@532 2448 ELSIF "i" = "row_count" THEN
jbe@532 2449 "output_row"."loop" := 'repetition';
jbe@532 2450 ELSE
jbe@532 2451 "output_row"."loop" := 'intermediate';
jbe@532 2452 END IF;
jbe@532 2453 ELSIF "output_row"."member_id" = "loop_member_id_v" THEN
jbe@532 2454 "output_row"."loop" := 'first';
jbe@532 2455 "loop_v" := TRUE;
jbe@532 2456 END IF;
jbe@532 2457 IF "scope_v" = 'unit' THEN
jbe@532 2458 "output_row"."participation" := NULL;
jbe@532 2459 END IF;
jbe@532 2460 RETURN NEXT "output_row";
jbe@532 2461 "i" := "i" + 1;
jbe@532 2462 END LOOP;
jbe@532 2463 RETURN;
jbe@532 2464 END;
jbe@532 2465 $$;
jbe@532 2466
jbe@532 2467
jbe@532 2468 CREATE OR REPLACE FUNCTION "get_initiatives_for_notification"
jbe@532 2469 ( "recipient_id_p" "member"."id"%TYPE )
jbe@532 2470 RETURNS SETOF "initiative_for_notification"
jbe@532 2471 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 2472 DECLARE
jbe@532 2473 "result_row" "initiative_for_notification"%ROWTYPE;
jbe@532 2474 "last_draft_id_v" "draft"."id"%TYPE;
jbe@532 2475 "last_suggestion_id_v" "suggestion"."id"%TYPE;
jbe@532 2476 BEGIN
jbe@532 2477 PERFORM "require_transaction_isolation"();
jbe@532 2478 PERFORM NULL FROM "member" WHERE "id" = "recipient_id_p" FOR UPDATE;
jbe@532 2479 FOR "result_row" IN
jbe@532 2480 SELECT * FROM "initiative_for_notification"
jbe@532 2481 WHERE "recipient_id" = "recipient_id_p"
jbe@532 2482 LOOP
jbe@532 2483 SELECT "id" INTO "last_draft_id_v" FROM "draft"
jbe@532 2484 WHERE "draft"."initiative_id" = "result_row"."initiative_id"
jbe@532 2485 ORDER BY "id" DESC LIMIT 1;
jbe@532 2486 SELECT "id" INTO "last_suggestion_id_v" FROM "suggestion"
jbe@532 2487 WHERE "suggestion"."initiative_id" = "result_row"."initiative_id"
jbe@532 2488 ORDER BY "id" DESC LIMIT 1;
jbe@532 2489 INSERT INTO "notification_initiative_sent"
jbe@532 2490 ("member_id", "initiative_id", "last_draft_id", "last_suggestion_id")
jbe@532 2491 VALUES (
jbe@532 2492 "recipient_id_p",
jbe@532 2493 "result_row"."initiative_id",
jbe@532 2494 "last_draft_id_v",
jbe@532 2495 "last_suggestion_id_v" )
jbe@532 2496 ON CONFLICT ("member_id", "initiative_id") DO UPDATE SET
jbe@532 2497 "last_draft_id" = "last_draft_id_v",
jbe@532 2498 "last_suggestion_id" = "last_suggestion_id_v";
jbe@532 2499 RETURN NEXT "result_row";
jbe@532 2500 END LOOP;
jbe@532 2501 DELETE FROM "notification_initiative_sent"
jbe@532 2502 USING "initiative", "issue"
jbe@532 2503 WHERE "notification_initiative_sent"."member_id" = "recipient_id_p"
jbe@532 2504 AND "initiative"."id" = "notification_initiative_sent"."initiative_id"
jbe@532 2505 AND "issue"."id" = "initiative"."issue_id"
jbe@532 2506 AND ( "issue"."closed" NOTNULL OR "issue"."fully_frozen" NOTNULL );
jbe@532 2507 UPDATE "member" SET
jbe@532 2508 "notification_counter" = "notification_counter" + 1,
jbe@532 2509 "notification_sent" = now()
jbe@532 2510 WHERE "id" = "recipient_id_p";
jbe@532 2511 RETURN;
jbe@532 2512 END;
jbe@532 2513 $$;
jbe@532 2514
jbe@532 2515
jbe@532 2516 CREATE OR REPLACE FUNCTION "calculate_member_counts"()
jbe@532 2517 RETURNS VOID
jbe@532 2518 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 2519 BEGIN
jbe@532 2520 PERFORM "require_transaction_isolation"();
jbe@532 2521 DELETE FROM "member_count";
jbe@532 2522 INSERT INTO "member_count" ("total_count")
jbe@532 2523 SELECT "total_count" FROM "member_count_view";
jbe@532 2524 UPDATE "unit" SET "member_count" = "view"."member_count"
jbe@532 2525 FROM "unit_member_count" AS "view"
jbe@532 2526 WHERE "view"."unit_id" = "unit"."id";
jbe@532 2527 RETURN;
jbe@532 2528 END;
jbe@532 2529 $$;
jbe@532 2530
jbe@532 2531 COMMENT ON FUNCTION "calculate_member_counts"() IS 'Updates "member_count" table and "member_count" column of table "area" by materializing data from views "member_count_view" and "unit_member_count"';
jbe@532 2532
jbe@532 2533
jbe@532 2534 CREATE FUNCTION "calculate_area_quorum"()
jbe@532 2535 RETURNS VOID
jbe@532 2536 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 2537 BEGIN
jbe@532 2538 PERFORM "dont_require_transaction_isolation"();
jbe@532 2539 UPDATE "area" SET "issue_quorum" = "view"."issue_quorum"
jbe@532 2540 FROM "area_quorum" AS "view"
jbe@532 2541 WHERE "view"."area_id" = "area"."id";
jbe@532 2542 RETURN;
jbe@532 2543 END;
jbe@532 2544 $$;
jbe@532 2545
jbe@532 2546 COMMENT ON FUNCTION "calculate_area_quorum"() IS 'Calculate column "issue_quorum" in table "area" from view "area_quorum"';
jbe@532 2547
jbe@532 2548
jbe@532 2549 DROP VIEW "remaining_harmonic_initiative_weight_summands";
jbe@532 2550 DROP VIEW "remaining_harmonic_supporter_weight";
jbe@532 2551
jbe@532 2552
jbe@532 2553 CREATE VIEW "remaining_harmonic_supporter_weight" AS
jbe@532 2554 SELECT
jbe@532 2555 "direct_interest_snapshot"."snapshot_id",
jbe@532 2556 "direct_interest_snapshot"."issue_id",
jbe@532 2557 "direct_interest_snapshot"."member_id",
jbe@532 2558 "direct_interest_snapshot"."weight" AS "weight_num",
jbe@532 2559 count("initiative"."id") AS "weight_den"
jbe@532 2560 FROM "issue"
jbe@532 2561 JOIN "direct_interest_snapshot"
jbe@532 2562 ON "issue"."latest_snapshot_id" = "direct_interest_snapshot"."snapshot_id"
jbe@532 2563 AND "issue"."id" = "direct_interest_snapshot"."issue_id"
jbe@532 2564 JOIN "initiative"
jbe@532 2565 ON "issue"."id" = "initiative"."issue_id"
jbe@532 2566 AND "initiative"."harmonic_weight" ISNULL
jbe@532 2567 JOIN "direct_supporter_snapshot"
jbe@532 2568 ON "issue"."latest_snapshot_id" = "direct_supporter_snapshot"."snapshot_id"
jbe@532 2569 AND "initiative"."id" = "direct_supporter_snapshot"."initiative_id"
jbe@532 2570 AND "direct_interest_snapshot"."member_id" = "direct_supporter_snapshot"."member_id"
jbe@532 2571 AND (
jbe@532 2572 "direct_supporter_snapshot"."satisfied" = TRUE OR
jbe@532 2573 coalesce("initiative"."admitted", FALSE) = FALSE
jbe@532 2574 )
jbe@532 2575 GROUP BY
jbe@532 2576 "direct_interest_snapshot"."snapshot_id",
jbe@532 2577 "direct_interest_snapshot"."issue_id",
jbe@532 2578 "direct_interest_snapshot"."member_id",
jbe@532 2579 "direct_interest_snapshot"."weight";
jbe@532 2580
jbe@532 2581
jbe@532 2582 CREATE VIEW "remaining_harmonic_initiative_weight_summands" AS
jbe@532 2583 SELECT
jbe@532 2584 "initiative"."issue_id",
jbe@532 2585 "initiative"."id" AS "initiative_id",
jbe@532 2586 "initiative"."admitted",
jbe@532 2587 sum("remaining_harmonic_supporter_weight"."weight_num") AS "weight_num",
jbe@532 2588 "remaining_harmonic_supporter_weight"."weight_den"
jbe@532 2589 FROM "remaining_harmonic_supporter_weight"
jbe@532 2590 JOIN "initiative"
jbe@532 2591 ON "remaining_harmonic_supporter_weight"."issue_id" = "initiative"."issue_id"
jbe@532 2592 AND "initiative"."harmonic_weight" ISNULL
jbe@532 2593 JOIN "direct_supporter_snapshot"
jbe@532 2594 ON "remaining_harmonic_supporter_weight"."snapshot_id" = "direct_supporter_snapshot"."snapshot_id"
jbe@532 2595 AND "initiative"."id" = "direct_supporter_snapshot"."initiative_id"
jbe@532 2596 AND "remaining_harmonic_supporter_weight"."member_id" = "direct_supporter_snapshot"."member_id"
jbe@532 2597 AND (
jbe@532 2598 "direct_supporter_snapshot"."satisfied" = TRUE OR
jbe@532 2599 coalesce("initiative"."admitted", FALSE) = FALSE
jbe@532 2600 )
jbe@532 2601 GROUP BY
jbe@532 2602 "initiative"."issue_id",
jbe@532 2603 "initiative"."id",
jbe@532 2604 "initiative"."admitted",
jbe@532 2605 "remaining_harmonic_supporter_weight"."weight_den";
jbe@532 2606
jbe@532 2607
jbe@532 2608 DROP FUNCTION "create_population_snapshot"
jbe@532 2609 ( "issue_id_p" "issue"."id"%TYPE );
jbe@532 2610
jbe@532 2611
jbe@532 2612 DROP FUNCTION "weight_of_added_delegations_for_population_snapshot"
jbe@532 2613 ( "issue_id_p" "issue"."id"%TYPE,
jbe@532 2614 "member_id_p" "member"."id"%TYPE,
jbe@532 2615 "delegate_member_ids_p" "delegating_population_snapshot"."delegate_member_ids"%TYPE );
jbe@532 2616
jbe@532 2617
jbe@532 2618 DROP FUNCTION "weight_of_added_delegations_for_interest_snapshot"
jbe@532 2619 ( "issue_id_p" "issue"."id"%TYPE,
jbe@532 2620 "member_id_p" "member"."id"%TYPE,
jbe@532 2621 "delegate_member_ids_p" "delegating_interest_snapshot"."delegate_member_ids"%TYPE );
jbe@532 2622
jbe@532 2623
jbe@532 2624 CREATE FUNCTION "weight_of_added_delegations_for_snapshot"
jbe@532 2625 ( "snapshot_id_p" "snapshot"."id"%TYPE,
jbe@532 2626 "issue_id_p" "issue"."id"%TYPE,
jbe@532 2627 "member_id_p" "member"."id"%TYPE,
jbe@532 2628 "delegate_member_ids_p" "delegating_interest_snapshot"."delegate_member_ids"%TYPE )
jbe@532 2629 RETURNS "direct_interest_snapshot"."weight"%TYPE
jbe@532 2630 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 2631 DECLARE
jbe@532 2632 "issue_delegation_row" "issue_delegation"%ROWTYPE;
jbe@532 2633 "delegate_member_ids_v" "delegating_interest_snapshot"."delegate_member_ids"%TYPE;
jbe@532 2634 "weight_v" INT4;
jbe@532 2635 "sub_weight_v" INT4;
jbe@532 2636 BEGIN
jbe@532 2637 PERFORM "require_transaction_isolation"();
jbe@532 2638 "weight_v" := 0;
jbe@532 2639 FOR "issue_delegation_row" IN
jbe@532 2640 SELECT * FROM "issue_delegation"
jbe@532 2641 WHERE "trustee_id" = "member_id_p"
jbe@532 2642 AND "issue_id" = "issue_id_p"
jbe@532 2643 LOOP
jbe@532 2644 IF NOT EXISTS (
jbe@532 2645 SELECT NULL FROM "direct_interest_snapshot"
jbe@532 2646 WHERE "snapshot_id" = "snapshot_id_p"
jbe@532 2647 AND "issue_id" = "issue_id_p"
jbe@532 2648 AND "member_id" = "issue_delegation_row"."truster_id"
jbe@532 2649 ) AND NOT EXISTS (
jbe@532 2650 SELECT NULL FROM "delegating_interest_snapshot"
jbe@532 2651 WHERE "snapshot_id" = "snapshot_id_p"
jbe@532 2652 AND "issue_id" = "issue_id_p"
jbe@532 2653 AND "member_id" = "issue_delegation_row"."truster_id"
jbe@532 2654 ) THEN
jbe@532 2655 "delegate_member_ids_v" :=
jbe@532 2656 "member_id_p" || "delegate_member_ids_p";
jbe@532 2657 INSERT INTO "delegating_interest_snapshot" (
jbe@532 2658 "snapshot_id",
jbe@532 2659 "issue_id",
jbe@532 2660 "member_id",
jbe@532 2661 "scope",
jbe@532 2662 "delegate_member_ids"
jbe@532 2663 ) VALUES (
jbe@532 2664 "snapshot_id_p",
jbe@532 2665 "issue_id_p",
jbe@532 2666 "issue_delegation_row"."truster_id",
jbe@532 2667 "issue_delegation_row"."scope",
jbe@532 2668 "delegate_member_ids_v"
jbe@532 2669 );
jbe@532 2670 "sub_weight_v" := 1 +
jbe@532 2671 "weight_of_added_delegations_for_snapshot"(
jbe@532 2672 "snapshot_id_p",
jbe@532 2673 "issue_id_p",
jbe@532 2674 "issue_delegation_row"."truster_id",
jbe@532 2675 "delegate_member_ids_v"
jbe@532 2676 );
jbe@532 2677 UPDATE "delegating_interest_snapshot"
jbe@532 2678 SET "weight" = "sub_weight_v"
jbe@532 2679 WHERE "snapshot_id" = "snapshot_id_p"
jbe@532 2680 AND "issue_id" = "issue_id_p"
jbe@532 2681 AND "member_id" = "issue_delegation_row"."truster_id";
jbe@532 2682 "weight_v" := "weight_v" + "sub_weight_v";
jbe@532 2683 END IF;
jbe@532 2684 END LOOP;
jbe@532 2685 RETURN "weight_v";
jbe@532 2686 END;
jbe@532 2687 $$;
jbe@532 2688
jbe@532 2689 COMMENT ON FUNCTION "weight_of_added_delegations_for_snapshot"
jbe@532 2690 ( "snapshot"."id"%TYPE,
jbe@532 2691 "issue"."id"%TYPE,
jbe@532 2692 "member"."id"%TYPE,
jbe@532 2693 "delegating_interest_snapshot"."delegate_member_ids"%TYPE )
jbe@532 2694 IS 'Helper function for "fill_snapshot" function';
jbe@532 2695
jbe@532 2696
jbe@532 2697 DROP FUNCTION "create_interest_snapshot"
jbe@532 2698 ( "issue_id_p" "issue"."id"%TYPE );
jbe@532 2699
jbe@532 2700
jbe@532 2701 DROP FUNCTION "create_snapshot"
jbe@532 2702 ( "issue_id_p" "issue"."id"%TYPE );
jbe@532 2703
jbe@532 2704
jbe@532 2705 CREATE FUNCTION "take_snapshot"
jbe@532 2706 ( "issue_id_p" "issue"."id"%TYPE,
jbe@532 2707 "area_id_p" "area"."id"%TYPE = NULL )
jbe@532 2708 RETURNS "snapshot"."id"%TYPE
jbe@532 2709 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 2710 DECLARE
jbe@532 2711 "area_id_v" "area"."id"%TYPE;
jbe@532 2712 "unit_id_v" "unit"."id"%TYPE;
jbe@532 2713 "snapshot_id_v" "snapshot"."id"%TYPE;
jbe@532 2714 "issue_id_v" "issue"."id"%TYPE;
jbe@532 2715 "member_id_v" "member"."id"%TYPE;
jbe@532 2716 BEGIN
jbe@532 2717 IF "issue_id_p" NOTNULL AND "area_id_p" NOTNULL THEN
jbe@532 2718 RAISE EXCEPTION 'One of "issue_id_p" and "area_id_p" must be NULL';
jbe@532 2719 END IF;
jbe@532 2720 PERFORM "require_transaction_isolation"();
jbe@532 2721 IF "issue_id_p" ISNULL THEN
jbe@532 2722 "area_id_v" := "area_id_p";
jbe@532 2723 ELSE
jbe@532 2724 SELECT "area_id" INTO "area_id_v"
jbe@532 2725 FROM "issue" WHERE "id" = "issue_id_p";
jbe@532 2726 END IF;
jbe@562 2727 SELECT "unit_id" INTO "unit_id_v" FROM "area" WHERE "id" = "area_id_v";
jbe@532 2728 INSERT INTO "snapshot" ("area_id", "issue_id")
jbe@532 2729 VALUES ("area_id_v", "issue_id_p")
jbe@532 2730 RETURNING "id" INTO "snapshot_id_v";
jbe@532 2731 INSERT INTO "snapshot_population" ("snapshot_id", "member_id")
jbe@532 2732 SELECT "snapshot_id_v", "member_id"
jbe@532 2733 FROM "unit_member" WHERE "unit_id" = "unit_id_v";
jbe@532 2734 UPDATE "snapshot" SET
jbe@532 2735 "population" = (
jbe@532 2736 SELECT count(1) FROM "snapshot_population"
jbe@532 2737 WHERE "snapshot_id" = "snapshot_id_v"
jbe@532 2738 ) WHERE "id" = "snapshot_id_v";
jbe@532 2739 FOR "issue_id_v" IN
jbe@532 2740 SELECT "id" FROM "issue"
jbe@532 2741 WHERE CASE WHEN "issue_id_p" ISNULL THEN
jbe@532 2742 "area_id" = "area_id_p" AND
jbe@532 2743 "state" = 'admission'
jbe@532 2744 ELSE
jbe@532 2745 "id" = "issue_id_p"
jbe@532 2746 END
jbe@532 2747 LOOP
jbe@532 2748 INSERT INTO "snapshot_issue" ("snapshot_id", "issue_id")
jbe@532 2749 VALUES ("snapshot_id_v", "issue_id_v");
jbe@532 2750 INSERT INTO "direct_interest_snapshot"
jbe@532 2751 ("snapshot_id", "issue_id", "member_id")
jbe@532 2752 SELECT
jbe@532 2753 "snapshot_id_v" AS "snapshot_id",
jbe@532 2754 "issue_id_v" AS "issue_id",
jbe@532 2755 "member"."id" AS "member_id"
jbe@532 2756 FROM "issue"
jbe@532 2757 JOIN "area" ON "issue"."area_id" = "area"."id"
jbe@532 2758 JOIN "interest" ON "issue"."id" = "interest"."issue_id"
jbe@532 2759 JOIN "member" ON "interest"."member_id" = "member"."id"
jbe@556 2760 JOIN "privilege"
jbe@556 2761 ON "privilege"."unit_id" = "area"."unit_id"
jbe@556 2762 AND "privilege"."member_id" = "member"."id"
jbe@532 2763 WHERE "issue"."id" = "issue_id_v"
jbe@556 2764 AND "member"."active" AND "privilege"."voting_right";
jbe@532 2765 FOR "member_id_v" IN
jbe@532 2766 SELECT "member_id" FROM "direct_interest_snapshot"
jbe@532 2767 WHERE "snapshot_id" = "snapshot_id_v"
jbe@532 2768 AND "issue_id" = "issue_id_v"
jbe@532 2769 LOOP
jbe@532 2770 UPDATE "direct_interest_snapshot" SET
jbe@532 2771 "weight" = 1 +
jbe@532 2772 "weight_of_added_delegations_for_snapshot"(
jbe@532 2773 "snapshot_id_v",
jbe@532 2774 "issue_id_v",
jbe@532 2775 "member_id_v",
jbe@532 2776 '{}'
jbe@532 2777 )
jbe@532 2778 WHERE "snapshot_id" = "snapshot_id_v"
jbe@532 2779 AND "issue_id" = "issue_id_v"
jbe@532 2780 AND "member_id" = "member_id_v";
jbe@532 2781 END LOOP;
jbe@532 2782 INSERT INTO "direct_supporter_snapshot"
jbe@532 2783 ( "snapshot_id", "issue_id", "initiative_id", "member_id",
jbe@532 2784 "draft_id", "informed", "satisfied" )
jbe@532 2785 SELECT
jbe@532 2786 "snapshot_id_v" AS "snapshot_id",
jbe@532 2787 "issue_id_v" AS "issue_id",
jbe@532 2788 "initiative"."id" AS "initiative_id",
jbe@532 2789 "supporter"."member_id" AS "member_id",
jbe@532 2790 "supporter"."draft_id" AS "draft_id",
jbe@532 2791 "supporter"."draft_id" = "current_draft"."id" AS "informed",
jbe@532 2792 NOT EXISTS (
jbe@532 2793 SELECT NULL FROM "critical_opinion"
jbe@532 2794 WHERE "initiative_id" = "initiative"."id"
jbe@532 2795 AND "member_id" = "supporter"."member_id"
jbe@532 2796 ) AS "satisfied"
jbe@532 2797 FROM "initiative"
jbe@532 2798 JOIN "supporter"
jbe@532 2799 ON "supporter"."initiative_id" = "initiative"."id"
jbe@532 2800 JOIN "current_draft"
jbe@532 2801 ON "initiative"."id" = "current_draft"."initiative_id"
jbe@532 2802 JOIN "direct_interest_snapshot"
jbe@532 2803 ON "snapshot_id_v" = "direct_interest_snapshot"."snapshot_id"
jbe@532 2804 AND "supporter"."member_id" = "direct_interest_snapshot"."member_id"
jbe@532 2805 AND "initiative"."issue_id" = "direct_interest_snapshot"."issue_id"
jbe@532 2806 WHERE "initiative"."issue_id" = "issue_id_v";
jbe@532 2807 DELETE FROM "temporary_suggestion_counts";
jbe@532 2808 INSERT INTO "temporary_suggestion_counts"
jbe@532 2809 ( "id",
jbe@532 2810 "minus2_unfulfilled_count", "minus2_fulfilled_count",
jbe@532 2811 "minus1_unfulfilled_count", "minus1_fulfilled_count",
jbe@532 2812 "plus1_unfulfilled_count", "plus1_fulfilled_count",
jbe@532 2813 "plus2_unfulfilled_count", "plus2_fulfilled_count" )
jbe@532 2814 SELECT
jbe@532 2815 "suggestion"."id",
jbe@532 2816 ( SELECT coalesce(sum("di"."weight"), 0)
jbe@532 2817 FROM "opinion" JOIN "direct_interest_snapshot" AS "di"
jbe@532 2818 ON "di"."snapshot_id" = "snapshot_id_v"
jbe@532 2819 AND "di"."issue_id" = "issue_id_v"
jbe@532 2820 AND "di"."member_id" = "opinion"."member_id"
jbe@532 2821 WHERE "opinion"."suggestion_id" = "suggestion"."id"
jbe@532 2822 AND "opinion"."degree" = -2
jbe@532 2823 AND "opinion"."fulfilled" = FALSE
jbe@532 2824 ) AS "minus2_unfulfilled_count",
jbe@532 2825 ( SELECT coalesce(sum("di"."weight"), 0)
jbe@532 2826 FROM "opinion" JOIN "direct_interest_snapshot" AS "di"
jbe@532 2827 ON "di"."snapshot_id" = "snapshot_id_v"
jbe@532 2828 AND "di"."issue_id" = "issue_id_v"
jbe@532 2829 AND "di"."member_id" = "opinion"."member_id"
jbe@532 2830 WHERE "opinion"."suggestion_id" = "suggestion"."id"
jbe@532 2831 AND "opinion"."degree" = -2
jbe@532 2832 AND "opinion"."fulfilled" = TRUE
jbe@532 2833 ) AS "minus2_fulfilled_count",
jbe@532 2834 ( SELECT coalesce(sum("di"."weight"), 0)
jbe@532 2835 FROM "opinion" JOIN "direct_interest_snapshot" AS "di"
jbe@532 2836 ON "di"."snapshot_id" = "snapshot_id_v"
jbe@532 2837 AND "di"."issue_id" = "issue_id_v"
jbe@532 2838 AND "di"."member_id" = "opinion"."member_id"
jbe@532 2839 WHERE "opinion"."suggestion_id" = "suggestion"."id"
jbe@532 2840 AND "opinion"."degree" = -1
jbe@532 2841 AND "opinion"."fulfilled" = FALSE
jbe@532 2842 ) AS "minus1_unfulfilled_count",
jbe@532 2843 ( SELECT coalesce(sum("di"."weight"), 0)
jbe@532 2844 FROM "opinion" JOIN "direct_interest_snapshot" AS "di"
jbe@532 2845 ON "di"."snapshot_id" = "snapshot_id_v"
jbe@532 2846 AND "di"."issue_id" = "issue_id_v"
jbe@532 2847 AND "di"."member_id" = "opinion"."member_id"
jbe@532 2848 WHERE "opinion"."suggestion_id" = "suggestion"."id"
jbe@532 2849 AND "opinion"."degree" = -1
jbe@532 2850 AND "opinion"."fulfilled" = TRUE
jbe@532 2851 ) AS "minus1_fulfilled_count",
jbe@532 2852 ( SELECT coalesce(sum("di"."weight"), 0)
jbe@532 2853 FROM "opinion" JOIN "direct_interest_snapshot" AS "di"
jbe@532 2854 ON "di"."snapshot_id" = "snapshot_id_v"
jbe@532 2855 AND "di"."issue_id" = "issue_id_v"
jbe@532 2856 AND "di"."member_id" = "opinion"."member_id"
jbe@532 2857 WHERE "opinion"."suggestion_id" = "suggestion"."id"
jbe@532 2858 AND "opinion"."degree" = 1
jbe@532 2859 AND "opinion"."fulfilled" = FALSE
jbe@532 2860 ) AS "plus1_unfulfilled_count",
jbe@532 2861 ( SELECT coalesce(sum("di"."weight"), 0)
jbe@532 2862 FROM "opinion" JOIN "direct_interest_snapshot" AS "di"
jbe@532 2863 ON "di"."snapshot_id" = "snapshot_id_v"
jbe@532 2864 AND "di"."issue_id" = "issue_id_v"
jbe@532 2865 AND "di"."member_id" = "opinion"."member_id"
jbe@532 2866 WHERE "opinion"."suggestion_id" = "suggestion"."id"
jbe@532 2867 AND "opinion"."degree" = 1
jbe@532 2868 AND "opinion"."fulfilled" = TRUE
jbe@532 2869 ) AS "plus1_fulfilled_count",
jbe@532 2870 ( SELECT coalesce(sum("di"."weight"), 0)
jbe@532 2871 FROM "opinion" JOIN "direct_interest_snapshot" AS "di"
jbe@532 2872 ON "di"."snapshot_id" = "snapshot_id_v"
jbe@532 2873 AND "di"."issue_id" = "issue_id_v"
jbe@532 2874 AND "di"."member_id" = "opinion"."member_id"
jbe@532 2875 WHERE "opinion"."suggestion_id" = "suggestion"."id"
jbe@532 2876 AND "opinion"."degree" = 2
jbe@532 2877 AND "opinion"."fulfilled" = FALSE
jbe@532 2878 ) AS "plus2_unfulfilled_count",
jbe@532 2879 ( SELECT coalesce(sum("di"."weight"), 0)
jbe@532 2880 FROM "opinion" JOIN "direct_interest_snapshot" AS "di"
jbe@532 2881 ON "di"."snapshot_id" = "snapshot_id_v"
jbe@532 2882 AND "di"."issue_id" = "issue_id_v"
jbe@532 2883 AND "di"."member_id" = "opinion"."member_id"
jbe@532 2884 WHERE "opinion"."suggestion_id" = "suggestion"."id"
jbe@532 2885 AND "opinion"."degree" = 2
jbe@532 2886 AND "opinion"."fulfilled" = TRUE
jbe@532 2887 ) AS "plus2_fulfilled_count"
jbe@532 2888 FROM "suggestion" JOIN "initiative"
jbe@532 2889 ON "suggestion"."initiative_id" = "initiative"."id"
jbe@532 2890 WHERE "initiative"."issue_id" = "issue_id_v";
jbe@532 2891 END LOOP;
jbe@532 2892 RETURN "snapshot_id_v";
jbe@532 2893 END;
jbe@532 2894 $$;
jbe@532 2895
jbe@532 2896 COMMENT ON FUNCTION "take_snapshot"
jbe@532 2897 ( "issue"."id"%TYPE,
jbe@532 2898 "area"."id"%TYPE )
jbe@532 2899 IS 'This function creates a new interest/supporter snapshot of a particular issue, or, if the first argument is NULL, for all issues in ''admission'' phase of the area given as second argument. It must be executed with TRANSACTION ISOLATION LEVEL REPEATABLE READ. The snapshot must later be finished by calling "finish_snapshot" for every issue.';
jbe@532 2900
jbe@532 2901
jbe@532 2902 DROP FUNCTION "set_snapshot_event"
jbe@532 2903 ( "issue_id_p" "issue"."id"%TYPE,
jbe@532 2904 "event_p" "snapshot_event" );
jbe@532 2905
jbe@532 2906
jbe@532 2907 CREATE FUNCTION "finish_snapshot"
jbe@532 2908 ( "issue_id_p" "issue"."id"%TYPE )
jbe@532 2909 RETURNS VOID
jbe@532 2910 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 2911 DECLARE
jbe@532 2912 "snapshot_id_v" "snapshot"."id"%TYPE;
jbe@532 2913 BEGIN
jbe@532 2914 -- NOTE: function does not require snapshot isolation but we don't call
jbe@532 2915 -- "dont_require_snapshot_isolation" here because this function is
jbe@532 2916 -- also invoked by "check_issue"
jbe@532 2917 LOCK TABLE "snapshot" IN EXCLUSIVE MODE;
jbe@532 2918 SELECT "id" INTO "snapshot_id_v" FROM "snapshot"
jbe@532 2919 ORDER BY "id" DESC LIMIT 1;
jbe@532 2920 UPDATE "issue" SET
jbe@532 2921 "calculated" = "snapshot"."calculated",
jbe@532 2922 "latest_snapshot_id" = "snapshot_id_v",
jbe@532 2923 "population" = "snapshot"."population"
jbe@532 2924 FROM "snapshot"
jbe@532 2925 WHERE "issue"."id" = "issue_id_p"
jbe@532 2926 AND "snapshot"."id" = "snapshot_id_v";
jbe@532 2927 UPDATE "initiative" SET
jbe@532 2928 "supporter_count" = (
jbe@532 2929 SELECT coalesce(sum("di"."weight"), 0)
jbe@532 2930 FROM "direct_interest_snapshot" AS "di"
jbe@532 2931 JOIN "direct_supporter_snapshot" AS "ds"
jbe@532 2932 ON "di"."member_id" = "ds"."member_id"
jbe@532 2933 WHERE "di"."snapshot_id" = "snapshot_id_v"
jbe@532 2934 AND "di"."issue_id" = "issue_id_p"
jbe@532 2935 AND "ds"."snapshot_id" = "snapshot_id_v"
jbe@532 2936 AND "ds"."initiative_id" = "initiative"."id"
jbe@532 2937 ),
jbe@532 2938 "informed_supporter_count" = (
jbe@532 2939 SELECT coalesce(sum("di"."weight"), 0)
jbe@532 2940 FROM "direct_interest_snapshot" AS "di"
jbe@532 2941 JOIN "direct_supporter_snapshot" AS "ds"
jbe@532 2942 ON "di"."member_id" = "ds"."member_id"
jbe@532 2943 WHERE "di"."snapshot_id" = "snapshot_id_v"
jbe@532 2944 AND "di"."issue_id" = "issue_id_p"
jbe@532 2945 AND "ds"."snapshot_id" = "snapshot_id_v"
jbe@532 2946 AND "ds"."initiative_id" = "initiative"."id"
jbe@532 2947 AND "ds"."informed"
jbe@532 2948 ),
jbe@532 2949 "satisfied_supporter_count" = (
jbe@532 2950 SELECT coalesce(sum("di"."weight"), 0)
jbe@532 2951 FROM "direct_interest_snapshot" AS "di"
jbe@532 2952 JOIN "direct_supporter_snapshot" AS "ds"
jbe@532 2953 ON "di"."member_id" = "ds"."member_id"
jbe@532 2954 WHERE "di"."snapshot_id" = "snapshot_id_v"
jbe@532 2955 AND "di"."issue_id" = "issue_id_p"
jbe@532 2956 AND "ds"."snapshot_id" = "snapshot_id_v"
jbe@532 2957 AND "ds"."initiative_id" = "initiative"."id"
jbe@532 2958 AND "ds"."satisfied"
jbe@532 2959 ),
jbe@532 2960 "satisfied_informed_supporter_count" = (
jbe@532 2961 SELECT coalesce(sum("di"."weight"), 0)
jbe@532 2962 FROM "direct_interest_snapshot" AS "di"
jbe@532 2963 JOIN "direct_supporter_snapshot" AS "ds"
jbe@532 2964 ON "di"."member_id" = "ds"."member_id"
jbe@532 2965 WHERE "di"."snapshot_id" = "snapshot_id_v"
jbe@532 2966 AND "di"."issue_id" = "issue_id_p"
jbe@532 2967 AND "ds"."snapshot_id" = "snapshot_id_v"
jbe@532 2968 AND "ds"."initiative_id" = "initiative"."id"
jbe@532 2969 AND "ds"."informed"
jbe@532 2970 AND "ds"."satisfied"
jbe@532 2971 )
jbe@532 2972 WHERE "issue_id" = "issue_id_p";
jbe@532 2973 UPDATE "suggestion" SET
jbe@532 2974 "minus2_unfulfilled_count" = "temp"."minus2_unfulfilled_count",
jbe@532 2975 "minus2_fulfilled_count" = "temp"."minus2_fulfilled_count",
jbe@532 2976 "minus1_unfulfilled_count" = "temp"."minus1_unfulfilled_count",
jbe@532 2977 "minus1_fulfilled_count" = "temp"."minus1_fulfilled_count",
jbe@532 2978 "plus1_unfulfilled_count" = "temp"."plus1_unfulfilled_count",
jbe@532 2979 "plus1_fulfilled_count" = "temp"."plus1_fulfilled_count",
jbe@532 2980 "plus2_unfulfilled_count" = "temp"."plus2_unfulfilled_count",
jbe@532 2981 "plus2_fulfilled_count" = "temp"."plus2_fulfilled_count"
jbe@532 2982 FROM "temporary_suggestion_counts" AS "temp", "initiative"
jbe@532 2983 WHERE "temp"."id" = "suggestion"."id"
jbe@532 2984 AND "initiative"."issue_id" = "issue_id_p"
jbe@532 2985 AND "suggestion"."initiative_id" = "initiative"."id";
jbe@532 2986 DELETE FROM "temporary_suggestion_counts";
jbe@532 2987 RETURN;
jbe@532 2988 END;
jbe@532 2989 $$;
jbe@532 2990
jbe@532 2991 COMMENT ON FUNCTION "finish_snapshot"
jbe@532 2992 ( "issue"."id"%TYPE )
jbe@532 2993 IS 'After calling "take_snapshot", this function "finish_snapshot" needs to be called for every issue in the snapshot (separate function calls keep locking time minimal)';
jbe@532 2994
jbe@532 2995
jbe@532 2996 CREATE FUNCTION "issue_admission"
jbe@532 2997 ( "area_id_p" "area"."id"%TYPE )
jbe@532 2998 RETURNS BOOLEAN
jbe@532 2999 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 3000 DECLARE
jbe@532 3001 "issue_id_v" "issue"."id"%TYPE;
jbe@532 3002 BEGIN
jbe@532 3003 PERFORM "dont_require_transaction_isolation"();
jbe@532 3004 LOCK TABLE "snapshot" IN EXCLUSIVE MODE;
jbe@532 3005 UPDATE "area" SET "issue_quorum" = "view"."issue_quorum"
jbe@532 3006 FROM "area_quorum" AS "view"
jbe@532 3007 WHERE "area"."id" = "view"."area_id"
jbe@532 3008 AND "area"."id" = "area_id_p";
jbe@532 3009 SELECT "id" INTO "issue_id_v" FROM "issue_for_admission"
jbe@532 3010 WHERE "area_id" = "area_id_p";
jbe@532 3011 IF "issue_id_v" ISNULL THEN RETURN FALSE; END IF;
jbe@532 3012 UPDATE "issue" SET
jbe@532 3013 "admission_snapshot_id" = "latest_snapshot_id",
jbe@532 3014 "state" = 'discussion',
jbe@532 3015 "accepted" = now(),
jbe@532 3016 "phase_finished" = NULL
jbe@532 3017 WHERE "id" = "issue_id_v";
jbe@532 3018 RETURN TRUE;
jbe@532 3019 END;
jbe@532 3020 $$;
jbe@532 3021
jbe@532 3022 COMMENT ON FUNCTION "issue_admission"
jbe@532 3023 ( "area"."id"%TYPE )
jbe@532 3024 IS 'Checks if an issue in the area can be admitted for further discussion; returns TRUE on success in which case the function must be called again until it returns FALSE';
jbe@532 3025
jbe@532 3026
jbe@532 3027 CREATE OR REPLACE FUNCTION "check_issue"
jbe@532 3028 ( "issue_id_p" "issue"."id"%TYPE,
jbe@532 3029 "persist" "check_issue_persistence" )
jbe@532 3030 RETURNS "check_issue_persistence"
jbe@532 3031 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 3032 DECLARE
jbe@532 3033 "issue_row" "issue"%ROWTYPE;
jbe@532 3034 "last_calculated_v" "snapshot"."calculated"%TYPE;
jbe@532 3035 "policy_row" "policy"%ROWTYPE;
jbe@532 3036 "initiative_row" "initiative"%ROWTYPE;
jbe@532 3037 "state_v" "issue_state";
jbe@532 3038 BEGIN
jbe@532 3039 PERFORM "require_transaction_isolation"();
jbe@532 3040 IF "persist" ISNULL THEN
jbe@532 3041 SELECT * INTO "issue_row" FROM "issue" WHERE "id" = "issue_id_p"
jbe@532 3042 FOR UPDATE;
jbe@532 3043 SELECT "calculated" INTO "last_calculated_v"
jbe@532 3044 FROM "snapshot" JOIN "snapshot_issue"
jbe@532 3045 ON "snapshot"."id" = "snapshot_issue"."snapshot_id"
jbe@532 3046 WHERE "snapshot_issue"."issue_id" = "issue_id_p";
jbe@532 3047 IF "issue_row"."closed" NOTNULL THEN
jbe@532 3048 RETURN NULL;
jbe@532 3049 END IF;
jbe@532 3050 "persist"."state" := "issue_row"."state";
jbe@532 3051 IF
jbe@532 3052 ( "issue_row"."state" = 'admission' AND "last_calculated_v" >=
jbe@532 3053 "issue_row"."created" + "issue_row"."max_admission_time" ) OR
jbe@532 3054 ( "issue_row"."state" = 'discussion' AND now() >=
jbe@532 3055 "issue_row"."accepted" + "issue_row"."discussion_time" ) OR
jbe@532 3056 ( "issue_row"."state" = 'verification' AND now() >=
jbe@532 3057 "issue_row"."half_frozen" + "issue_row"."verification_time" ) OR
jbe@532 3058 ( "issue_row"."state" = 'voting' AND now() >=
jbe@532 3059 "issue_row"."fully_frozen" + "issue_row"."voting_time" )
jbe@532 3060 THEN
jbe@532 3061 "persist"."phase_finished" := TRUE;
jbe@532 3062 ELSE
jbe@532 3063 "persist"."phase_finished" := FALSE;
jbe@532 3064 END IF;
jbe@532 3065 IF
jbe@532 3066 NOT EXISTS (
jbe@532 3067 -- all initiatives are revoked
jbe@532 3068 SELECT NULL FROM "initiative"
jbe@532 3069 WHERE "issue_id" = "issue_id_p" AND "revoked" ISNULL
jbe@532 3070 ) AND (
jbe@532 3071 -- and issue has not been accepted yet
jbe@532 3072 "persist"."state" = 'admission' OR
jbe@532 3073 -- or verification time has elapsed
jbe@532 3074 ( "persist"."state" = 'verification' AND
jbe@532 3075 "persist"."phase_finished" ) OR
jbe@532 3076 -- or no initiatives have been revoked lately
jbe@532 3077 NOT EXISTS (
jbe@532 3078 SELECT NULL FROM "initiative"
jbe@532 3079 WHERE "issue_id" = "issue_id_p"
jbe@532 3080 AND now() < "revoked" + "issue_row"."verification_time"
jbe@532 3081 )
jbe@532 3082 )
jbe@532 3083 THEN
jbe@532 3084 "persist"."issue_revoked" := TRUE;
jbe@532 3085 ELSE
jbe@532 3086 "persist"."issue_revoked" := FALSE;
jbe@532 3087 END IF;
jbe@532 3088 IF "persist"."phase_finished" OR "persist"."issue_revoked" THEN
jbe@532 3089 UPDATE "issue" SET "phase_finished" = now()
jbe@532 3090 WHERE "id" = "issue_row"."id";
jbe@532 3091 RETURN "persist";
jbe@532 3092 ELSIF
jbe@532 3093 "persist"."state" IN ('admission', 'discussion', 'verification')
jbe@532 3094 THEN
jbe@532 3095 RETURN "persist";
jbe@532 3096 ELSE
jbe@532 3097 RETURN NULL;
jbe@532 3098 END IF;
jbe@532 3099 END IF;
jbe@532 3100 IF
jbe@532 3101 "persist"."state" IN ('admission', 'discussion', 'verification') AND
jbe@532 3102 coalesce("persist"."snapshot_created", FALSE) = FALSE
jbe@532 3103 THEN
jbe@532 3104 IF "persist"."state" != 'admission' THEN
jbe@532 3105 PERFORM "take_snapshot"("issue_id_p");
jbe@532 3106 PERFORM "finish_snapshot"("issue_id_p");
jbe@532 3107 END IF;
jbe@532 3108 "persist"."snapshot_created" = TRUE;
jbe@532 3109 IF "persist"."phase_finished" THEN
jbe@532 3110 IF "persist"."state" = 'admission' THEN
jbe@561 3111 UPDATE "issue" SET "admission_snapshot_id" = "latest_snapshot_id"
jbe@561 3112 WHERE "id" = "issue_id_p";
jbe@532 3113 ELSIF "persist"."state" = 'discussion' THEN
jbe@561 3114 UPDATE "issue" SET "half_freeze_snapshot_id" = "latest_snapshot_id"
jbe@561 3115 WHERE "id" = "issue_id_p";
jbe@532 3116 ELSIF "persist"."state" = 'verification' THEN
jbe@561 3117 UPDATE "issue" SET "full_freeze_snapshot_id" = "latest_snapshot_id"
jbe@561 3118 WHERE "id" = "issue_id_p";
jbe@532 3119 SELECT * INTO "issue_row" FROM "issue" WHERE "id" = "issue_id_p";
jbe@532 3120 SELECT * INTO "policy_row" FROM "policy"
jbe@532 3121 WHERE "id" = "issue_row"."policy_id";
jbe@532 3122 FOR "initiative_row" IN
jbe@532 3123 SELECT * FROM "initiative"
jbe@532 3124 WHERE "issue_id" = "issue_id_p" AND "revoked" ISNULL
jbe@532 3125 FOR UPDATE
jbe@532 3126 LOOP
jbe@532 3127 IF
jbe@532 3128 "initiative_row"."polling" OR (
jbe@532 3129 "initiative_row"."satisfied_supporter_count" >
jbe@532 3130 "policy_row"."initiative_quorum" AND
jbe@532 3131 "initiative_row"."satisfied_supporter_count" *
jbe@532 3132 "policy_row"."initiative_quorum_den" >=
jbe@532 3133 "issue_row"."population" * "policy_row"."initiative_quorum_num"
jbe@532 3134 )
jbe@532 3135 THEN
jbe@532 3136 UPDATE "initiative" SET "admitted" = TRUE
jbe@532 3137 WHERE "id" = "initiative_row"."id";
jbe@532 3138 ELSE
jbe@532 3139 UPDATE "initiative" SET "admitted" = FALSE
jbe@532 3140 WHERE "id" = "initiative_row"."id";
jbe@532 3141 END IF;
jbe@532 3142 END LOOP;
jbe@532 3143 END IF;
jbe@532 3144 END IF;
jbe@532 3145 RETURN "persist";
jbe@532 3146 END IF;
jbe@532 3147 IF
jbe@532 3148 "persist"."state" IN ('admission', 'discussion', 'verification') AND
jbe@532 3149 coalesce("persist"."harmonic_weights_set", FALSE) = FALSE
jbe@532 3150 THEN
jbe@532 3151 PERFORM "set_harmonic_initiative_weights"("issue_id_p");
jbe@532 3152 "persist"."harmonic_weights_set" = TRUE;
jbe@532 3153 IF
jbe@532 3154 "persist"."phase_finished" OR
jbe@532 3155 "persist"."issue_revoked" OR
jbe@532 3156 "persist"."state" = 'admission'
jbe@532 3157 THEN
jbe@532 3158 RETURN "persist";
jbe@532 3159 ELSE
jbe@532 3160 RETURN NULL;
jbe@532 3161 END IF;
jbe@532 3162 END IF;
jbe@532 3163 IF "persist"."issue_revoked" THEN
jbe@532 3164 IF "persist"."state" = 'admission' THEN
jbe@532 3165 "state_v" := 'canceled_revoked_before_accepted';
jbe@532 3166 ELSIF "persist"."state" = 'discussion' THEN
jbe@532 3167 "state_v" := 'canceled_after_revocation_during_discussion';
jbe@532 3168 ELSIF "persist"."state" = 'verification' THEN
jbe@532 3169 "state_v" := 'canceled_after_revocation_during_verification';
jbe@532 3170 END IF;
jbe@532 3171 UPDATE "issue" SET
jbe@532 3172 "state" = "state_v",
jbe@532 3173 "closed" = "phase_finished",
jbe@532 3174 "phase_finished" = NULL
jbe@532 3175 WHERE "id" = "issue_id_p";
jbe@532 3176 RETURN NULL;
jbe@532 3177 END IF;
jbe@532 3178 IF "persist"."state" = 'admission' THEN
jbe@532 3179 SELECT * INTO "issue_row" FROM "issue" WHERE "id" = "issue_id_p"
jbe@532 3180 FOR UPDATE;
jbe@532 3181 IF "issue_row"."phase_finished" NOTNULL THEN
jbe@532 3182 UPDATE "issue" SET
jbe@532 3183 "state" = 'canceled_issue_not_accepted',
jbe@532 3184 "closed" = "phase_finished",
jbe@532 3185 "phase_finished" = NULL
jbe@532 3186 WHERE "id" = "issue_id_p";
jbe@532 3187 END IF;
jbe@532 3188 RETURN NULL;
jbe@532 3189 END IF;
jbe@532 3190 IF "persist"."phase_finished" THEN
jbe@532 3191 IF "persist"."state" = 'discussion' THEN
jbe@532 3192 UPDATE "issue" SET
jbe@532 3193 "state" = 'verification',
jbe@532 3194 "half_frozen" = "phase_finished",
jbe@532 3195 "phase_finished" = NULL
jbe@532 3196 WHERE "id" = "issue_id_p";
jbe@532 3197 RETURN NULL;
jbe@532 3198 END IF;
jbe@532 3199 IF "persist"."state" = 'verification' THEN
jbe@532 3200 SELECT * INTO "issue_row" FROM "issue" WHERE "id" = "issue_id_p"
jbe@532 3201 FOR UPDATE;
jbe@532 3202 SELECT * INTO "policy_row" FROM "policy"
jbe@532 3203 WHERE "id" = "issue_row"."policy_id";
jbe@532 3204 IF EXISTS (
jbe@532 3205 SELECT NULL FROM "initiative"
jbe@532 3206 WHERE "issue_id" = "issue_id_p" AND "admitted" = TRUE
jbe@532 3207 ) THEN
jbe@532 3208 UPDATE "issue" SET
jbe@532 3209 "state" = 'voting',
jbe@532 3210 "fully_frozen" = "phase_finished",
jbe@532 3211 "phase_finished" = NULL
jbe@532 3212 WHERE "id" = "issue_id_p";
jbe@532 3213 ELSE
jbe@532 3214 UPDATE "issue" SET
jbe@532 3215 "state" = 'canceled_no_initiative_admitted',
jbe@532 3216 "fully_frozen" = "phase_finished",
jbe@532 3217 "closed" = "phase_finished",
jbe@532 3218 "phase_finished" = NULL
jbe@532 3219 WHERE "id" = "issue_id_p";
jbe@532 3220 -- NOTE: The following DELETE statements have effect only when
jbe@532 3221 -- issue state has been manipulated
jbe@532 3222 DELETE FROM "direct_voter" WHERE "issue_id" = "issue_id_p";
jbe@532 3223 DELETE FROM "delegating_voter" WHERE "issue_id" = "issue_id_p";
jbe@532 3224 DELETE FROM "battle" WHERE "issue_id" = "issue_id_p";
jbe@532 3225 END IF;
jbe@532 3226 RETURN NULL;
jbe@532 3227 END IF;
jbe@532 3228 IF "persist"."state" = 'voting' THEN
jbe@532 3229 IF coalesce("persist"."closed_voting", FALSE) = FALSE THEN
jbe@532 3230 PERFORM "close_voting"("issue_id_p");
jbe@532 3231 "persist"."closed_voting" = TRUE;
jbe@532 3232 RETURN "persist";
jbe@532 3233 END IF;
jbe@532 3234 PERFORM "calculate_ranks"("issue_id_p");
jbe@532 3235 RETURN NULL;
jbe@532 3236 END IF;
jbe@532 3237 END IF;
jbe@532 3238 RAISE WARNING 'should not happen';
jbe@532 3239 RETURN NULL;
jbe@532 3240 END;
jbe@532 3241 $$;
jbe@532 3242
jbe@532 3243
jbe@532 3244 CREATE OR REPLACE FUNCTION "check_everything"()
jbe@532 3245 RETURNS VOID
jbe@532 3246 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 3247 DECLARE
jbe@532 3248 "area_id_v" "area"."id"%TYPE;
jbe@532 3249 "snapshot_id_v" "snapshot"."id"%TYPE;
jbe@532 3250 "issue_id_v" "issue"."id"%TYPE;
jbe@532 3251 "persist_v" "check_issue_persistence";
jbe@532 3252 BEGIN
jbe@532 3253 RAISE WARNING 'Function "check_everything" should only be used for development and debugging purposes';
jbe@532 3254 DELETE FROM "expired_session";
jbe@532 3255 DELETE FROM "expired_token";
jbe@532 3256 DELETE FROM "expired_snapshot";
jbe@532 3257 PERFORM "check_activity"();
jbe@532 3258 PERFORM "calculate_member_counts"();
jbe@532 3259 FOR "area_id_v" IN SELECT "id" FROM "area_with_unaccepted_issues" LOOP
jbe@532 3260 SELECT "take_snapshot"(NULL, "area_id_v") INTO "snapshot_id_v";
jbe@532 3261 PERFORM "finish_snapshot"("issue_id") FROM "snapshot_issue"
jbe@532 3262 WHERE "snapshot_id" = "snapshot_id_v";
jbe@532 3263 LOOP
jbe@532 3264 EXIT WHEN "issue_admission"("area_id_v") = FALSE;
jbe@532 3265 END LOOP;
jbe@532 3266 END LOOP;
jbe@532 3267 FOR "issue_id_v" IN SELECT "id" FROM "open_issue" LOOP
jbe@532 3268 "persist_v" := NULL;
jbe@532 3269 LOOP
jbe@532 3270 "persist_v" := "check_issue"("issue_id_v", "persist_v");
jbe@532 3271 EXIT WHEN "persist_v" ISNULL;
jbe@532 3272 END LOOP;
jbe@532 3273 END LOOP;
jbe@532 3274 RETURN;
jbe@532 3275 END;
jbe@532 3276 $$;
jbe@532 3277
jbe@532 3278 COMMENT ON FUNCTION "check_everything"() IS 'Amongst other regular tasks, this function performs "check_issue" for every open issue. Use this function only for development and debugging purposes, as you may run into locking and/or serialization problems in productive environments. For production, use lf_update binary instead';
jbe@532 3279
jbe@532 3280
jbe@532 3281 CREATE OR REPLACE FUNCTION "clean_issue"("issue_id_p" "issue"."id"%TYPE)
jbe@532 3282 RETURNS VOID
jbe@532 3283 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 3284 BEGIN
jbe@532 3285 IF EXISTS (
jbe@532 3286 SELECT NULL FROM "issue" WHERE "id" = "issue_id_p" AND "cleaned" ISNULL
jbe@532 3287 ) THEN
jbe@532 3288 -- override protection triggers:
jbe@532 3289 INSERT INTO "temporary_transaction_data" ("key", "value")
jbe@532 3290 VALUES ('override_protection_triggers', TRUE::TEXT);
jbe@532 3291 -- clean data:
jbe@532 3292 DELETE FROM "delegating_voter"
jbe@532 3293 WHERE "issue_id" = "issue_id_p";
jbe@532 3294 DELETE FROM "direct_voter"
jbe@532 3295 WHERE "issue_id" = "issue_id_p";
jbe@532 3296 DELETE FROM "delegating_interest_snapshot"
jbe@532 3297 WHERE "issue_id" = "issue_id_p";
jbe@532 3298 DELETE FROM "direct_interest_snapshot"
jbe@532 3299 WHERE "issue_id" = "issue_id_p";
jbe@532 3300 DELETE FROM "non_voter"
jbe@532 3301 WHERE "issue_id" = "issue_id_p";
jbe@532 3302 DELETE FROM "delegation"
jbe@532 3303 WHERE "issue_id" = "issue_id_p";
jbe@532 3304 DELETE FROM "supporter"
jbe@532 3305 USING "initiative" -- NOTE: due to missing index on issue_id
jbe@532 3306 WHERE "initiative"."issue_id" = "issue_id_p"
jbe@532 3307 AND "supporter"."initiative_id" = "initiative_id";
jbe@532 3308 -- mark issue as cleaned:
jbe@532 3309 UPDATE "issue" SET "cleaned" = now() WHERE "id" = "issue_id_p";
jbe@532 3310 -- finish overriding protection triggers (avoids garbage):
jbe@532 3311 DELETE FROM "temporary_transaction_data"
jbe@532 3312 WHERE "key" = 'override_protection_triggers';
jbe@532 3313 END IF;
jbe@532 3314 RETURN;
jbe@532 3315 END;
jbe@532 3316 $$;
jbe@532 3317
jbe@532 3318
jbe@532 3319 CREATE OR REPLACE FUNCTION "delete_member"("member_id_p" "member"."id"%TYPE)
jbe@532 3320 RETURNS VOID
jbe@532 3321 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 3322 BEGIN
jbe@532 3323 UPDATE "member" SET
jbe@532 3324 "last_login" = NULL,
jbe@532 3325 "last_delegation_check" = NULL,
jbe@532 3326 "login" = NULL,
jbe@532 3327 "password" = NULL,
jbe@532 3328 "authority" = NULL,
jbe@532 3329 "authority_uid" = NULL,
jbe@532 3330 "authority_login" = NULL,
jbe@552 3331 "deleted" = coalesce("deleted", now()),
jbe@532 3332 "locked" = TRUE,
jbe@532 3333 "active" = FALSE,
jbe@532 3334 "notify_email" = NULL,
jbe@532 3335 "notify_email_unconfirmed" = NULL,
jbe@532 3336 "notify_email_secret" = NULL,
jbe@532 3337 "notify_email_secret_expiry" = NULL,
jbe@532 3338 "notify_email_lock_expiry" = NULL,
jbe@532 3339 "disable_notifications" = TRUE,
jbe@532 3340 "notification_counter" = DEFAULT,
jbe@532 3341 "notification_sample_size" = 0,
jbe@532 3342 "notification_dow" = NULL,
jbe@532 3343 "notification_hour" = NULL,
jbe@543 3344 "notification_sent" = NULL,
jbe@532 3345 "login_recovery_expiry" = NULL,
jbe@532 3346 "password_reset_secret" = NULL,
jbe@532 3347 "password_reset_secret_expiry" = NULL,
jbe@532 3348 "location" = NULL
jbe@532 3349 WHERE "id" = "member_id_p";
jbe@532 3350 -- "text_search_data" is updated by triggers
jbe@544 3351 DELETE FROM "member_settings" WHERE "member_id" = "member_id_p";
jbe@543 3352 DELETE FROM "member_profile" WHERE "member_id" = "member_id_p";
jbe@543 3353 DELETE FROM "rendered_member_statement" WHERE "member_id" = "member_id_p";
jbe@532 3354 DELETE FROM "member_image" WHERE "member_id" = "member_id_p";
jbe@532 3355 DELETE FROM "contact" WHERE "member_id" = "member_id_p";
jbe@532 3356 DELETE FROM "ignored_member" WHERE "member_id" = "member_id_p";
jbe@532 3357 DELETE FROM "session" WHERE "member_id" = "member_id_p";
jbe@543 3358 DELETE FROM "member_application" WHERE "member_id" = "member_id_p";
jbe@543 3359 DELETE FROM "token" WHERE "member_id" = "member_id_p";
jbe@543 3360 DELETE FROM "subscription" WHERE "member_id" = "member_id_p";
jbe@543 3361 DELETE FROM "ignored_area" WHERE "member_id" = "member_id_p";
jbe@532 3362 DELETE FROM "ignored_initiative" WHERE "member_id" = "member_id_p";
jbe@532 3363 DELETE FROM "delegation" WHERE "truster_id" = "member_id_p";
jbe@532 3364 DELETE FROM "non_voter" WHERE "member_id" = "member_id_p";
jbe@532 3365 DELETE FROM "direct_voter" USING "issue"
jbe@532 3366 WHERE "direct_voter"."issue_id" = "issue"."id"
jbe@532 3367 AND "issue"."closed" ISNULL
jbe@532 3368 AND "member_id" = "member_id_p";
jbe@543 3369 DELETE FROM "notification_initiative_sent" WHERE "member_id" = "member_id_p";
jbe@532 3370 RETURN;
jbe@532 3371 END;
jbe@532 3372 $$;
jbe@532 3373
jbe@532 3374
jbe@532 3375 CREATE OR REPLACE FUNCTION "delete_private_data"()
jbe@532 3376 RETURNS VOID
jbe@532 3377 LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@532 3378 BEGIN
jbe@532 3379 DELETE FROM "temporary_transaction_data";
jbe@543 3380 DELETE FROM "temporary_suggestion_counts";
jbe@532 3381 DELETE FROM "member" WHERE "activated" ISNULL;
jbe@532 3382 UPDATE "member" SET
jbe@532 3383 "invite_code" = NULL,
jbe@532 3384 "invite_code_expiry" = NULL,
jbe@532 3385 "admin_comment" = NULL,
jbe@532 3386 "last_login" = NULL,
jbe@532 3387 "last_delegation_check" = NULL,
jbe@532 3388 "login" = NULL,
jbe@532 3389 "password" = NULL,
jbe@532 3390 "authority" = NULL,
jbe@532 3391 "authority_uid" = NULL,
jbe@532 3392 "authority_login" = NULL,
jbe@532 3393 "lang" = NULL,
jbe@532 3394 "notify_email" = NULL,
jbe@532 3395 "notify_email_unconfirmed" = NULL,
jbe@532 3396 "notify_email_secret" = NULL,
jbe@532 3397 "notify_email_secret_expiry" = NULL,
jbe@532 3398 "notify_email_lock_expiry" = NULL,
jbe@532 3399 "disable_notifications" = TRUE,
jbe@532 3400 "notification_counter" = DEFAULT,
jbe@532 3401 "notification_sample_size" = 0,
jbe@532 3402 "notification_dow" = NULL,
jbe@532 3403 "notification_hour" = NULL,
jbe@543 3404 "notification_sent" = NULL,
jbe@532 3405 "login_recovery_expiry" = NULL,
jbe@532 3406 "password_reset_secret" = NULL,
jbe@532 3407 "password_reset_secret_expiry" = NULL,
jbe@532 3408 "location" = NULL;
jbe@532 3409 -- "text_search_data" is updated by triggers
jbe@557 3410 DELETE FROM "verification";
jbe@544 3411 DELETE FROM "member_settings";
jbe@544 3412 DELETE FROM "member_useterms";
jbe@543 3413 DELETE FROM "member_profile";
jbe@543 3414 DELETE FROM "rendered_member_statement";
jbe@532 3415 DELETE FROM "member_image";
jbe@532 3416 DELETE FROM "contact";
jbe@532 3417 DELETE FROM "ignored_member";
jbe@532 3418 DELETE FROM "session";
jbe@543 3419 DELETE FROM "system_application";
jbe@543 3420 DELETE FROM "system_application_redirect_uri";
jbe@543 3421 DELETE FROM "dynamic_application_scope";
jbe@543 3422 DELETE FROM "member_application";
jbe@543 3423 DELETE FROM "token";
jbe@543 3424 DELETE FROM "subscription";
jbe@543 3425 DELETE FROM "ignored_area";
jbe@532 3426 DELETE FROM "ignored_initiative";
jbe@532 3427 DELETE FROM "non_voter";
jbe@532 3428 DELETE FROM "direct_voter" USING "issue"
jbe@532 3429 WHERE "direct_voter"."issue_id" = "issue"."id"
jbe@532 3430 AND "issue"."closed" ISNULL;
jbe@543 3431 DELETE FROM "event_processed";
jbe@543 3432 DELETE FROM "notification_initiative_sent";
jbe@543 3433 DELETE FROM "newsletter";
jbe@532 3434 RETURN;
jbe@532 3435 END;
jbe@532 3436 $$;
jbe@532 3437
jbe@532 3438
jbe@532 3439 CREATE TEMPORARY TABLE "old_snapshot" AS
jbe@532 3440 SELECT "ordered".*, row_number() OVER () AS "snapshot_id"
jbe@532 3441 FROM (
jbe@532 3442 SELECT * FROM (
jbe@532 3443 SELECT
jbe@532 3444 "id" AS "issue_id",
jbe@532 3445 'end_of_admission'::"snapshot_event" AS "event",
jbe@532 3446 "accepted" AS "calculated"
jbe@532 3447 FROM "issue" WHERE "accepted" NOTNULL
jbe@532 3448 UNION ALL
jbe@532 3449 SELECT
jbe@532 3450 "id" AS "issue_id",
jbe@532 3451 'half_freeze'::"snapshot_event" AS "event",
jbe@532 3452 "half_frozen" AS "calculated"
jbe@532 3453 FROM "issue" WHERE "half_frozen" NOTNULL
jbe@532 3454 UNION ALL
jbe@532 3455 SELECT
jbe@532 3456 "id" AS "issue_id",
jbe@532 3457 'full_freeze'::"snapshot_event" AS "event",
jbe@532 3458 "fully_frozen" AS "calculated"
jbe@532 3459 FROM "issue" WHERE "fully_frozen" NOTNULL
jbe@532 3460 ) AS "unordered"
jbe@532 3461 ORDER BY "calculated", "issue_id", "event"
jbe@532 3462 ) AS "ordered";
jbe@532 3463
jbe@532 3464
jbe@532 3465 INSERT INTO "snapshot" ("id", "calculated", "population", "area_id", "issue_id")
jbe@532 3466 SELECT
jbe@532 3467 "old_snapshot"."snapshot_id" AS "id",
jbe@532 3468 "old_snapshot"."calculated",
jbe@532 3469 ( SELECT COALESCE(sum("weight"), 0)
jbe@532 3470 FROM "direct_population_snapshot" "dps"
jbe@532 3471 WHERE "dps"."issue_id" = "old_snapshot"."issue_id"
jbe@532 3472 AND "dps"."event" = "old_snapshot"."event"
jbe@532 3473 ) AS "population",
jbe@532 3474 "issue"."area_id" AS "area_id",
jbe@532 3475 "issue"."id" AS "issue_id"
jbe@532 3476 FROM "old_snapshot" JOIN "issue"
jbe@532 3477 ON "old_snapshot"."issue_id" = "issue"."id";
jbe@532 3478
jbe@532 3479
jbe@532 3480 INSERT INTO "snapshot_issue" ("snapshot_id", "issue_id")
jbe@532 3481 SELECT "id" AS "snapshot_id", "issue_id" FROM "snapshot";
jbe@532 3482
jbe@532 3483
jbe@532 3484 INSERT INTO "snapshot_population" ("snapshot_id", "member_id")
jbe@532 3485 SELECT
jbe@532 3486 "old_snapshot"."snapshot_id",
jbe@532 3487 "direct_population_snapshot"."member_id"
jbe@532 3488 FROM "old_snapshot" JOIN "direct_population_snapshot"
jbe@532 3489 ON "old_snapshot"."issue_id" = "direct_population_snapshot"."issue_id"
jbe@532 3490 AND "old_snapshot"."event" = "direct_population_snapshot"."event";
jbe@532 3491
jbe@532 3492 INSERT INTO "snapshot_population" ("snapshot_id", "member_id")
jbe@532 3493 SELECT
jbe@532 3494 "old_snapshot"."snapshot_id",
jbe@532 3495 "delegating_population_snapshot"."member_id"
jbe@532 3496 FROM "old_snapshot" JOIN "delegating_population_snapshot"
jbe@532 3497 ON "old_snapshot"."issue_id" = "delegating_population_snapshot"."issue_id"
jbe@532 3498 AND "old_snapshot"."event" = "delegating_population_snapshot"."event";
jbe@532 3499
jbe@532 3500
jbe@532 3501 INSERT INTO "direct_interest_snapshot"
jbe@532 3502 ("snapshot_id", "issue_id", "member_id", "weight")
jbe@532 3503 SELECT
jbe@532 3504 "old_snapshot"."snapshot_id",
jbe@532 3505 "old_snapshot"."issue_id",
jbe@532 3506 "direct_interest_snapshot_old"."member_id",
jbe@532 3507 "direct_interest_snapshot_old"."weight"
jbe@532 3508 FROM "old_snapshot" JOIN "direct_interest_snapshot_old"
jbe@532 3509 ON "old_snapshot"."issue_id" = "direct_interest_snapshot_old"."issue_id"
jbe@532 3510 AND "old_snapshot"."event" = "direct_interest_snapshot_old"."event";
jbe@532 3511
jbe@532 3512 INSERT INTO "delegating_interest_snapshot"
jbe@532 3513 ( "snapshot_id", "issue_id",
jbe@532 3514 "member_id", "weight", "scope", "delegate_member_ids" )
jbe@532 3515 SELECT
jbe@532 3516 "old_snapshot"."snapshot_id",
jbe@532 3517 "old_snapshot"."issue_id",
jbe@532 3518 "delegating_interest_snapshot_old"."member_id",
jbe@532 3519 "delegating_interest_snapshot_old"."weight",
jbe@532 3520 "delegating_interest_snapshot_old"."scope",
jbe@532 3521 "delegating_interest_snapshot_old"."delegate_member_ids"
jbe@532 3522 FROM "old_snapshot" JOIN "delegating_interest_snapshot_old"
jbe@532 3523 ON "old_snapshot"."issue_id" = "delegating_interest_snapshot_old"."issue_id"
jbe@532 3524 AND "old_snapshot"."event" = "delegating_interest_snapshot_old"."event";
jbe@532 3525
jbe@532 3526 INSERT INTO "direct_supporter_snapshot"
jbe@532 3527 ( "snapshot_id", "issue_id",
jbe@532 3528 "initiative_id", "member_id", "draft_id", "informed", "satisfied" )
jbe@532 3529 SELECT
jbe@532 3530 "old_snapshot"."snapshot_id",
jbe@532 3531 "old_snapshot"."issue_id",
jbe@532 3532 "direct_supporter_snapshot_old"."initiative_id",
jbe@532 3533 "direct_supporter_snapshot_old"."member_id",
jbe@532 3534 "direct_supporter_snapshot_old"."draft_id",
jbe@532 3535 "direct_supporter_snapshot_old"."informed",
jbe@532 3536 "direct_supporter_snapshot_old"."satisfied"
jbe@532 3537 FROM "old_snapshot" JOIN "direct_supporter_snapshot_old"
jbe@532 3538 ON "old_snapshot"."issue_id" = "direct_supporter_snapshot_old"."issue_id"
jbe@532 3539 AND "old_snapshot"."event" = "direct_supporter_snapshot_old"."event";
jbe@532 3540
jbe@532 3541
jbe@532 3542 ALTER TABLE "issue" DISABLE TRIGGER USER; -- NOTE: required to modify table later
jbe@532 3543
jbe@532 3544 UPDATE "issue" SET "latest_snapshot_id" = "snapshot"."id"
jbe@532 3545 FROM (
jbe@532 3546 SELECT DISTINCT ON ("issue_id") "issue_id", "id"
jbe@532 3547 FROM "snapshot" ORDER BY "issue_id", "id" DESC
jbe@532 3548 ) AS "snapshot"
jbe@532 3549 WHERE "snapshot"."issue_id" = "issue"."id";
jbe@532 3550
jbe@532 3551 UPDATE "issue" SET "admission_snapshot_id" = "old_snapshot"."snapshot_id"
jbe@532 3552 FROM "old_snapshot"
jbe@532 3553 WHERE "old_snapshot"."issue_id" = "issue"."id"
jbe@532 3554 AND "old_snapshot"."event" = 'end_of_admission';
jbe@532 3555
jbe@532 3556 UPDATE "issue" SET "half_freeze_snapshot_id" = "old_snapshot"."snapshot_id"
jbe@532 3557 FROM "old_snapshot"
jbe@532 3558 WHERE "old_snapshot"."issue_id" = "issue"."id"
jbe@532 3559 AND "old_snapshot"."event" = 'half_freeze';
jbe@532 3560
jbe@532 3561 UPDATE "issue" SET "full_freeze_snapshot_id" = "old_snapshot"."snapshot_id"
jbe@532 3562 FROM "old_snapshot"
jbe@532 3563 WHERE "old_snapshot"."issue_id" = "issue"."id"
jbe@532 3564 AND "old_snapshot"."event" = 'full_freeze';
jbe@532 3565
jbe@532 3566 ALTER TABLE "issue" ENABLE TRIGGER USER;
jbe@532 3567
jbe@532 3568
jbe@532 3569 DROP TABLE "old_snapshot";
jbe@532 3570
jbe@532 3571 DROP TABLE "direct_supporter_snapshot_old";
jbe@532 3572 DROP TABLE "delegating_interest_snapshot_old";
jbe@532 3573 DROP TABLE "direct_interest_snapshot_old";
jbe@532 3574 DROP TABLE "delegating_population_snapshot";
jbe@532 3575 DROP TABLE "direct_population_snapshot";
jbe@532 3576
jbe@532 3577
jbe@532 3578 DROP VIEW "open_issue";
jbe@532 3579
jbe@532 3580
jbe@532 3581 ALTER TABLE "issue" DROP COLUMN "latest_snapshot_event";
jbe@532 3582
jbe@532 3583
jbe@532 3584 CREATE VIEW "open_issue" AS
jbe@532 3585 SELECT * FROM "issue" WHERE "closed" ISNULL;
jbe@532 3586
jbe@532 3587 COMMENT ON VIEW "open_issue" IS 'All open issues';
jbe@532 3588
jbe@532 3589
jbe@532 3590 -- NOTE: create "issue_for_admission" view after altering table "issue"
jbe@532 3591 CREATE VIEW "issue_for_admission" AS
jbe@532 3592 SELECT DISTINCT ON ("issue"."area_id")
jbe@532 3593 "issue".*,
jbe@532 3594 max("initiative"."supporter_count") AS "max_supporter_count"
jbe@532 3595 FROM "issue"
jbe@532 3596 JOIN "policy" ON "issue"."policy_id" = "policy"."id"
jbe@532 3597 JOIN "initiative" ON "issue"."id" = "initiative"."issue_id"
jbe@532 3598 JOIN "area" ON "issue"."area_id" = "area"."id"
jbe@532 3599 WHERE "issue"."state" = 'admission'::"issue_state"
jbe@532 3600 AND now() >= "issue"."created" + "issue"."min_admission_time"
jbe@532 3601 AND "initiative"."supporter_count" >= "policy"."issue_quorum"
jbe@532 3602 AND "initiative"."supporter_count" * "policy"."issue_quorum_den" >=
jbe@532 3603 "issue"."population" * "policy"."issue_quorum_num"
jbe@532 3604 AND "initiative"."supporter_count" >= "area"."issue_quorum"
jbe@532 3605 AND "initiative"."revoked" ISNULL
jbe@532 3606 GROUP BY "issue"."id"
jbe@532 3607 ORDER BY "issue"."area_id", "max_supporter_count" DESC, "issue"."id";
jbe@532 3608
jbe@532 3609 COMMENT ON VIEW "issue_for_admission" IS 'Contains up to 1 issue per area eligible to pass from ''admission'' to ''discussion'' state; needs to be recalculated after admitting the issue in this view';
jbe@532 3610
jbe@532 3611
jbe@532 3612 DROP TYPE "snapshot_event";
jbe@532 3613
jbe@532 3614
jbe@532 3615 ALTER TABLE "issue" ADD CONSTRAINT "snapshot_required" CHECK (
jbe@532 3616 ("half_frozen" ISNULL OR "half_freeze_snapshot_id" NOTNULL) AND
jbe@532 3617 ("fully_frozen" ISNULL OR "full_freeze_snapshot_id" NOTNULL) );
jbe@532 3618
jbe@532 3619
jbe@532 3620 COMMIT;

Impressum / About Us