| | 202 | |
| | 203 | == Triggers |
| | 204 | ==== Automatically updates the story timestamp on every update |
| | 205 | {{{ |
| | 206 | CREATE OR REPLACE FUNCTION update_timestamp() |
| | 207 | RETURNS TRIGGER |
| | 208 | LANGUAGE plpgsql |
| | 209 | AS $$ |
| | 210 | BEGIN |
| | 211 | NEW.story_updated_at := CURRENT_TIMESTAMP; |
| | 212 | RETURN NEW; |
| | 213 | END; |
| | 214 | $$; |
| | 215 | |
| | 216 | CREATE OR REPLACE TRIGGER story_update_timestamp |
| | 217 | BEFORE UPDATE ON story |
| | 218 | FOR EACH ROW |
| | 219 | EXECUTE FUNCTION update_timestamp(); |
| | 220 | }}} |
| | 221 | ==== Sends a notification to the writer when someone likes their story |
| | 222 | {{{ |
| | 223 | CREATE OR REPLACE FUNCTION notify_writer_on_like() |
| | 224 | RETURNS TRIGGER |
| | 225 | LANGUAGE plpgsql |
| | 226 | AS $$ |
| | 227 | DECLARE |
| | 228 | v_writer_id INTEGER; |
| | 229 | v_liker_username VARCHAR; |
| | 230 | v_story_desc VARCHAR; |
| | 231 | BEGIN |
| | 232 | SELECT s.user_id, s.short_description |
| | 233 | INTO v_writer_id, v_story_desc |
| | 234 | FROM story s |
| | 235 | WHERE s.story_id = NEW.story_id; |
| | 236 | |
| | 237 | SELECT username INTO v_liker_username |
| | 238 | FROM users |
| | 239 | WHERE user_id = NEW.user_id; |
| | 240 | |
| | 241 | -- Do not notify if the writer likes their own story |
| | 242 | IF v_writer_id != NEW.user_id THEN |
| | 243 | INSERT INTO notification ( |
| | 244 | notification_content, |
| | 245 | is_read, |
| | 246 | recipient_user_id, |
| | 247 | type, |
| | 248 | link, |
| | 249 | notification_created_at |
| | 250 | ) |
| | 251 | VALUES ( |
| | 252 | v_liker_username || ' liked your story "' || v_story_desc || '"', |
| | 253 | FALSE, |
| | 254 | v_writer_id, |
| | 255 | 'like', |
| | 256 | '/story/' || NEW.story_id::VARCHAR, |
| | 257 | CURRENT_TIMESTAMP |
| | 258 | ); |
| | 259 | END IF; |
| | 260 | |
| | 261 | RETURN NEW; |
| | 262 | END; |
| | 263 | $$; |
| | 264 | |
| | 265 | CREATE OR REPLACE TRIGGER on_story_liked |
| | 266 | AFTER INSERT ON likes |
| | 267 | FOR EACH ROW |
| | 268 | EXECUTE FUNCTION notify_writer_on_like(); |
| | 269 | }}} |
| | 270 | |
| | 271 | ==== Prevents adding a story to a reading list if it is not published |
| | 272 | {{{ |
| | 273 | CREATE OR REPLACE FUNCTION check_story_published_before_adding() |
| | 274 | RETURNS TRIGGER |
| | 275 | LANGUAGE plpgsql |
| | 276 | AS $$ |
| | 277 | BEGIN |
| | 278 | IF NOT EXISTS ( |
| | 279 | SELECT 1 FROM "status" |
| | 280 | WHERE story_id = NEW.story_id |
| | 281 | AND status = 'published' |
| | 282 | ) THEN |
| | 283 | RAISE EXCEPTION |
| | 284 | 'story_id=% is not published and cannot be added to a reading list.', |
| | 285 | NEW.story_id; |
| | 286 | END IF; |
| | 287 | RETURN NEW; |
| | 288 | END; |
| | 289 | $$; |
| | 290 | |
| | 291 | CREATE OR REPLACE TRIGGER enforce_published_before_list_add |
| | 292 | BEFORE INSERT ON reading_list_items |
| | 293 | FOR EACH ROW |
| | 294 | EXECUTE FUNCTION check_story_published_before_adding(); |
| | 295 | }}} |
| | 296 | ==== Trigger: prevents a writer from collaborating on their own story |
| | 297 | {{{ |
| | 298 | CREATE OR REPLACE FUNCTION check_not_own_story() |
| | 299 | RETURNS TRIGGER |
| | 300 | LANGUAGE plpgsql |
| | 301 | AS $$ |
| | 302 | BEGIN |
| | 303 | IF EXISTS ( |
| | 304 | SELECT 1 FROM story |
| | 305 | WHERE story_id = NEW.story_id |
| | 306 | AND user_id = NEW.user_id |
| | 307 | ) THEN |
| | 308 | RAISE EXCEPTION |
| | 309 | 'user_id=% is the owner of story_id=% and cannot be a collaborator.', |
| | 310 | NEW.user_id, |
| | 311 | NEW.story_id; |
| | 312 | END IF; |
| | 313 | RETURN NEW; |
| | 314 | END; |
| | 315 | $$; |
| | 316 | |
| | 317 | CREATE OR REPLACE TRIGGER prevent_self_collaboration |
| | 318 | BEFORE INSERT ON collaboration |
| | 319 | FOR EACH ROW |
| | 320 | EXECUTE FUNCTION check_not_own_story(); |
| | 321 | }}} |