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, the quota system consolidates information 380 related to the schedules of one or more resources, thus enabling observations 381 to be made about their collective usage. 382 383 First, consider a resource such as a car where an organiser of an event may be 384 booking the car for travel purposes. A quota prevents the organiser from 385 booking the resource too much and denying other users access to it. 386 387 Now consider a number of separate car resources. An organiser might attempt to 388 get around any individual resource quota by booking a number of different cars. 389 By grouping the resources together, the organiser will exhaust any quota set on 390 the group of resources as they try and make reservations for the different 391 members of the quota group. 392 393 ==== Initialising Quotas ==== 394 395 Within the journal storage area, a quota may be initialised with limits 396 indicating the amount of time that can be occupied by the cumulative total of 397 all events scheduled by an individual user or a group of which they are a 398 member. 399 400 Such limits may be set directly using the `limits` file in a quota directory 401 (described in the [[../FilesystemUsage|filesystem guide]]) or in the 402 `quota_limits` table (described in the [[../DatabaseStore|database guide]]), 403 but a tool is also provided to set such limits. For example: 404 405 {{{ 406 cat <<EOF | set_quota_limits.py 'mailto:resource-car-cadillac@example.com' 407 mailto:vincent.vole@example.com PT10H 408 EOF 409 }}} 410 411 {{{#!wiki tip 412 In the above example, shell syntax is used to indicate a 413 [[http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_07_04|here document]] 414 providing a kind of "inline" file that is terminated by the final `EOF`. 415 The contents of this file are piped to the tool with a single argument given 416 indicating the quota involved. 417 418 You could also just invoke the tool and then enter the limit descriptions, 419 ending the input with Ctrl-D or equivalent end-of-file keystroke, or save 420 the descriptions in a file and then use input redirection with the filename. 421 }}} 422 423 The above example indicates that the given user may only reserve 10 hours 424 of events or less time within the given quota (corresponding to a specific 425 resource in the above example). Attempts to schedule more time will be 426 declined. 427 428 To impose a general quota, the special `*` identity can be used: 429 430 {{{ 431 cat <<EOF | set_quota_limits.py 'mailto:resource-car-cadillac@example.com' 432 * PT10H 433 EOF 434 }}} 435 436 Note that this general quota applies to each individual identity and not 437 collectively to all unspecified identities. To impose such a collective 438 quota, a group may be defined for this purpose as described below. 439 440 When a user identity is not listed and no general quota is defined, that 441 particular user will be unable to reserve the resource unless defined as a 442 member of a group listed in the `limits` file, as described below. 443 444 It may be useful to define unlimited quotas for certain identities or 445 groups in order to effectively exclude them from limits. For example: 446 447 {{{ 448 cat <<EOF | set_quota_limits.py 'mailto:resource-car-cadillac@example.com' 449 mailto:vincent.vole@example.com * 450 EOF 451 }}} 452 453 ==== Sharing Quotas Across Users ==== 454 455 When the use of resources is to be shared between users in such a way that 456 groups of users will be sharing a single quota, a `groups` file in a quota 457 directory (or records in the `quota_groups` table) must be defined, mapping 458 each user identity to the group to which they will belong. 459 460 A tool is provided to define groups and is used as follows: 461 462 {{{ 463 cat <<EOF | tools/set_quota_groups.py 'mailto:resource-car-cadillac@example.com' 464 mailto:vincent.vole@example.com developers 465 * others 466 EOF 467 }}} 468 469 Here, otherwise unrecognised organisers are mapped to the `others` group. 470 Thus, all scheduling performed by such organisers will be done in a common 471 journal with this label. 472 473 The process of determining where an organiser's usage of resources is 474 recorded is illustrated by the following example: 475 476 {{{{#!table 477 '''Scheduling Data''' || '''Decision Process''' 478 == 479 <style="vertical-align: top;"> 480 The groups are defined as follows in the `groups` file: 481 482 {{{ 483 mailto:vincent.vole@example.com developers 484 mailto:harvey.horse@example.com developers 485 mailto:paul.boddie@example.com developers 486 mailto:simon.skunk@example.com testers 487 }}} 488 489 The group identity can then be employed in the `limits` file: 490 491 {{{ 492 developers PT10H 493 testers PT20H 494 }}} 495 496 || 497 498 {{{#!graphviz 499 //format=svg 500 //transform=notugly 501 digraph quota_users { 502 node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Quota users"]; 503 edge [tooltip="Quota users"]; 504 505 subgraph { 506 rank=same; 507 user1 [label="User is vincent.vole@example.com"]; 508 user2 [label="User is oliver.otter@example.com"]; 509 } 510 511 havegroup [label="Have group for quota?",shape=ellipse,style=filled,fillcolor=gold]; 512 haveuser [label="Have group for user in quota?",shape=ellipse,style=filled,fillcolor=gold]; 513 514 group1 [label="User is vincent.vole@example.com\nGroup is developers"]; 515 group2 [label="User is oliver.otter@example.com"]; 516 517 checkuser1 [label="Have limit for group?",shape=ellipse,style=filled,fillcolor=gold]; 518 checkgeneral1 [label="Have general limit?",shape=ellipse,style=filled,fillcolor=gold]; 519 520 checkuser2 [label="Have limit for user?",shape=ellipse,style=filled,fillcolor=gold]; 521 checkgeneral2 [label="Have general limit?",shape=ellipse,style=filled,fillcolor=gold]; 522 523 accept [label="Quota",shape=folder,style=filled,fillcolor=cyan]; 524 decline [label="No quota",shape=folder,style=filled,fillcolor=cyan]; 525 526 user1 -> havegroup -> haveuser -> group1 -> checkuser1 -> checkgeneral1 -> accept; 527 user2 -> havegroup -> haveuser -> group2 -> checkuser2 -> checkgeneral2 -> decline [style=dashed]; 528 } 529 }}} 530 }}}} 531 532 Where individuals are not assigned to groups, any individual limit will apply 533 to them; otherwise, the general quota applies. Where individuals are assigned 534 to groups, any group limit will apply; otherwise, the general quota applies. 535 536 ==== Individual Resource Quotas ==== 537 538 The trivial case of applying quotas is to give a resource its own quota. This 539 is achieved by not specifying any arguments to the `check_quota` scheduling 540 function or to the `add_to_quota` and `remove_from_quota` functions. 541 542 {{{{#!table 543 '''Scheduling Functions''' || '''Decision Process''' 544 == 545 <style="vertical-align: top;"> 546 547 {{{ 548 check_quota 549 }}} 550 551 || 552 553 {{{#!graphviz 554 //format=svg 555 //transform=notugly 556 digraph scheduling_decisions { 557 node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Scheduling decisions"]; 558 edge [tooltip="Scheduling decisions"]; 559 560 subgraph { 561 rank=same; 562 mail [label="Incoming mail\nfrom vincent.vole@example.com",shape=folder,style=filled,fillcolor=cyan]; 563 cancel [label="Incoming cancellation",shape=folder,style=filled,fillcolor=cyan]; 564 } 565 566 subgraph { 567 rank=same; 568 check_quota [label="Is allowed by quota?",shape=ellipse,style=filled,fillcolor=gold]; 569 quota [label="Quota for resource",shape=folder]; 570 quota_for_vole [label="...applying to\nvincent.vole@example.com",shape=folder]; 571 } 572 573 schedule [label="Schedule event for resource",shape=ellipse,style=filled,fillcolor=gold]; 574 575 subgraph { 576 rank=same; 577 accept [label="Accept",shape=folder,style=filled,fillcolor=cyan]; 578 decline [label="Decline",shape=folder,style=filled,fillcolor=cyan]; 579 } 580 581 add_to_quota [label="Add to quota",shape=ellipse,style=filled,fillcolor=darkorange]; 582 remove_from_quota [label="Remove from quota",shape=ellipse,style=filled,fillcolor=darkorange]; 583 584 mail -> check_quota -> schedule -> accept; 585 check_quota -> decline [style=dashed]; 586 schedule -> add_to_quota -> quota; 587 quota -> quota_for_vole -> check_quota; 588 589 cancel -> remove_from_quota -> quota; 590 } 591 }}} 592 593 }}}} 594 595 ==== Common Resource Quotas ==== 596 597 By indicating an argument to the different functions, a common quota can be 598 employed. In the following example, both resources would employ the given 599 function invocations to pool their knowledge about their schedules. 600 601 {{{{#!table 602 '''Scheduling Functions''' || '''Decision Process''' 603 == 604 <style="vertical-align: top;"> 605 606 {{{ 607 check_quota cars 608 }}} 609 610 || 611 612 {{{#!graphviz 613 //format=svg 614 //transform=notugly 615 digraph scheduling_decisions { 616 node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Scheduling decisions"]; 617 edge [tooltip="Scheduling decisions"]; 618 619 subgraph { 620 rank=same; 621 mail_cadillac [label="Incoming mail\nfrom vincent.vole@example.com\nto resource-car-cadillac@example.com",shape=folder,style=filled,fillcolor=cyan]; 622 mail_pontiac [label="Incoming mail\nfrom vincent.vole@example.com\nto resource-car-pontiac@example.com",shape=folder,style=filled,fillcolor=cyan]; 623 cancel [label="Incoming cancellation",shape=folder,style=filled,fillcolor=cyan]; 624 } 625 626 subgraph { 627 rank=same; 628 check_quota [label="Is allowed by quota?",shape=ellipse,style=filled,fillcolor=gold]; 629 quota_cars [label="Quota for cars",shape=folder]; 630 quota_cars_vole [label="...applying to\nvincent.vole@example.com",shape=folder]; 631 } 632 633 schedule [label="Schedule event for resource",shape=ellipse,style=filled,fillcolor=gold]; 634 635 subgraph { 636 rank=same; 637 accept [label="Accept",shape=folder,style=filled,fillcolor=cyan]; 638 decline [label="Decline",shape=folder,style=filled,fillcolor=cyan]; 639 } 640 641 add_to_quota [label="Add to quota",shape=ellipse,style=filled,fillcolor=darkorange]; 642 remove_from_quota [label="Remove from quota",shape=ellipse,style=filled,fillcolor=darkorange]; 643 644 mail_cadillac -> check_quota; 645 mail_pontiac -> check_quota -> schedule -> accept; 646 check_quota -> decline [style=dashed]; 647 schedule -> add_to_quota -> quota_cars; 648 quota_cars -> quota_cars_vole -> check_quota; 649 650 cancel -> remove_from_quota -> quota_cars; 651 } 652 }}} 653 654 }}}} 655 656 ==== Collective Scheduling ==== 657 658 Consider two separate resources: both may be reserved at the same time by the 659 same organiser; neither resource would normally decline the reservation on the 660 basis of schedule availability, should the period concerned be free. However, 661 it may be undesirable for one organiser to occupy both resources at the same 662 time. 663 664 Consequently, a mechanism is required to pool the resource schedules in such a 665 way that any reservation performed for one resource at a given point in time 666 prohibits another reservation performed for a related resource at the same 667 point in time by the same user. 668 669 The free/busy records held for a given quota group permit such collective 670 scheduling decisions and are employed as follows: 671 672 {{{{#!table 673 '''Scheduling Functions''' || '''Decision Process''' 674 == 675 <style="vertical-align: top;"> 676 677 {{{ 678 schedule_across_quota cars 679 }}} 680 681 || 682 683 {{{#!graphviz 684 //format=svg 685 //transform=notugly 686 digraph scheduling_decisions { 687 node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Scheduling decisions"]; 688 edge [tooltip="Scheduling decisions"]; 689 690 subgraph { 691 rank=same; 692 mail_cadillac [label="Incoming mail\nfrom vincent.vole@example.com\nto resource-car-cadillac@example.com",shape=folder,style=filled,fillcolor=cyan]; 693 mail_pontiac [label="Incoming mail\nfrom vincent.vole@example.com\nto resource-car-pontiac@example.com",shape=folder,style=filled,fillcolor=cyan]; 694 cancel [label="Incoming cancellation",shape=folder,style=filled,fillcolor=cyan]; 695 } 696 697 subgraph { 698 rank=same; 699 schedule_across_quota [label="Can be scheduled within the quota?",shape=ellipse,style=filled,fillcolor=gold]; 700 quota_cars [label="Quota for cars",shape=folder]; 701 freebusy_cars_vole [label="...recording schedule for\nvincent.vole@example.com",shape=folder]; 702 } 703 704 schedule [label="Schedule event for resource",shape=ellipse,style=filled,fillcolor=gold]; 705 706 subgraph { 707 rank=same; 708 accept [label="Accept",shape=folder,style=filled,fillcolor=cyan]; 709 decline [label="Decline",shape=folder,style=filled,fillcolor=cyan]; 710 } 711 712 add_to_quota_freebusy [label="Add to quota free/busy",shape=ellipse,style=filled,fillcolor=darkorange]; 713 remove_from_quota_freebusy [label="Remove from quota free/busy",shape=ellipse,style=filled,fillcolor=darkorange]; 714 715 mail_cadillac -> schedule_across_quota; 716 mail_pontiac -> schedule_across_quota -> schedule -> accept; 717 schedule_across_quota -> decline [style=dashed]; 718 schedule -> add_to_quota_freebusy -> quota_cars -> freebusy_cars_vole; 719 freebusy_cars_vole -> schedule_across_quota; 720 721 cancel -> remove_from_quota_freebusy -> quota_cars; 722 } 723 }}} 724 725 }}}} 726 727 ==== Delegating Attendance ==== 728 729 A number of resources may be regarded as interchangeable and can therefore 730 stand in for each other when they are unavailable. The iCalendar specification 731 supports the notion of delegation: the recipient of an event invitation may 732 delegate their attendance to other calendar user, informing that user and the 733 event organiser of this decision. 734 735 To define such delegation relationships, a quota is first selected as the 736 repository of common scheduling information for a group of resources. Then, 737 the members of the group are defined as delegates. This can be done using a 738 tool provided for this purpose. For example: 739 740 {{{ 741 cat <<EOF | tools/set_delegates.py 'cars' 742 mailto:resource-car-cadillac@example.com 743 mailto:resource-car-pontiac@example.com 744 EOF 745 }}} 746 747 Here, two resources are defined that will delegate to each other if they 748 cannot attend an event according to their own schedule. 749 750 {{{{#!table 751 '''Scheduling Functions''' || '''Decision Process''' 752 == 753 <style="vertical-align: top;"> 754 755 {{{ 756 schedule_for_delegate cars 757 }}} 758 759 || 760 761 {{{#!graphviz 762 //format=svg 763 //transform=notugly 764 digraph scheduling_decisions { 765 node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Scheduling decisions"]; 766 edge [tooltip="Scheduling decisions"]; 767 768 subgraph { 769 rank=same; 770 mail_cadillac [label="Incoming mail\nfrom vincent.vole@example.com\nto resource-car-cadillac@example.com",shape=folder,style=filled,fillcolor=cyan]; 771 mail_pontiac [label="Incoming mail\nfrom vincent.vole@example.com\nto resource-car-pontiac@example.com",shape=folder,style=filled,fillcolor=cyan]; 772 cancel [label="Incoming cancellation",shape=folder,style=filled,fillcolor=cyan]; 773 } 774 775 subgraph { 776 rank=same; 777 schedule_for_delegate [label="Can be scheduled or delegated?",shape=ellipse,style=filled,fillcolor=gold]; 778 quota_cars [label="Quota for cars",shape=folder]; 779 freebusy_cars_vole [label="...recording schedule for\nvincent.vole@example.com",shape=folder]; 780 } 781 782 schedule [label="Schedule event for resource",shape=ellipse,style=filled,fillcolor=gold]; 783 784 subgraph { 785 rank=same; 786 accept [label="Accept",shape=folder,style=filled,fillcolor=cyan]; 787 delegate [label="Delegate",shape=folder,style=filled,fillcolor=cyan]; 788 decline [label="Decline",shape=folder,style=filled,fillcolor=cyan]; 789 } 790 791 add_to_quota [label="Add to quota",shape=ellipse,style=filled,fillcolor=darkorange]; 792 remove_from_quota [label="Remove from quota",shape=ellipse,style=filled,fillcolor=darkorange]; 793 794 mail_cadillac -> schedule_for_delegate; 795 mail_pontiac -> schedule_for_delegate -> schedule -> accept; 796 schedule_for_delegate -> delegate [style=dashed]; 797 schedule_for_delegate -> decline [style=dashed]; 798 schedule -> add_to_quota -> quota_cars -> freebusy_cars_vole; 799 freebusy_cars_vole -> schedule_for_delegate; 800 801 cancel -> remove_from_quota -> quota_cars; 802 } 803 }}} 804 805 }}}} 806 807 Note that it is generally more useful to have delegation decisions made on the 808 basis of many resources, which is what the journal entries for each quota 809 provides, but also considering organisers attempting to reserve those resources 810 as a single group whose reservations are consolidated and assessed collectively. 811 Thus, a single group of users would be defined: 812 813 {{{ 814 cat <<EOF | tools/set_quota_groups.py 'cars' 815 * all 816 EOF 817 }}} 818 819 Although the journal for each quota may be divided up to administer quotas for 820 multiple groups of organisers, for the purposes of delegation - deciding 821 whether a resource is generally available, and deciding which other resource 822 would be available instead - a single group of all organisers is more desirable. 823 824 If limits need to be imposed alongside delegation, separate quotas may be used 825 to achieve this. 826 827 {{{{#!table 828 '''Scheduling Functions''' || '''Decision Process''' 829 == 830 <style="vertical-align: top;"> 831 832 {{{ 833 check_quota cars 834 schedule_for_delegate car_delegation 835 }}} 836 837 || 838 839 {{{#!graphviz 840 //format=svg 841 //transform=notugly 842 digraph scheduling_decisions { 843 node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Scheduling decisions"]; 844 edge [tooltip="Scheduling decisions"]; 845 846 subgraph { 847 rank=same; 848 mail_cadillac [label="Incoming mail\nfrom vincent.vole@example.com\nto resource-car-cadillac@example.com",shape=folder,style=filled,fillcolor=cyan]; 849 mail_pontiac [label="Incoming mail\nfrom vincent.vole@example.com\nto resource-car-pontiac@example.com",shape=folder,style=filled,fillcolor=cyan]; 850 cancel [label="Incoming cancellation",shape=folder,style=filled,fillcolor=cyan]; 851 } 852 853 subgraph { 854 rank=same; 855 check_quota [label="Is allowed by quota?",shape=ellipse,style=filled,fillcolor=gold]; 856 quota_cars [label="Quota for cars",shape=folder]; 857 quota_cars_vole [label="...applying to\nvincent.vole@example.com",shape=folder]; 858 } 859 860 subgraph { 861 rank=same; 862 schedule_for_delegate [label="Can be scheduled or delegated?",shape=ellipse,style=filled,fillcolor=gold]; 863 quota_cars_delegation [label="Quota for cars_delegation",shape=folder]; 864 freebusy_cars_delegation_vole [label="...recording schedule for\nvincent.vole@example.com",shape=folder]; 865 } 866 867 schedule [label="Schedule event for resource",shape=ellipse,style=filled,fillcolor=gold]; 868 869 subgraph { 870 rank=same; 871 accept [label="Accept",shape=folder,style=filled,fillcolor=cyan]; 872 delegate [label="Delegate",shape=folder,style=filled,fillcolor=cyan]; 873 decline [label="Decline",shape=folder,style=filled,fillcolor=cyan]; 874 } 875 876 add_to_quota [label="Add to quota",shape=ellipse,style=filled,fillcolor=darkorange]; 877 remove_from_quota [label="Remove from quota",shape=ellipse,style=filled,fillcolor=darkorange]; 878 879 mail_cadillac -> check_quota; 880 mail_pontiac -> check_quota; 881 check_quota -> schedule_for_delegate; 882 check_quota -> decline [style=dashed]; 883 schedule_for_delegate -> schedule -> accept; 884 schedule_for_delegate -> delegate [style=dashed]; 885 schedule_for_delegate -> decline [style=dashed]; 886 schedule -> add_to_quota; 887 add_to_quota -> quota_cars -> quota_cars_vole; 888 add_to_quota -> quota_cars_delegation -> freebusy_cars_delegation_vole; 889 quota_cars_vole -> check_quota; 890 freebusy_cars_delegation_vole -> schedule_for_delegate; 891 892 cancel -> remove_from_quota; 893 remove_from_quota -> quota_cars; 894 remove_from_quota -> quota_cars_delegation; 895 } 896 }}} 897 898 }}}}