| | 226 | |
| | 227 | === 3.Detailed report on percentage change in collaborator count and invitation validation for a story |
| | 228 | === SQL |
| | 229 | {{{ |
| | 230 | WITH |
| | 231 | owned_story AS ( |
| | 232 | SELECT s.story_id, s.short_description |
| | 233 | FROM story s |
| | 234 | JOIN writer w ON s.user_id = w.user_id |
| | 235 | WHERE s.story_id = 5 |
| | 236 | AND s.user_id = :owner_user_id |
| | 237 | ), |
| | 238 | invited_writer AS ( |
| | 239 | SELECT u.user_id, u.username, u.user_name, u.surname |
| | 240 | FROM users u |
| | 241 | JOIN writer w ON u.user_id = w.user_id |
| | 242 | WHERE u.username = :invited_username |
| | 243 | ), |
| | 244 | already_collaborating AS ( |
| | 245 | SELECT 1 |
| | 246 | FROM collaboration |
| | 247 | WHERE user_id = (SELECT user_id FROM invited_writer) |
| | 248 | AND story_id = (SELECT story_id FROM owned_story) |
| | 249 | ), |
| | 250 | current_collaborators AS ( |
| | 251 | SELECT |
| | 252 | u.username, |
| | 253 | u.user_name, |
| | 254 | u.surname, |
| | 255 | r.roles, |
| | 256 | p.permission_level, |
| | 257 | c.collab_created_at |
| | 258 | FROM collaboration c |
| | 259 | JOIN users u ON c.user_id = u.user_id |
| | 260 | JOIN roles r ON c.user_id = r.user_id AND c.story_id = r.story_id |
| | 261 | JOIN permission_level p ON c.user_id = p.user_id AND c.story_id = p.story_id |
| | 262 | WHERE c.story_id = (SELECT story_id FROM owned_story) |
| | 263 | ), |
| | 264 | notification_preview AS ( |
| | 265 | SELECT |
| | 266 | iw.user_id AS recipient_user_id, |
| | 267 | iw.username AS recipient_username, |
| | 268 | 'You have been invited to collaborate on "' |
| | 269 | || os.short_description || '"' AS notification_content, |
| | 270 | 'collaboration' AS type, |
| | 271 | '/story/' || os.story_id::VARCHAR AS link |
| | 272 | FROM invited_writer iw |
| | 273 | CROSS JOIN owned_story os |
| | 274 | ) |
| | 275 | SELECT |
| | 276 | cc.username, |
| | 277 | cc.user_name, |
| | 278 | cc.surname, |
| | 279 | cc.roles, |
| | 280 | cc.permission_level, |
| | 281 | cc.collab_created_at, |
| | 282 | COUNT(*) OVER () AS total_collaborators, |
| | 283 | np.notification_content AS pending_notification, |
| | 284 | CASE |
| | 285 | WHEN NOT EXISTS (SELECT 1 FROM owned_story) THEN 'Failed: story not found or not owned by you' |
| | 286 | WHEN NOT EXISTS (SELECT 1 FROM invited_writer) THEN 'Failed: invited user is not a writer' |
| | 287 | WHEN EXISTS (SELECT 1 FROM already_collaborating) THEN 'User is already a collaborator' |
| | 288 | ELSE 'Ready to add collaborator' |
| | 289 | END AS status |
| | 290 | FROM current_collaborators cc |
| | 291 | LEFT JOIN notification_preview np ON np.recipient_username = :invited_username |
| | 292 | ORDER BY cc.collab_created_at; |
| | 293 | }}} |
| | 294 | === Relational Algebra |
| | 295 | {{{ |
| | 296 | OwnedStory ← |
| | 297 | π story_id, short_description |
| | 298 | ( |
| | 299 | σ s.story_id = :story_id ∧ s.user_id = :owner_user_id |
| | 300 | ( |
| | 301 | story s |
| | 302 | ⨝ (s.user_id = w.user_id) writer w |
| | 303 | ) |
| | 304 | ) |
| | 305 | |
| | 306 | InvitedWriter ← |
| | 307 | π user_id, username, user_name, surname |
| | 308 | ( |
| | 309 | σ u.username = :invited_username |
| | 310 | ( |
| | 311 | users u |
| | 312 | ⨝ (u.user_id = w.user_id) writer w |
| | 313 | ) |
| | 314 | ) |
| | 315 | |
| | 316 | AlreadyCollaborating ← |
| | 317 | σ user_id = (π user_id (InvitedWriter)) |
| | 318 | ∧ story_id = (π story_id (OwnedStory)) |
| | 319 | ( |
| | 320 | collaboration |
| | 321 | ) |
| | 322 | |
| | 323 | CurrentCollaborators ← |
| | 324 | π |
| | 325 | u.username, u.user_name, u.surname, |
| | 326 | r.roles, p.permission_level, |
| | 327 | c.collab_created_at |
| | 328 | ( |
| | 329 | ( |
| | 330 | ( |
| | 331 | σ story_id = (π story_id (OwnedStory)) (collaboration c) |
| | 332 | ⨝ (c.user_id = u.user_id) users u |
| | 333 | ) |
| | 334 | ⨝ (c.user_id = r.user_id ∧ c.story_id = r.story_id) roles r |
| | 335 | ) |
| | 336 | ⨝ (c.user_id = p.user_id ∧ c.story_id = p.story_id) permission_level p |
| | 337 | ) |
| | 338 | |
| | 339 | NotificationPreview ← |
| | 340 | π |
| | 341 | iw.user_id → recipient_user_id, |
| | 342 | iw.username → recipient_username, |
| | 343 | 'You have been invited to collaborate on "' || os.short_description || '"' |
| | 344 | → notification_content, |
| | 345 | 'collaboration' → type, |
| | 346 | '/story/' || os.story_id → link |
| | 347 | ( |
| | 348 | InvitedWriter iw |
| | 349 | ⨯ OwnedStory os |
| | 350 | ) |
| | 351 | |
| | 352 | Result ← |
| | 353 | π |
| | 354 | cc.username, |
| | 355 | cc.user_name, |
| | 356 | cc.surname, |
| | 357 | cc.roles, |
| | 358 | cc.permission_level, |
| | 359 | cc.collab_created_at, |
| | 360 | COUNT(*) OVER () → total_collaborators, |
| | 361 | np.notification_content → pending_notification, |
| | 362 | CASE |
| | 363 | WHEN OwnedStory = ∅ → 'Failed: story not found or not owned by you' |
| | 364 | WHEN InvitedWriter = ∅ → 'Failed: invited user is not a writer' |
| | 365 | WHEN AlreadyCollaborating ≠ ∅ → 'User is already a collaborator' |
| | 366 | ELSE → 'Ready to add collaborator' |
| | 367 | END → status |
| | 368 | ( |
| | 369 | CurrentCollaborators cc |
| | 370 | ⟕ (cc.username = np.recipient_username) NotificationPreview np |
| | 371 | ) |
| | 372 | }}} |