liquid_feedback_core

annotate update/core-update.v3.2.2-v4.0.0.sql @ 554:3e7ad7233404

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

Impressum / About Us