imip-agent

docs/wiki/Resources

1226:9beac0f55ce5
2017-04-11 Paul Boddie Handle absent release archives: do not generate erroneous attachment details.
     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 }}}}