liquid_feedback_core

annotate update/core-update.v3.2.2-v4.0.0.sql @ 532:5855ff9e5c8f

Several changes/additions for upcoming major release

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

Impressum / About Us