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 ==== Sharing Quotas Across Users ==== 445 446 When the use of resources is to be shared between users in such a way that 447 groups of users will be sharing a single quota, a `groups` file in a quota 448 directory (or records in the `quota_groups` table) must be defined, mapping 449 each user identity to the group to which they will belong. 450 451 A tool is provided to define groups and is used as follows: 452 453 {{{ 454 cat <<EOF | tools/set_quota_groups.py 'mailto:resource-car-cadillac@example.com' 455 mailto:vincent.vole@example.com developers 456 * others 457 EOF 458 }}} 459 460 Here, otherwise unrecognised organisers are mapped to the `others` group. 461 Thus, all scheduling performed by such organisers will be done in a common 462 journal with this label. 463 464 The process of determining where an organiser's usage of resources is 465 recorded is illustrated by the following example: 466 467 {{{{#!table 468 '''Scheduling Data''' || '''Decision Process''' 469 == 470 <style="vertical-align: top;"> 471 The groups are defined as follows in the `groups` file: 472 473 {{{ 474 mailto:vincent.vole@example.com developers 475 mailto:harvey.horse@example.com developers 476 mailto:paul.boddie@example.com developers 477 mailto:simon.skunk@example.com testers 478 }}} 479 480 The group identity can then be employed in the `limits` file: 481 482 {{{ 483 developers PT10H 484 testers PT20H 485 }}} 486 487 || 488 489 {{{#!graphviz 490 //format=svg 491 //transform=notugly 492 digraph quota_users { 493 node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Quota users"]; 494 edge [tooltip="Quota users"]; 495 496 subgraph { 497 rank=same; 498 user1 [label="User is vincent.vole@example.com"]; 499 user2 [label="User is oliver.otter@example.com"]; 500 } 501 502 havegroup [label="Have group for quota?",shape=ellipse,style=filled,fillcolor=gold]; 503 haveuser [label="Have group for user in quota?",shape=ellipse,style=filled,fillcolor=gold]; 504 505 group1 [label="User is vincent.vole@example.com\nGroup is developers"]; 506 group2 [label="User is oliver.otter@example.com"]; 507 508 checkuser1 [label="Have limit for group?",shape=ellipse,style=filled,fillcolor=gold]; 509 checkgeneral1 [label="Have general limit?",shape=ellipse,style=filled,fillcolor=gold]; 510 511 checkuser2 [label="Have limit for user?",shape=ellipse,style=filled,fillcolor=gold]; 512 checkgeneral2 [label="Have general limit?",shape=ellipse,style=filled,fillcolor=gold]; 513 514 accept [label="Quota",shape=folder,style=filled,fillcolor=cyan]; 515 decline [label="No quota",shape=folder,style=filled,fillcolor=cyan]; 516 517 user1 -> havegroup -> haveuser -> group1 -> checkuser1 -> checkgeneral1 -> accept; 518 user2 -> havegroup -> haveuser -> group2 -> checkuser2 -> checkgeneral2 -> decline [style=dashed]; 519 } 520 }}} 521 }}}} 522 523 Where individuals are not assigned to groups, any individual limit will apply 524 to them; otherwise, the general quota applies. Where individuals are assigned 525 to groups, any group limit will apply; otherwise, the general quota applies. 526 527 ==== Individual Resource Quotas ==== 528 529 The trivial case of applying quotas is to give a resource its own quota. This 530 is achieved by not specifying any arguments to the `check_quota` scheduling 531 function or to the `add_to_quota` and `remove_from_quota` functions. 532 533 {{{{#!table 534 '''Scheduling Functions''' || '''Decision Process''' 535 == 536 <style="vertical-align: top;"> 537 538 {{{ 539 check_quota 540 }}} 541 542 || 543 544 {{{#!graphviz 545 //format=svg 546 //transform=notugly 547 digraph scheduling_decisions { 548 node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Scheduling decisions"]; 549 edge [tooltip="Scheduling decisions"]; 550 551 subgraph { 552 rank=same; 553 mail [label="Incoming mail\nfrom vincent.vole@example.com",shape=folder,style=filled,fillcolor=cyan]; 554 cancel [label="Incoming cancellation",shape=folder,style=filled,fillcolor=cyan]; 555 } 556 557 subgraph { 558 rank=same; 559 check_quota [label="Is allowed by quota?",shape=ellipse,style=filled,fillcolor=gold]; 560 quota [label="Quota for resource",shape=folder]; 561 quota_for_vole [label="...applying to\nvincent.vole@example.com",shape=folder]; 562 } 563 564 schedule [label="Schedule event for resource",shape=ellipse,style=filled,fillcolor=gold]; 565 566 subgraph { 567 rank=same; 568 accept [label="Accept",shape=folder,style=filled,fillcolor=cyan]; 569 decline [label="Decline",shape=folder,style=filled,fillcolor=cyan]; 570 } 571 572 add_to_quota [label="Add to quota",shape=ellipse,style=filled,fillcolor=darkorange]; 573 remove_from_quota [label="Remove from quota",shape=ellipse,style=filled,fillcolor=darkorange]; 574 575 mail -> check_quota -> schedule -> accept; 576 check_quota -> decline [style=dashed]; 577 schedule -> add_to_quota -> quota; 578 quota -> quota_for_vole -> check_quota; 579 580 cancel -> remove_from_quota -> quota; 581 } 582 }}} 583 584 }}}} 585 586 ==== Common Resource Quotas ==== 587 588 By indicating an argument to the different functions, a common quota can be 589 employed. In the following example, both resources would employ the given 590 function invocations to pool their knowledge about their schedules. 591 592 {{{{#!table 593 '''Scheduling Functions''' || '''Decision Process''' 594 == 595 <style="vertical-align: top;"> 596 597 {{{ 598 check_quota cars 599 }}} 600 601 || 602 603 {{{#!graphviz 604 //format=svg 605 //transform=notugly 606 digraph scheduling_decisions { 607 node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Scheduling decisions"]; 608 edge [tooltip="Scheduling decisions"]; 609 610 subgraph { 611 rank=same; 612 mail_cadillac [label="Incoming mail\nfrom vincent.vole@example.com\nto resource-car-cadillac@example.com",shape=folder,style=filled,fillcolor=cyan]; 613 mail_pontiac [label="Incoming mail\nfrom vincent.vole@example.com\nto resource-car-pontiac@example.com",shape=folder,style=filled,fillcolor=cyan]; 614 cancel [label="Incoming cancellation",shape=folder,style=filled,fillcolor=cyan]; 615 } 616 617 subgraph { 618 rank=same; 619 check_quota [label="Is allowed by quota?",shape=ellipse,style=filled,fillcolor=gold]; 620 quota_cars [label="Quota for cars",shape=folder]; 621 quota_cars_vole [label="...applying to\nvincent.vole@example.com",shape=folder]; 622 } 623 624 schedule [label="Schedule event for resource",shape=ellipse,style=filled,fillcolor=gold]; 625 626 subgraph { 627 rank=same; 628 accept [label="Accept",shape=folder,style=filled,fillcolor=cyan]; 629 decline [label="Decline",shape=folder,style=filled,fillcolor=cyan]; 630 } 631 632 add_to_quota [label="Add to quota",shape=ellipse,style=filled,fillcolor=darkorange]; 633 remove_from_quota [label="Remove from quota",shape=ellipse,style=filled,fillcolor=darkorange]; 634 635 mail_cadillac -> check_quota; 636 mail_pontiac -> check_quota -> schedule -> accept; 637 check_quota -> decline [style=dashed]; 638 schedule -> add_to_quota -> quota_cars; 639 quota_cars -> quota_cars_vole -> check_quota; 640 641 cancel -> remove_from_quota -> quota_cars; 642 } 643 }}} 644 645 }}}} 646 647 ==== Collective Scheduling ==== 648 649 Consider two separate resources: both may be reserved at the same time by the 650 same organiser; neither resource would normally decline the reservation on the 651 basis of schedule availability, should the period concerned be free. However, 652 it may be undesirable for one organiser to occupy both resources at the same 653 time. 654 655 Consequently, a mechanism is required to pool the resource schedules in such a 656 way that any reservation performed for one resource at a given point in time 657 prohibits another reservation performed for a related resource at the same 658 point in time by the same user. 659 660 The free/busy records held for a given quota group permit such collective 661 scheduling decisions and are employed as follows: 662 663 {{{{#!table 664 '''Scheduling Functions''' || '''Decision Process''' 665 == 666 <style="vertical-align: top;"> 667 668 {{{ 669 schedule_across_quota cars 670 }}} 671 672 || 673 674 {{{#!graphviz 675 //format=svg 676 //transform=notugly 677 digraph scheduling_decisions { 678 node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Scheduling decisions"]; 679 edge [tooltip="Scheduling decisions"]; 680 681 subgraph { 682 rank=same; 683 mail_cadillac [label="Incoming mail\nfrom vincent.vole@example.com\nto resource-car-cadillac@example.com",shape=folder,style=filled,fillcolor=cyan]; 684 mail_pontiac [label="Incoming mail\nfrom vincent.vole@example.com\nto resource-car-pontiac@example.com",shape=folder,style=filled,fillcolor=cyan]; 685 cancel [label="Incoming cancellation",shape=folder,style=filled,fillcolor=cyan]; 686 } 687 688 subgraph { 689 rank=same; 690 schedule_across_quota [label="Can be scheduled within the quota?",shape=ellipse,style=filled,fillcolor=gold]; 691 quota_cars [label="Quota for cars",shape=folder]; 692 freebusy_cars_vole [label="...recording schedule for\nvincent.vole@example.com",shape=folder]; 693 } 694 695 schedule [label="Schedule event for resource",shape=ellipse,style=filled,fillcolor=gold]; 696 697 subgraph { 698 rank=same; 699 accept [label="Accept",shape=folder,style=filled,fillcolor=cyan]; 700 decline [label="Decline",shape=folder,style=filled,fillcolor=cyan]; 701 } 702 703 add_to_quota_freebusy [label="Add to quota free/busy",shape=ellipse,style=filled,fillcolor=darkorange]; 704 remove_from_quota_freebusy [label="Remove from quota free/busy",shape=ellipse,style=filled,fillcolor=darkorange]; 705 706 mail_cadillac -> schedule_across_quota; 707 mail_pontiac -> schedule_across_quota -> schedule -> accept; 708 schedule_across_quota -> decline [style=dashed]; 709 schedule -> add_to_quota_freebusy -> quota_cars -> freebusy_cars_vole; 710 freebusy_cars_vole -> schedule_across_quota; 711 712 cancel -> remove_from_quota_freebusy -> freebusy_cars_vole; 713 } 714 }}} 715 716 }}}} 717 718 ==== Delegating Attendance ==== 719 720 A number of resources may be regarded as interchangeable and can therefore 721 stand in for each other when they are unavailable. The iCalendar specification 722 supports the notion of delegation: the recipient of an event invitation may 723 delegate their attendance to other calendar user, informing that user and the 724 event organiser of this decision. 725 726 To define such delegation relationships, a quota is first selected as the 727 repository of common scheduling information for a group of resources. Then, 728 the members of the group are defined as delegates. This can be done using a 729 tool provided for this purpose. For example: 730 731 {{{ 732 cat <<EOF | tools/set_delegates.py 'cars' 733 mailto:resource-car-cadillac@example.com 734 mailto:resource-car-pontiac@example.com 735 EOF 736 }}} 737 738 Here, two resources are defined that will delegate to each other if they 739 cannot attend an event according to their own schedule. 740 741 {{{{#!table 742 '''Scheduling Functions''' || '''Decision Process''' 743 == 744 <style="vertical-align: top;"> 745 746 {{{ 747 schedule_for_delegate cars 748 }}} 749 750 || 751 752 {{{#!graphviz 753 //format=svg 754 //transform=notugly 755 digraph scheduling_decisions { 756 node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Scheduling decisions"]; 757 edge [tooltip="Scheduling decisions"]; 758 759 subgraph { 760 rank=same; 761 mail_cadillac [label="Incoming mail\nfrom vincent.vole@example.com\nto resource-car-cadillac@example.com",shape=folder,style=filled,fillcolor=cyan]; 762 mail_pontiac [label="Incoming mail\nfrom vincent.vole@example.com\nto resource-car-pontiac@example.com",shape=folder,style=filled,fillcolor=cyan]; 763 cancel [label="Incoming cancellation",shape=folder,style=filled,fillcolor=cyan]; 764 } 765 766 subgraph { 767 rank=same; 768 schedule_for_delegate [label="Can be scheduled or delegated?",shape=ellipse,style=filled,fillcolor=gold]; 769 quota_cars [label="Quota for cars",shape=folder]; 770 freebusy_cars_vole [label="...recording schedule for\nvincent.vole@example.com",shape=folder]; 771 } 772 773 schedule [label="Schedule event for resource",shape=ellipse,style=filled,fillcolor=gold]; 774 775 subgraph { 776 rank=same; 777 accept [label="Accept",shape=folder,style=filled,fillcolor=cyan]; 778 delegate [label="Delegate",shape=folder,style=filled,fillcolor=cyan]; 779 decline [label="Decline",shape=folder,style=filled,fillcolor=cyan]; 780 } 781 782 add_to_quota [label="Add to quota",shape=ellipse,style=filled,fillcolor=darkorange]; 783 remove_from_quota [label="Remove from quota",shape=ellipse,style=filled,fillcolor=darkorange]; 784 785 mail_cadillac -> schedule_for_delegate; 786 mail_pontiac -> schedule_for_delegate -> schedule -> accept; 787 schedule_for_delegate -> delegate [style=dashed]; 788 schedule_for_delegate -> decline [style=dashed]; 789 schedule -> add_to_quota -> quota_cars -> freebusy_cars_vole; 790 freebusy_cars_vole -> schedule_for_delegate; 791 792 cancel -> remove_from_quota -> freebusy_cars_vole; 793 } 794 }}} 795 796 }}}} 797 798 Note that it is generally more useful to have delegation decisions made on the 799 basis of many resources, which is what the journal entries for each quota 800 provides, but also for many organisers attempting to reserve those resources. 801 Although the journal for each quota may be divided up to administer quotas for 802 multiple groups of organisers, for the purposes of delegation - deciding 803 whether a resource is generally available, and deciding which other resource 804 would be available instead - a single group of all organisers is more desirable.