1 = Resources = 2 3 In imip-agent, resources are a special kind of user that act upon requests 4 to schedule events and that perform such scheduling autonomously, meaning 5 that no human intervention is necessary when such resources receive messages 6 containing invitations. 7 8 By default, the [[../AgentPrograms|agent program]] responsible for resources 9 merely attempts to fit a received event into the resource's schedule. However, 10 in some organisations and environments, it is likely to be the case that other 11 policies are needed to ensure that a resource is not misused, overused or made 12 unnecessarily unavailable. 13 14 The [[../Preferences|preferences]] provide a way of controlling the behaviour 15 of resources, just as with any other kind of user, but certain preferences 16 are central to the configuration of resources. 17 18 <<TableOfContents(2,4)>> 19 20 == Scheduling Functions == 21 22 The [[../Preferences#scheduling_function|scheduling_function]] setting 23 indicates the behaviour of a resource when a valid request to schedule an 24 event has been received. By default, a value equivalent to the following is 25 employed: 26 27 {{{{#!table 28 '''Scheduling Functions''' || '''Decision Process''' 29 == 30 <style="vertical-align: top;"> 31 32 {{{ 33 schedule_in_freebusy 34 }}} 35 36 || 37 38 {{{#!graphviz 39 //format=svg 40 //transform=notugly 41 digraph scheduling_decisions { 42 node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Scheduling decisions"]; 43 edge [tooltip="Scheduling decisions"]; 44 45 mail [label="Incoming mail",shape=folder,style=filled,fillcolor=cyan]; 46 47 subgraph { 48 rank=same; 49 schedule_in_freebusy [label="Can schedule in free/busy?",shape=ellipse,style=filled,fillcolor=gold]; 50 freebusy [label="Free/busy",shape=folder]; 51 } 52 53 schedule [label="Schedule event for resource",shape=ellipse,style=filled,fillcolor=gold]; 54 55 subgraph { 56 rank=same; 57 accept [label="Accept",shape=folder,style=filled,fillcolor=cyan]; 58 decline [label="Decline",shape=folder,style=filled,fillcolor=cyan]; 59 } 60 61 mail -> schedule_in_freebusy -> schedule -> accept; 62 schedule_in_freebusy -> decline [style=dashed]; 63 freebusy -> schedule_in_freebusy; 64 } 65 }}} 66 67 }}}} 68 69 As described above, this merely attempts to schedule an event in the free 70 periods of the resource's schedule. However, no attempt is made to reject the 71 booking of the resource according to the identity of the organiser. 72 73 === Concurrent Reservations === 74 75 The `schedule_in_freebusy` function causes a resource to attempt to schedule 76 an event, and by default it rejects requests that involve periods for which 77 the resource is otherwise committed. However, a resource can be allowed to 78 attend (or commit to) multiple concurrent events. 79 80 By indicating a value as an argument to the function, a kind of capacity or 81 commitment level can be assigned to a resource. For example: 82 83 {{{ 84 schedule_in_freebusy 5 85 }}} 86 87 This example indicates that a resource can support five different events 88 occupying the same point in time. Applications of such concurrent reservations 89 include things like rooms or resources that can be shared and which have a 90 notion of a capacity that is not immediately exhausted as soon as one event 91 seeks to reserve such a room or resource. 92 93 === Identity Controls === 94 95 Although identity controls may be implemented in the e-mail system, 96 effectively preventing the messages from addresses other than those within 97 an organisation (for example) from being delivered to the resource, it is 98 possible to use scheduling functions to implement such controls instead. 99 100 ==== Same Domain Membership ==== 101 102 For instance, the following combines the default free/busy check with a 103 test that the organiser belongs to the same Internet mail domain (by using 104 the organiser's address): 105 106 {{{{#!table 107 '''Scheduling Functions''' || '''Decision Process''' 108 == 109 <style="vertical-align: top;"> 110 111 {{{ 112 schedule_in_freebusy 113 same_domain_only 114 }}} 115 116 || 117 118 {{{#!graphviz 119 //format=svg 120 //transform=notugly 121 digraph scheduling_decisions { 122 node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Scheduling decisions"]; 123 edge [tooltip="Scheduling decisions"]; 124 125 mail [label="Incoming mail",shape=folder,style=filled,fillcolor=cyan]; 126 127 subgraph { 128 rank=same; 129 schedule_in_freebusy [label="Can schedule in free/busy?",shape=ellipse,style=filled,fillcolor=gold]; 130 freebusy [label="Free/busy",shape=folder]; 131 } 132 133 same_domain_only [label="Organiser has resource domain?",shape=ellipse,style=filled,fillcolor=gold]; 134 135 schedule [label="Schedule event for resource",shape=ellipse,style=filled,fillcolor=gold]; 136 137 subgraph { 138 rank=same; 139 accept [label="Accept",shape=folder,style=filled,fillcolor=cyan]; 140 decline [label="Decline",shape=folder,style=filled,fillcolor=cyan]; 141 } 142 143 mail -> schedule_in_freebusy -> same_domain_only -> schedule -> accept; 144 schedule_in_freebusy -> decline [style=dashed]; 145 same_domain_only -> decline [style=dashed]; 146 freebusy -> schedule_in_freebusy; 147 } 148 }}} 149 150 }}}} 151 152 Note that if the first function is omitted, no check against the resource's 153 schedule will occur, so it is necessary to mention any such function in the 154 list. 155 156 ==== Access Control Lists ==== 157 158 A simple domain-related test may not be sufficient to control access to a 159 resource. Thus, another function is provided to exercise a finer degree of 160 control over event participants. For example: 161 162 {{{{#!table 163 '''Scheduling Functions and Data''' || '''Decision Process''' 164 == 165 <style="vertical-align: top;"> 166 167 {{{ 168 schedule_in_freebusy 169 access_control_list 170 }}} 171 172 Access control list: 173 174 {{{ 175 accept 176 }}} 177 178 || 179 180 {{{#!graphviz 181 //format=svg 182 //transform=notugly 183 digraph scheduling_decisions { 184 node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Scheduling decisions"]; 185 edge [tooltip="Scheduling decisions"]; 186 187 mail [label="Incoming mail",shape=folder,style=filled,fillcolor=cyan]; 188 189 subgraph { 190 rank=same; 191 schedule_in_freebusy [label="Can schedule in free/busy?",shape=ellipse,style=filled,fillcolor=gold]; 192 freebusy [label="Free/busy",shape=folder]; 193 } 194 195 subgraph { 196 rank=same; 197 access_control_list [label="Access control list permits booking?",shape=ellipse,style=filled,fillcolor=gold]; 198 acl [label="acl setting",shape=folder]; 199 } 200 201 accept_default [label="Accept invitation by default",shape=ellipse,style=filled,fillcolor=darkorange]; 202 end_acl [label="end",shape=ellipse,style=filled,fillcolor=darkorange]; 203 204 schedule [label="Schedule event for resource",shape=ellipse,style=filled,fillcolor=gold]; 205 206 subgraph { 207 rank=same; 208 accept [label="Accept",shape=folder,style=filled,fillcolor=cyan]; 209 decline [label="Decline",shape=folder,style=filled,fillcolor=cyan]; 210 } 211 212 mail -> schedule_in_freebusy -> access_control_list -> accept_default -> end_acl -> schedule -> accept; 213 end_acl -> decline [style=dashed]; 214 schedule_in_freebusy -> decline [style=dashed]; 215 freebusy -> schedule_in_freebusy; 216 acl -> access_control_list; 217 } 218 }}} 219 220 }}}} 221 222 To accompany the scheduling functions, the [[../Preferences#acl|acl]] setting 223 in the resource's preferences must be set, or if a separate file is more 224 appropriate, its full path may be given as an argument to `access_control_list`: 225 226 {{{ 227 schedule_in_freebusy 228 access_control_list /etc/imip-agent/resources.acl 229 }}} 230 231 Within the file provided by the setting or separate file, a list of rules 232 must describe the handling procedure for an event. For example, the following 233 was given in the above example: 234 235 {{{ 236 accept 237 }}} 238 239 This will merely accept all invitations, anyway. However, it may be 240 appropriate to prevent certain users from using resources. For example: 241 242 {{{{#!table 243 '''Scheduling Functions and Data''' || '''Decision Process''' 244 == 245 <style="vertical-align: top;"> 246 247 {{{ 248 schedule_in_freebusy 249 access_control_list 250 }}} 251 252 Access control list: 253 254 {{{ 255 accept 256 decline attendee simon.skunk@example.com 257 }}} 258 259 || 260 261 {{{#!graphviz 262 //format=svg 263 //transform=notugly 264 digraph scheduling_decisions { 265 node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Scheduling decisions"]; 266 edge [tooltip="Scheduling decisions"]; 267 268 mail [label="Incoming mail",shape=folder,style=filled,fillcolor=cyan]; 269 270 subgraph { 271 rank=same; 272 schedule_in_freebusy [label="Can schedule in free/busy?",shape=ellipse,style=filled,fillcolor=gold]; 273 freebusy [label="Free/busy",shape=folder]; 274 } 275 276 subgraph { 277 rank=same; 278 access_control_list [label="Access control list permits booking?",shape=ellipse,style=filled,fillcolor=gold]; 279 acl [label="acl setting",shape=folder]; 280 } 281 282 accept_default [label="Accept invitation by default",shape=ellipse,style=filled,fillcolor=darkorange]; 283 decline_attendee [label="Is attendee simon.skunk@example.com?",shape=ellipse,style=filled,fillcolor=darkorange]; 284 end_acl [label="end",shape=ellipse,style=filled,fillcolor=darkorange]; 285 286 schedule [label="Schedule event for resource",shape=ellipse,style=filled,fillcolor=gold]; 287 288 subgraph { 289 rank=same; 290 accept [label="Accept",shape=folder,style=filled,fillcolor=cyan]; 291 decline [label="Decline",shape=folder,style=filled,fillcolor=cyan]; 292 } 293 294 mail -> schedule_in_freebusy -> access_control_list -> accept_default -> decline_attendee -> end_acl -> schedule -> accept; 295 end_acl -> decline [style=dashed]; 296 schedule_in_freebusy -> decline [style=dashed]; 297 freebusy -> schedule_in_freebusy; 298 acl -> access_control_list; 299 } 300 }}} 301 302 }}}} 303 304 This example indicates that by default, invitations will be accepted, but if 305 one of the attendees of an event is `simon.skunk@example.com`, the invitation 306 will be declined. However, it may be the case that this rule should be 307 overridden under certain circumstances. For example: 308 309 {{{{#!table 310 '''Scheduling Functions and Data''' || '''Decision Process''' 311 == 312 <style="vertical-align: top;"> 313 314 {{{ 315 schedule_in_freebusy 316 access_control_list 317 }}} 318 319 Access control list: 320 321 {{{ 322 accept 323 decline attendee simon.skunk@example.com 324 accept organiser paul.boddie@example.com 325 }}} 326 327 || 328 329 {{{#!graphviz 330 //format=svg 331 //transform=notugly 332 digraph scheduling_decisions { 333 node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Scheduling decisions"]; 334 edge [tooltip="Scheduling decisions"]; 335 336 mail [label="Incoming mail",shape=folder,style=filled,fillcolor=cyan]; 337 338 subgraph { 339 rank=same; 340 schedule_in_freebusy [label="Can schedule in free/busy?",shape=ellipse,style=filled,fillcolor=gold]; 341 freebusy [label="Free/busy",shape=folder]; 342 } 343 344 subgraph { 345 rank=same; 346 access_control_list [label="Access control list permits booking?",shape=ellipse,style=filled,fillcolor=gold]; 347 acl [label="acl setting",shape=folder]; 348 } 349 350 accept_default [label="Accept invitation by default",shape=ellipse,style=filled,fillcolor=darkorange]; 351 decline_attendee [label="Is attendee simon.skunk@example.com?",shape=ellipse,style=filled,fillcolor=darkorange]; 352 accept_organiser [label="Is organiser paul.boddie@example.com?",shape=ellipse,style=filled,fillcolor=darkorange]; 353 end_acl [label="end",shape=ellipse,style=filled,fillcolor=darkorange]; 354 355 schedule [label="Schedule event for resource",shape=ellipse,style=filled,fillcolor=gold]; 356 357 subgraph { 358 rank=same; 359 accept [label="Accept",shape=folder,style=filled,fillcolor=cyan]; 360 decline [label="Decline",shape=folder,style=filled,fillcolor=cyan]; 361 } 362 363 mail -> schedule_in_freebusy -> access_control_list -> accept_default -> decline_attendee -> accept_organiser -> end_acl -> schedule -> accept; 364 end_acl -> decline [style=dashed]; 365 schedule_in_freebusy -> decline [style=dashed]; 366 freebusy -> schedule_in_freebusy; 367 acl -> access_control_list; 368 } 369 }}} 370 371 }}}} 372 373 Here, the stated organiser may still arrange a booking of the resource where 374 the previously-mentioned attendee is involved. 375 376 === Quota Controls === 377 378 In contrast to each user's stored information which consolidates information 379 related to that user's own schedule in a section of the data store, the quota 380 system consolidates information related to the schedules of one or more 381 resources in a repository known as the journal, thus enabling observations to 382 be made about their collective usage. 383 384 First, consider a resource such as a car where an organiser of an event may be 385 booking the car for travel purposes. A quota prevents the organiser from 386 booking the resource too much and denying other users access to it. 387 388 {{{#!graphviz 389 //format=svg 390 //transform=notugly 391 digraph quota_users { 392 node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Quota example"]; 393 edge [tooltip="Quota example"]; 394 395 subgraph { 396 rank=same; 397 reservation1 [label="Reservation from oliver.otter@example.com\nMonday at 10am",shape=folder,style=filled,fillcolor=cyan]; 398 reservation2 [label="Reservation from oliver.otter@example.com\nTuesday at 10am",shape=folder,style=filled,fillcolor=cyan]; 399 reservation3 [label="Reservation from oliver.otter@example.com\nWednesday at 10am",shape=folder,style=filled,fillcolor=cyan]; 400 } 401 402 subgraph { 403 rank=same; 404 test1 [label="Within quota?",shape=ellipse,style=filled,fillcolor=gold]; 405 test2 [label="Within quota?",shape=ellipse,style=filled,fillcolor=gold]; 406 test3 [label="Within quota?",shape=ellipse,style=filled,fillcolor=gold]; 407 } 408 409 subgraph { 410 rank=max; 411 quota [label="Quota for resource-car-pontiac@example.com",shape=folder]; 412 } 413 414 reservation1 -> test1; 415 reservation2 -> test2; 416 reservation3 -> test3; 417 418 quota -> test1; 419 quota -> test2; 420 quota -> test3; 421 } 422 }}} 423 424 Now consider a number of separate car resources. An organiser might attempt to 425 get around any individual resource quota by booking a number of different cars. 426 Since each car is only aware of its own usage, it would be unaware of the 427 undesirable cumulative usage of all cars by the organiser. 428 429 By grouping the resources together, the organiser will exhaust any quota set on 430 the group of resources as they try and make reservations for the different 431 members of the quota group. Some additional measures are introduced as follows: 432 433 {{{#!graphviz 434 //format=svg 435 //transform=notugly 436 digraph quota_users { 437 node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Quota example"]; 438 edge [tooltip="Quota example"]; 439 440 subgraph { 441 rank=same; 442 reservation1 [label="Reservation from oliver.otter@example.com\nMonday at 10am",shape=folder,style=filled,fillcolor=cyan]; 443 reservation2 [label="Reservation from oliver.otter@example.com\nTuesday at 10am",shape=folder,style=filled,fillcolor=cyan]; 444 reservation3 [label="Reservation from oliver.otter@example.com\nWednesday at 10am",shape=folder,style=filled,fillcolor=cyan]; 445 } 446 447 subgraph { 448 rank=same; 449 car1 [label="resource-car-pontiac@example.com",shape=folder]; 450 car2 [label="resource-car-cadillac@example.com",shape=folder]; 451 car3 [label="resource-car-lexus@example.com",shape=folder]; 452 } 453 454 test [label="Within common quota?",shape=ellipse,style=filled,fillcolor=gold]; 455 456 subgraph { 457 rank=max; 458 journal [label="Quota for cars",shape=folder]; 459 } 460 461 reservation1 -> car1 -> test; 462 reservation2 -> car2 -> test; 463 reservation3 -> car3 -> test; 464 465 journal -> test; 466 } 467 }}} 468 469 ==== Initialising Quotas ==== 470 471 Within the journal storage area, a quota may be initialised with limits 472 indicating the amount of time that can be occupied by the cumulative total of 473 all events scheduled by an individual user or a group of which they are a 474 member. 475 476 Such limits may be set directly using the `limits` file in a quota directory 477 (described in the [[../FilesystemUsage|filesystem guide]]) or in the 478 `quota_limits` table (described in the [[../DatabaseStore|database guide]]), 479 but a tool is also provided to set such limits. For example: 480 481 {{{ 482 cat <<EOF | set_quota_limits.py 'mailto:resource-car-cadillac@example.com' 483 mailto:vincent.vole@example.com PT10H 484 EOF 485 }}} 486 487 {{{#!wiki tip 488 In the above example, shell syntax is used to indicate a 489 [[http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_07_04|here document]] 490 providing a kind of "inline" file that is terminated by the final `EOF`. 491 The contents of this file are piped to the tool with a single argument given 492 indicating the quota involved. 493 494 You could also just invoke the tool and then enter the limit descriptions, 495 ending the input with Ctrl-D or equivalent end-of-file keystroke, or save 496 the descriptions in a file and then use input redirection with the filename. 497 }}} 498 499 The above example indicates that the given user may only reserve 10 hours 500 of events or less time within the given quota (corresponding to a specific 501 resource in the above example). Attempts to schedule more time will be 502 declined. 503 504 To impose a general quota, the special `*` identity can be used: 505 506 {{{ 507 cat <<EOF | set_quota_limits.py 'mailto:resource-car-cadillac@example.com' 508 * PT10H 509 EOF 510 }}} 511 512 Note that this general quota applies to each individual identity and not 513 collectively to all unspecified identities. To impose such a collective 514 quota, a group may be defined for this purpose as described below. 515 516 When a user identity is not listed and no general quota is defined, that 517 particular user will be unable to reserve the resource unless defined as a 518 member of a group listed in the `limits` file, as described below. 519 520 It may be useful to define unlimited quotas for certain identities or 521 groups in order to effectively exclude them from limits. For example: 522 523 {{{ 524 cat <<EOF | set_quota_limits.py 'mailto:resource-car-cadillac@example.com' 525 mailto:vincent.vole@example.com * 526 EOF 527 }}} 528 529 ==== Sharing Quotas Across Users ==== 530 531 When the use of resources is to be shared between users in such a way that 532 groups of users will be sharing a single quota, a `groups` file in a quota 533 directory (or records in the `quota_groups` table) must be defined, mapping 534 each user identity to the group to which they will belong. 535 536 A tool is provided to define groups and is used as follows: 537 538 {{{ 539 cat <<EOF | tools/set_quota_groups.py 'mailto:resource-car-cadillac@example.com' 540 mailto:vincent.vole@example.com developers 541 * others 542 EOF 543 }}} 544 545 Here, otherwise unrecognised organisers are mapped to the `others` group. 546 Thus, all scheduling performed by such organisers will be done in a common 547 journal with this label. 548 549 The process of determining where an organiser's usage of resources is 550 recorded is illustrated by the following example: 551 552 {{{{#!table 553 '''Scheduling Data''' || '''Decision Process''' 554 == 555 <style="vertical-align: top;"> 556 The groups are defined as follows in the `groups` file: 557 558 {{{ 559 mailto:vincent.vole@example.com developers 560 mailto:harvey.horse@example.com developers 561 mailto:paul.boddie@example.com developers 562 mailto:simon.skunk@example.com testers 563 }}} 564 565 The group identity can then be employed in the `limits` file: 566 567 {{{ 568 developers PT10H 569 testers PT20H 570 }}} 571 572 || 573 574 {{{#!graphviz 575 //format=svg 576 //transform=notugly 577 digraph quota_users { 578 node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Quota users"]; 579 edge [tooltip="Quota users"]; 580 581 subgraph { 582 rank=same; 583 user1 [label="User is vincent.vole@example.com"]; 584 user2 [label="User is oliver.otter@example.com"]; 585 } 586 587 havegroup [label="Have group for quota?",shape=ellipse,style=filled,fillcolor=gold]; 588 haveuser [label="Have group for user in quota?",shape=ellipse,style=filled,fillcolor=gold]; 589 590 group1 [label="User is vincent.vole@example.com\nGroup is developers"]; 591 group2 [label="User is oliver.otter@example.com"]; 592 593 checkuser1 [label="Have limit for group?",shape=ellipse,style=filled,fillcolor=gold]; 594 checkgeneral1 [label="Have general limit?",shape=ellipse,style=filled,fillcolor=gold]; 595 596 checkuser2 [label="Have limit for user?",shape=ellipse,style=filled,fillcolor=gold]; 597 checkgeneral2 [label="Have general limit?",shape=ellipse,style=filled,fillcolor=gold]; 598 599 accept [label="Quota",shape=folder,style=filled,fillcolor=cyan]; 600 decline [label="No quota",shape=folder,style=filled,fillcolor=cyan]; 601 602 user1 -> havegroup -> haveuser -> group1 -> checkuser1 -> checkgeneral1 -> accept; 603 user2 -> havegroup -> haveuser -> group2 -> checkuser2 -> checkgeneral2 -> decline [style=dashed]; 604 } 605 }}} 606 }}}} 607 608 Where individuals are not assigned to groups, any individual limit will apply 609 to them; otherwise, the general quota applies. Where individuals are assigned 610 to groups, any group limit will apply; otherwise, the general quota applies. 611 612 ==== Individual Resource Quotas ==== 613 614 The trivial case of applying quotas is to give a resource its own quota. This 615 is achieved by not specifying any arguments to the `check_quota` scheduling 616 function or to the `add_to_quota` and `remove_from_quota` functions. 617 618 {{{{#!table 619 '''Scheduling Functions''' || '''Decision Process''' 620 == 621 <style="vertical-align: top;"> 622 623 {{{ 624 check_quota 625 }}} 626 627 || 628 629 {{{#!graphviz 630 //format=svg 631 //transform=notugly 632 digraph scheduling_decisions { 633 node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Scheduling decisions"]; 634 edge [tooltip="Scheduling decisions"]; 635 636 subgraph { 637 rank=same; 638 mail [label="Incoming mail\nfrom vincent.vole@example.com",shape=folder,style=filled,fillcolor=cyan]; 639 cancel [label="Incoming cancellation",shape=folder,style=filled,fillcolor=cyan]; 640 } 641 642 subgraph { 643 rank=same; 644 check_quota [label="Is allowed by quota?",shape=ellipse,style=filled,fillcolor=gold]; 645 quota [label="Quota for resource",shape=folder]; 646 quota_for_vole [label="...applying to\nvincent.vole@example.com",shape=folder]; 647 } 648 649 schedule [label="Schedule event for resource",shape=ellipse,style=filled,fillcolor=gold]; 650 651 subgraph { 652 rank=same; 653 accept [label="Accept",shape=folder,style=filled,fillcolor=cyan]; 654 decline [label="Decline",shape=folder,style=filled,fillcolor=cyan]; 655 } 656 657 add_to_quota [label="Add to quota",shape=ellipse,style=filled,fillcolor=darkorange]; 658 remove_from_quota [label="Remove from quota",shape=ellipse,style=filled,fillcolor=darkorange]; 659 660 mail -> check_quota -> schedule -> accept; 661 check_quota -> decline [style=dashed]; 662 schedule -> add_to_quota -> quota; 663 quota -> quota_for_vole -> check_quota; 664 665 cancel -> remove_from_quota -> quota; 666 } 667 }}} 668 669 }}}} 670 671 ==== Common Resource Quotas ==== 672 673 By indicating an argument to the different functions, a common quota can be 674 employed. In the following example, both resources would employ the given 675 function invocations to pool their knowledge about their schedules. 676 677 {{{{#!table 678 '''Scheduling Functions''' || '''Decision Process''' 679 == 680 <style="vertical-align: top;"> 681 682 {{{ 683 check_quota cars 684 }}} 685 686 || 687 688 {{{#!graphviz 689 //format=svg 690 //transform=notugly 691 digraph scheduling_decisions { 692 node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Scheduling decisions"]; 693 edge [tooltip="Scheduling decisions"]; 694 695 subgraph { 696 rank=same; 697 mail_cadillac [label="Incoming mail\nfrom vincent.vole@example.com\nto resource-car-cadillac@example.com",shape=folder,style=filled,fillcolor=cyan]; 698 mail_pontiac [label="Incoming mail\nfrom vincent.vole@example.com\nto resource-car-pontiac@example.com",shape=folder,style=filled,fillcolor=cyan]; 699 cancel [label="Incoming cancellation",shape=folder,style=filled,fillcolor=cyan]; 700 } 701 702 subgraph { 703 rank=same; 704 check_quota [label="Is allowed by quota?",shape=ellipse,style=filled,fillcolor=gold]; 705 quota_cars [label="Quota for cars",shape=folder]; 706 quota_cars_vole [label="...applying to\nvincent.vole@example.com",shape=folder]; 707 } 708 709 schedule [label="Schedule event for resource",shape=ellipse,style=filled,fillcolor=gold]; 710 711 subgraph { 712 rank=same; 713 accept [label="Accept",shape=folder,style=filled,fillcolor=cyan]; 714 decline [label="Decline",shape=folder,style=filled,fillcolor=cyan]; 715 } 716 717 add_to_quota [label="Add to quota",shape=ellipse,style=filled,fillcolor=darkorange]; 718 remove_from_quota [label="Remove from quota",shape=ellipse,style=filled,fillcolor=darkorange]; 719 720 mail_cadillac -> check_quota; 721 mail_pontiac -> check_quota -> schedule -> accept; 722 check_quota -> decline [style=dashed]; 723 schedule -> add_to_quota -> quota_cars; 724 quota_cars -> quota_cars_vole -> check_quota; 725 726 cancel -> remove_from_quota -> quota_cars; 727 } 728 }}} 729 730 }}}} 731 732 ==== Collective Scheduling ==== 733 734 Consider two separate resources: both may be reserved at the same time by the 735 same organiser; neither resource would normally decline the reservation on the 736 basis of schedule availability, should the period concerned be free. However, 737 it may be undesirable for one organiser to occupy both resources at the same 738 time. 739 740 Consequently, a mechanism is required to pool the resource schedules in such a 741 way that any reservation performed for one resource at a given point in time 742 prohibits another reservation performed for a related resource at the same 743 point in time by the same user. 744 745 The free/busy records held for a given quota group permit such collective 746 scheduling decisions and are employed as follows: 747 748 {{{{#!table 749 '''Scheduling Functions''' || '''Decision Process''' 750 == 751 <style="vertical-align: top;"> 752 753 {{{ 754 schedule_across_quota cars 755 }}} 756 757 || 758 759 {{{#!graphviz 760 //format=svg 761 //transform=notugly 762 digraph scheduling_decisions { 763 node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Scheduling decisions"]; 764 edge [tooltip="Scheduling decisions"]; 765 766 subgraph { 767 rank=same; 768 mail_cadillac [label="Incoming mail\nfrom vincent.vole@example.com\nto resource-car-cadillac@example.com",shape=folder,style=filled,fillcolor=cyan]; 769 mail_pontiac [label="Incoming mail\nfrom vincent.vole@example.com\nto resource-car-pontiac@example.com",shape=folder,style=filled,fillcolor=cyan]; 770 cancel [label="Incoming cancellation",shape=folder,style=filled,fillcolor=cyan]; 771 } 772 773 subgraph { 774 rank=same; 775 schedule_across_quota [label="Can be scheduled within the quota?",shape=ellipse,style=filled,fillcolor=gold]; 776 quota_cars [label="Quota for cars",shape=folder]; 777 freebusy_cars_vole [label="...recording schedule for\nvincent.vole@example.com",shape=folder]; 778 } 779 780 schedule [label="Schedule event for resource",shape=ellipse,style=filled,fillcolor=gold]; 781 782 subgraph { 783 rank=same; 784 accept [label="Accept",shape=folder,style=filled,fillcolor=cyan]; 785 decline [label="Decline",shape=folder,style=filled,fillcolor=cyan]; 786 } 787 788 add_to_quota_freebusy [label="Add to quota free/busy",shape=ellipse,style=filled,fillcolor=darkorange]; 789 remove_from_quota_freebusy [label="Remove from quota free/busy",shape=ellipse,style=filled,fillcolor=darkorange]; 790 791 mail_cadillac -> schedule_across_quota; 792 mail_pontiac -> schedule_across_quota -> schedule -> accept; 793 schedule_across_quota -> decline [style=dashed]; 794 schedule -> add_to_quota_freebusy -> quota_cars -> freebusy_cars_vole; 795 freebusy_cars_vole -> schedule_across_quota; 796 797 cancel -> remove_from_quota_freebusy -> quota_cars; 798 } 799 }}} 800 801 }}}} 802 803 ==== Delegating Attendance ==== 804 805 A number of resources may be regarded as interchangeable and can therefore 806 stand in for each other when they are unavailable. The iCalendar specification 807 supports the notion of delegation: the recipient of an event invitation may 808 delegate their attendance to other calendar user, informing that user and the 809 event organiser of this decision. 810 811 To define such delegation relationships, a quota is first selected as the 812 repository of common scheduling information for a group of resources. Then, 813 the members of the group are defined as delegates. This can be done using a 814 tool provided for this purpose. For example: 815 816 {{{ 817 cat <<EOF | tools/set_delegates.py 'cars' 818 mailto:resource-car-cadillac@example.com 819 mailto:resource-car-pontiac@example.com 820 EOF 821 }}} 822 823 Here, two resources are defined that will delegate to each other if they 824 cannot attend an event according to their own schedule. 825 826 {{{{#!table 827 '''Scheduling Functions''' || '''Decision Process''' 828 == 829 <style="vertical-align: top;"> 830 831 {{{ 832 schedule_for_delegate cars 833 }}} 834 835 || 836 837 {{{#!graphviz 838 //format=svg 839 //transform=notugly 840 digraph scheduling_decisions { 841 node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Scheduling decisions"]; 842 edge [tooltip="Scheduling decisions"]; 843 844 subgraph { 845 rank=same; 846 mail_cadillac [label="Incoming mail\nfrom vincent.vole@example.com\nto resource-car-cadillac@example.com",shape=folder,style=filled,fillcolor=cyan]; 847 mail_pontiac [label="Incoming mail\nfrom vincent.vole@example.com\nto resource-car-pontiac@example.com",shape=folder,style=filled,fillcolor=cyan]; 848 cancel [label="Incoming cancellation",shape=folder,style=filled,fillcolor=cyan]; 849 } 850 851 subgraph { 852 rank=same; 853 schedule_for_delegate [label="Can be scheduled or delegated?",shape=ellipse,style=filled,fillcolor=gold]; 854 quota_cars [label="Quota for cars",shape=folder]; 855 freebusy_cars_vole [label="...recording schedule for\nvincent.vole@example.com",shape=folder]; 856 } 857 858 schedule [label="Schedule event for resource",shape=ellipse,style=filled,fillcolor=gold]; 859 860 subgraph { 861 rank=same; 862 accept [label="Accept",shape=folder,style=filled,fillcolor=cyan]; 863 delegate [label="Delegate",shape=folder,style=filled,fillcolor=cyan]; 864 decline [label="Decline",shape=folder,style=filled,fillcolor=cyan]; 865 } 866 867 add_to_quota [label="Add to quota",shape=ellipse,style=filled,fillcolor=darkorange]; 868 remove_from_quota [label="Remove from quota",shape=ellipse,style=filled,fillcolor=darkorange]; 869 870 mail_cadillac -> schedule_for_delegate; 871 mail_pontiac -> schedule_for_delegate -> schedule -> accept; 872 schedule_for_delegate -> delegate [style=dashed]; 873 schedule_for_delegate -> decline [style=dashed]; 874 schedule -> add_to_quota -> quota_cars -> freebusy_cars_vole; 875 freebusy_cars_vole -> schedule_for_delegate; 876 877 cancel -> remove_from_quota -> quota_cars; 878 } 879 }}} 880 881 }}}} 882 883 Note that it is generally more useful to have delegation decisions made on the 884 basis of many resources, which is what the journal entries for each quota 885 provides, but also considering organisers attempting to reserve those resources 886 as a single group whose reservations are consolidated and assessed collectively. 887 Thus, a single group of users would be defined: 888 889 {{{ 890 cat <<EOF | tools/set_quota_groups.py 'cars' 891 * all 892 EOF 893 }}} 894 895 Although the journal for each quota may be divided up to administer quotas for 896 multiple groups of organisers, for the purposes of delegation - deciding 897 whether a resource is generally available, and deciding which other resource 898 would be available instead - a single group of all organisers is more desirable. 899 900 If limits need to be imposed alongside delegation, separate quotas may be used 901 to achieve this. 902 903 {{{{#!table 904 '''Scheduling Functions''' || '''Decision Process''' 905 == 906 <style="vertical-align: top;"> 907 908 {{{ 909 check_quota cars 910 schedule_for_delegate car_delegation 911 }}} 912 913 || 914 915 {{{#!graphviz 916 //format=svg 917 //transform=notugly 918 digraph scheduling_decisions { 919 node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Scheduling decisions"]; 920 edge [tooltip="Scheduling decisions"]; 921 922 subgraph { 923 rank=same; 924 mail_cadillac [label="Incoming mail\nfrom vincent.vole@example.com\nto resource-car-cadillac@example.com",shape=folder,style=filled,fillcolor=cyan]; 925 mail_pontiac [label="Incoming mail\nfrom vincent.vole@example.com\nto resource-car-pontiac@example.com",shape=folder,style=filled,fillcolor=cyan]; 926 cancel [label="Incoming cancellation",shape=folder,style=filled,fillcolor=cyan]; 927 } 928 929 subgraph { 930 rank=same; 931 check_quota [label="Is allowed by quota?",shape=ellipse,style=filled,fillcolor=gold]; 932 quota_cars [label="Quota for cars",shape=folder]; 933 quota_cars_vole [label="...applying to\nvincent.vole@example.com",shape=folder]; 934 } 935 936 subgraph { 937 rank=same; 938 schedule_for_delegate [label="Can be scheduled or delegated?",shape=ellipse,style=filled,fillcolor=gold]; 939 quota_cars_delegation [label="Quota for cars_delegation",shape=folder]; 940 freebusy_cars_delegation_vole [label="...recording schedule for\nvincent.vole@example.com",shape=folder]; 941 } 942 943 schedule [label="Schedule event for resource",shape=ellipse,style=filled,fillcolor=gold]; 944 945 subgraph { 946 rank=same; 947 accept [label="Accept",shape=folder,style=filled,fillcolor=cyan]; 948 delegate [label="Delegate",shape=folder,style=filled,fillcolor=cyan]; 949 decline [label="Decline",shape=folder,style=filled,fillcolor=cyan]; 950 } 951 952 add_to_quota [label="Add to quota",shape=ellipse,style=filled,fillcolor=darkorange]; 953 remove_from_quota [label="Remove from quota",shape=ellipse,style=filled,fillcolor=darkorange]; 954 955 mail_cadillac -> check_quota; 956 mail_pontiac -> check_quota; 957 check_quota -> schedule_for_delegate; 958 check_quota -> decline [style=dashed]; 959 schedule_for_delegate -> schedule -> accept; 960 schedule_for_delegate -> delegate [style=dashed]; 961 schedule_for_delegate -> decline [style=dashed]; 962 schedule -> add_to_quota; 963 add_to_quota -> quota_cars -> quota_cars_vole; 964 add_to_quota -> quota_cars_delegation -> freebusy_cars_delegation_vole; 965 quota_cars_vole -> check_quota; 966 freebusy_cars_delegation_vole -> schedule_for_delegate; 967 968 cancel -> remove_from_quota; 969 remove_from_quota -> quota_cars; 970 remove_from_quota -> quota_cars_delegation; 971 } 972 }}} 973 974 }}}}